第七章 JdbcTemplate

target

理解为什么会有JdbcTemplate的出现
掌握 JdbcTemplate 的三种使用方式
掌握JdbcTemplate 常用API

1. 概述

JDBC已经能够满足大部分用户最基本的需求,但是在使用JDBC时,必须自己来管理数据库资源如:获取PreparedStatement,设置SQL语句参数,关闭连接等步骤。Spring对JDBC进行了封装,简化了JDBC的相关操作,这就是JdbcTemplate:

  • JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。

  • JdbcTemplate是Spring的一部分,处理了资源的建立和释放。

  • 他帮助我们避免一些常见的错误,比如忘了总要关闭连接。

  • 他运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供SQL语句和提取结果。

2. 使用

2.1 搭建环境

① 导入jar

 commons-dbcp-1.4.jar
 commons-logging-1.2.jar
 commons-pool-1.6.jar
 mysql-connector-java-8.0.15.jar
 spring-beans-4.3.9.RELEASE.jar
 spring-context-4.3.9.RELEASE.jar
 spring-core-4.3.9.RELEASE.jar
 spring-expression-4.3.9.RELEASE.jar
 spring-jdbc-4.3.9.RELEASE.jar
 spring-tx-4.3.9.RELEASE.jar

② 数据库相关

准备好数据库及模拟的数据:

  • 创建数据库
create database test;
  • 使用数据库
use test;
  • 创建表
create table user(
 id int primary key auto_increment,
 username varchar(30),
 password varchar(30)
)
  • 插入数据
insert into user(username,password) values('jerry','jerry1234');
insert into user(username,password) values('grace','grace1234');

③ 实体类

新建实例类,对数据库里的字段进行封装:

package com.lee.spring.bean;

public class User {
    private int id;
    private String name;
    private String password;
}

2.2 三种使用方式

jdbcTemplate提供了三种实现方式,根据自己的需求去选择合适的方式使用:

① 纯手写方式使用JdbcTemplate(不推荐)

直接在测试方法中进行测试即可:

@Test
public void test01() {
  //1.创建数据源
  BasicDataSource dataSource = new BasicDataSource();
  dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
  dataSource.setUrl("jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=utf-8");
  dataSource.setUsername("root");
  dataSource.setPassword("root");

  //2.创建模板
  JdbcTemplate jdbcTemplate = new JdbcTemplate();
  jdbcTemplate.setDataSource(dataSource);

  //3.使用API
  String sql = "insert into user(username,password) values(?,?)";
  jdbcTemplate.update(sql , "rose" , "rose1234");
}

查看数据库,发现成功插入数据:

这种方式是不推荐的,因为数据源的操作全部是手工编码的,尤其是数据库连接相关操作一定是放在配置文件中才是最佳的。

② 使用IoC注入方式

Dbcp数据源

  • jar包:

    commons-dbcp-1.4.jar

    commons-pool-1.6.jar

  • Dao层:

    public class UserDao {

    private JdbcTemplate jdbcTemplate;

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void updateUser( User user) {
        String sql = "update user set username = ? ,password=? where id = ?";
        Object[] orgs = {user.getName(),user.getPassword(),user.getId()};
        jdbcTemplate.update(sql , orgs);
    }
}

需要注意:在 Dao中需要提供jdbcTemplate和他的setter方法。

  • 配置文件:
<!-- 配置jdbc模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  <property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 将userDao纳入到IOC容器 -->
<bean id="userDao" class="com.lee.spring.dao.UserDao">
  <property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>

<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
  <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false"></property>
  <property name="username" value="root"></property>
  <property name="password" value="root"></property>
</bean>
  • 测试:
 @Test
public void test02() {
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserDao userDao =(UserDao) context.getBean("userDao");
  User user = new User();
  user.setId(1);
  user.setName("杰瑞");
  user.setPassword("admin");
  userDao.updateUser(user );
}

除了使用Dbcp数据源,还可以使用c3p0数据源实现:

  • jar包

    c3p0-0.9.5.2.jar

    mchange-commons-java-0.2.20.jar

  • 配置文件

<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
  <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
  <property name="user" value="root"></property>
  <property name="password" value="root"></property>
</bean>

<!-- 配置jdbc模板 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  <property name="dataSource" ref="dataSource"></property>
</bean>

③ 继承JdbcDaoSupport方式

上面的方法,我们每一个dao类都需要一个JdbcTemplate属性。Spring已经为JdbcTemplate做了封装,直接继承JdbcDaoSupport就可以调用已经封装好的JdbcTemplate。

第一步:dao类继承JdbcDaoSupport

public class UserDao extends JdbcDaoSupport {

    public List<Map<String, Object>> findAll(){
        String sql = "select * from user";
        List<Map<String, Object>> list = this.getJdbcTemplate().queryForList(sql);
        return list;
    }
}

第二步:配置文件删掉JdbcTemplate的注入,直接把数据源注入给dao

<!-- 将userDao纳入到IOC容器 -->
<bean id="userDao" class="com.lee.dao.UserDao">
  <property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  <property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
  <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
  <property name="user" value="root"></property>
  <property name="password" value="root"></property>
</bean>

测试:

@Test
public void test03() {
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserDao userDao =(UserDao) context.getBean("userDao");
  List<Map<String,Object>> all = userDao.findAll();
  System.out.println(all);
}

2.3 properties使用

一般情况下,我们会把数据库相关信息在一个单独的文件中配置,可以使用properties。

在src下新建db.properties:

jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/test
jdbc.user=root
jdbc.password=root

编写Spring配置文件applicationContext.xml:

直接使用 $ 获取db.properties中的值

<!-- 将数据库配置文件导入 -->
<context:property-placeholder location="classpath:db.properties"/>

<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  <property name="driverClass" value="${jdbc.driverClass}"></property>
  <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
  <property name="user" value="${jdbc.user}"></property>
  <property name="password" value="${jdbc.password}"></property>
</bean>

注意:

如果数据库连接失败,可以在相应的属性前加 jdbc.

3. API

JdbcTemplate常用的API如下:

3.1 配置类表映射

有时候数据表的字段和实体类的属性不是一一对应的,需要手动进行匹配。怎么匹配?通过实现RowMapper接口。

🌰

UserMapper的作用就是对user数据表的字段和User类的属性匹配:

package com.lee.spring.dao;

public class UserMapper implements RowMapper<User> {

    @Override
      public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        User user = new User();
        user.setId(rs.getInt("id"));
        user.setName(rs.getString("username"));
        user.setPassword(rs.getString("password"));
        return user;
      }
}

在Dao里进行查询:

查询单个用户使用queryForObject()方法,查询多个用户使用query()方法

package com.lee.spring.dao;

public class UserDao extends JdbcDaoSupport {
    
    //  查询单个用户
    public User getUserById(int id) {
        String sql = "select * from user where id = " + id;
        User user = this.getJdbcTemplate().queryForObject(sql, new UserMapper());
        return user;
    }
    
    //  查询多个用户
    public List<User> getAllUsers() {
        String sql = "select * from user";
        List<User> allUsers = this.getJdbcTemplate().query(sql, new UserMapper());
        return allUsers;
    }
}

编写测试类进行测试:

@Test
public void test04() {
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserDao userDao =(UserDao) context.getBean("userDao");
  User user = userDao.getUserById(1);
  System.out.println(user);
}

@Test
public void test05() {
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserDao userDao =(UserDao) context.getBean("userDao");
  List<User> allUsers = userDao.getAllUsers();
  System.out.println(allUsers);
}

3.2 query相关方法

方法 描述 参数 返回值
queryForObject(String sql, RowMapper rowMapper) 查询单个对象,以对象方式返回 第一个参数:执行的查询语句 第二个参数:一个映射类对象(比如UserMapper) T
queryForMap(String sql) 查询单个对象,以map方式返回 执行的查询语句 Map<String, Object>
query(String sql, RowMapper rowMapper) 查询多个对象,返回值为List<T> 第一个参数:执行的查询语句 第二个参数:一个映射类对象(比如UserMapper) List<T>
queryForList(String sql) 查询你多个对象,返回值为List<Map<String,Object>> 执行的查询语句 List<Map<String,Object>>

🌰

package com.lee.spring.dao;

public class UserDao extends JdbcDaoSupport {

    // queryForObject:查询单个对象,以对象方式返回
        public User queryForObject(int id) {
            String sql = "select * from user where id = " + id;
            User user = this.getJdbcTemplate().queryForObject(sql, new UserMapper());
            return user;
        }
        
        // queryForMap:查询单个对象,以map方式返回
        public Map<String, Object> queryForMap(int id) {
            String sql = "select * from user where id = " + id;
            Map<String, Object> map = this.getJdbcTemplate().queryForMap(sql);
            return map;
        }
        
    // query(String sql, RowMapper rowMapper):查询多个对象,返回值为List<T>
        public List<User> queryAll() {
            String sql = "select * from user";
            List<User> allUsers = this.getJdbcTemplate().query(sql, new UserMapper());
            return allUsers;
        }
    
    // queryForList(String sql):查询多个对象,以List<Map<String, Object>>返回
    public List<Map<String, Object>> queryForList(){
        String sql = "select * from user";
        List<Map<String, Object>> list = this.getJdbcTemplate().queryForList(sql);
        return list;
    }
}

编写测试类测试:

@Test
public void test06() {
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserDao userDao =(UserDao) context.getBean("userDao");
  Map<String, Object> map = userDao.queryForMap(1);
  System.out.println(map);
  System.out.println("-------------------------");
  
  User user = userDao.queryForObject(1);
  System.out.println(user);
  System.out.println("-------------------------");
  
  List<User> all = userDao.queryAll();
  System.out.println(all);
  System.out.println("-------------------------");
  
  List<Map<String, Object>> list = userDao.queryForList();
  System.out.println(list);
}

3.3 update

方法:update(String sql, Object... args)

其中,args为更新的参数

作用:更新、修改、删除操作,返回受影响的行数 .

🌰

package com.lee.spring.dao;

public class UserDao extends JdbcDaoSupport {

    public int updateUser( User user) {
        String sql = "update user set username = ? ,password=? where id = ?";
        Object[] orgs = {user.getName(),user.getPassword(),user.getId()};
        int i = this.getJdbcTemplate().update(sql , orgs);
        return i;
    }
}

测试:

@Test
public void test07() {
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserDao userDao =(UserDao) context.getBean("userDao");
  User user = new User();
  user.setId(1);
  user.setName("杰瑞");
  user.setPassword("admin");
  userDao.updateUser(user );
}

3.4 batchUpdate

方法:batchUpdate(SQL语句1,SQL语句2....);

作用:执行批量操作,可以是批量更新、批量插入、批量删除,参数为string数组

返回值:整形数组。数组中数字表示相应的SQL语句影响的行数。

🌰

package com.lee.spring.dao;

public class UserDao extends JdbcDaoSupport {

    public int[] batch() {
        String sql1 = "delete from  user";
        String sql2 = "insert into user values(1,'aa','aa123'),(2,'bb','bb123')";
        String sql3 = "update user set password = 'admin' where id =1";
        int[] nums = this.getJdbcTemplate().batchUpdate(sql1,sql2,sql3);
        return nums;
    }   
}

测试:

@Test
public void test08() {
  ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserDao userDao =(UserDao) context.getBean("userDao");
  int[] batch = userDao.batch();
  for (int i : batch) {
    System.out.println(i);
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341

推荐阅读更多精彩内容