目录

一、JdbcTemplate

1. 环境准备

2. 新增、修改、删除

3. 查询

4. 批量添加、修改、删除

5. 使用回调函数(了解)

6. 使用德鲁伊连接池


一、JdbcTemplate

JdbcTemplate是Spring提供的一个JDBC模板类,是对JDBC的封装,简化JDBC代码。

当然,你也可以不用!可以让Spring集成其它的ORM框架,例如:MyBatis、Hibernate等。

接下来我们简单来学习一下,使用JdbcTemplate完成增删改查。

1. 环境准备

数据库表准备t_user

插入数据

新建模块:spring6-008-jdbc

pom.xml中引入相关依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bjpowernode</groupId>
    <artifactId>spring6-008-jdbc</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <repositories>
        <repository>
            <id>repository.spring.milestone</id>
            <name>Spring Milestone Repository</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <!--新增的依赖:mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <!--新增的依赖:spring jdbc,这个依赖中有JdbcTemplate-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
    </dependencies>
    
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

</project>

准备实体类:表t_user对应的实体类User

package com.powernode.spring6.bean;

public class User {

    private Integer id;
    private String realName;
    private Integer age;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", realName='" + realName + '\'' +
                ", age=" + age +
                '}';
    }

    public User() {
    }

    public User(Integer id, String realName, Integer age) {
        this.id = id;
        this.realName = realName;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }


}

编写数据源DataSource

我们使用JdbcTemplate对象,完成增删改查,所以我们先分析一下源码:

①可以看到JdbcTemplate类中有一个DataSource属性,这个属性是数据源,我们都知道连接数据库需要Connection对象,而生成Connection对象是数据源负责的,所以我们需要给JdbcTemplate设置数据源属性。

②所有的数据源都是要实现javax.sql.DataSource接口的。这个数据源可以自己写一个,也可以用写好的,比如:阿里巴巴的德鲁伊连接池druid,c3p0,dbcp等。我们这里自己先手写一个数据源,命名为MyDataSource。

准备数据源

package com.powernode.spring6.jdbc;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

public class MyDataSource implements DataSource {
    // 提供连接数据库的属性
    private String driver;
    private String url;
    private String username;
    private String password;
    // 提供setter方法
    public void setDriver(String driver) {
        this.driver = driver;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    // 重点写怎么获取Connection对象就行,其他方法不用管。
    @Override
    public Connection getConnection() throws SQLException {
        // 获取Connection对象
        try {
            // 注册驱动
            Class.forName(driver);
            // 获取连接
            Connection connection = DriverManager.getConnection(url, username, password);
            // 返回connection对象
            return connection;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

spring.xml配置

写完数据源MyDataSource,我们需要把这个数据源传递给JdbcTemplate;因为JdbcTemplate类中需要一个DataSource属性

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置数据源-->
    <bean id="myDataSource" class="com.powernode.spring6.jdbc.MyDataSource">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring"/>
        <property name="username" value="root"/>
        <property name="password" value="123"/>
    </bean>
    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--没有数据源的信息,就无法创建JdbcTemplate对象-->
        <property name="dataSource" ref="myDataSource"/>
    </bean>
</beans>

编写测试程序

package com.powernode.spring6.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;

public class SpringJdbcTest {
    @Test
    public void testTest(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        System.out.println(jdbcTemplate);
    }
}

执行结果:成功创建JdbcTemplate对象

2. 新增、修改、删除

注意:JdbcTemplate当中,只要是insert、update、delete语句,都是调用update()方法

update方法有两个参数:

第一个参数:要执行的SQL语句。(SQL语句中可能会有占位符 ? )

第二个参数:可变长参数(给前面的占位符传值),参数的个数可以是0个,也可以是多个;一般是SQL语句中有几个问号,则对应几个参数。

注:对于JdbcTemplate不想MyBatis那样需要手动提交!

新增

    @Test
    public void testInsert(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "insert into t_user(real_name,age) values(?,?)";
        int count = jdbcTemplate.update(sql,"王五",20);
        System.out.println(count);
    }

修改

    @Test
    public void testUpdate(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "update t_user set real_name=?,age=? where id=?";
        int count = jdbcTemplate.update(sql,"小红",10,3);
        System.out.println(count);
    }

删除

    @Test
    public void testDelete(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "delete from t_user where id = ?";
        int count = jdbcTemplate.update(sql,3);
        System.out.println(count);
    }

3. 查询

注意:select语句调用的是queryForObject方法。

queryForObject方法有三个参数:

第一个参数:sql语句

第二个参数:创建一个BeanPropertyRowMapper对象,用来指定属性值和数据库记录行的映射关系,并且调用在构造方法中指定映射的对象类型。

第三个参数:可变长参数(给前面的占位符传值),给sql语句的占位符问号传值。

查询一个对象

调用queryForObject方法,返回的是我们构造方法中指定的对象!

    @Test
    public void testSelectOne(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "select id,real_name,age from t_user where id = ?";
        User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), 1);
        System.out.println(user);
    }

查询多个对象

调用的是query方法,返回的是一个List集合,类型是我们构造方法中指定的类型

    @Test
    public void testSelectAll() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "select id,real_name,age from t_user";
        List<User> users = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
        users.forEach(user -> {
            System.out.println(user);
        });
    }

查询一个值

还是调用queryForObject方法,返回的肯定是记录的条数,所以指定一下类型是int类型

注:因为吃查询记录的个数,和数据库中的字段没有关系,所以就不需要BeanPropertyRowMapper对象去指定映射关系,直接写int.class即可!

    @Test
    public void testSelectOneValue() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "select count(*) from t_user";
        Integer total = jdbcTemplate.queryForObject(sql, int.class);
        System.out.println("总记录条数是:"+total);
    }

4. 批量添加、修改、删除

批量增加、修改、删除操作,基本上的步骤都是相同的,都是要先把要操作的数据封装到一个List集合当中;主要的区别就是:执行的SQL不同 和 准备的数据不同!

注:无论是批量增加、修改、还是删除调用的都是batchUpdate()方法!

批量增加

首先把要插入的数据封装到一个List集合当中,然后调用batchUpdate()方法,把这个List集合传进去即可!

    @Test
    public void testBatchInsert(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "insert into t_user(real_name,age) values(?,?)";
        // 准备要插入的数据
        Object[] obj1 = {"小花",12};
        Object[] obj2 = {"小明",14};
        // 创建List集合
        List<Object[]> list = new ArrayList<>();
        // 把数据添加到集合当中
        list.add(obj1);
        list.add(obj2);
        // 执行sql,调用batchUpdate方法
        int[] count = jdbcTemplate.batchUpdate(sql, list);
        System.out.println(Arrays.toString(count)); // [1, 1]

    }

批量修改 

和批量增加的步骤基本相同!

    @Test
    public void testBatchUpdate(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "update t_user set real_name = ?,age = ? where id = ?";
        // 准备要插入的数据
        Object[] obj1 = {"小红",18,5};
        Object[] obj2 = {"小虹",18,6};
        // 创建List集合
        List<Object[]> list = new ArrayList<>();
        // 把数据添加到集合当中
        list.add(obj1);
        list.add(obj2);
        // 执行sql,调用batchUpdate方法
        int[] count = jdbcTemplate.batchUpdate(sql, list);
        System.out.println(Arrays.toString(count)); // [1, 1]

    }

 

批量删除

和批量增加、修改的步骤基本相同!

    @Test
    public void testBatchDelete(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "delete from t_user where id = ?";
        // 准备要插入的数据
        Object[] obj1 = {5};
        Object[] obj2 = {7};
        // 创建List集合
        List<Object[]> list = new ArrayList<>();
        // 把数据添加到集合当中
        list.add(obj1);
        list.add(obj2);
        // 执行sql,调用batchUpdate方法
        int[] count = jdbcTemplate.batchUpdate(sql, list);
        System.out.println(Arrays.toString(count)); // [1, 1]

    }

5. 使用回调函数(了解)

回调函数的作用:如果我们需要编写JDBC代码,就可以使用回调函数;在这个回调函数里就可以编写原生的JDBC代码,步骤如下:

①先调用execute方法注册回调函数;方法中的参数:第一个参数是sql语句,第二个参数是一个PreparedStatementCallback对象,就是一个回调函数。

②使用回调函数我们要重写里面的doInPreparedStatement方法,这个方法的参数就是原生JDBC中的PreparedStatement对象

③通过PreparedStatement对象,我们就可以编写下面原生的JDBC代码了

@Test
    public void testCallback(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
        // 准备sql语句
        String sql = "select id,real_name,age from t_user where id = ?";
        // 注册回调函数
        // 调用execute方法来注册回调函数:第一个参数是sql语句,第二个参数是一个PreparedStatementCallback
        User user = jdbcTemplate.execute(sql, new PreparedStatementCallback<User>() {
            @Override
            public User doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
               User user = null;
                // 使用ps进行?赋值
                ps.setInt(1,2);
                // 返回一个set集合
                ResultSet rs = ps.executeQuery();
                if (rs.next()){
                    // 获取数据
                    int id = rs.getInt("id");
                    String realName = rs.getString("real_name");
                    int age = rs.getInt("age");
                    // 封装数据
                    user = new User(id,realName,age);
                }

                return user;
            }
        });
        System.out.println(user);
    }

6. 使用德鲁伊连接池

之前的数据源MyDateSource是用我们自己写的;当然也可以使用别人写好的,例如:比较牛的阿里巴巴旗下的德鲁伊连接池(druid)

第一步:引入德鲁伊连接池的依赖

<!--引入druid连接池的依赖-->
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid</artifactId>
   <version>1.2.13</version>
</dependency>

第二步:将德鲁伊中的数据源配置到spring配置文件中

注:使用德鲁伊连接池druid和自己写的连接池相比,就driver不同,其它的配置都是相同的,使用自己写的driver,我们定义的就是String类型;一旦使用德鲁伊连接池此时driver属性代表的就是Driver类型,要想使用String类型必须是使用属性driverClassName

    <!--配置德鲁伊连接池的依赖-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring"/>
        <property name="username" value="root"/>
        <property name="password" value="123"/>
    </bean>

    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--没有数据源的信息,就无法创建JdbcTemplate对象-->
        <property name="dataSource" ref="druidDataSource"/>
    </bean>

执行结果:

根据输出的信息就能看出使用的确实是德鲁伊连接池!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐