09.JdbcTemplate的基本使用

2.JdbcTemplate的概述和入门

它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。spring 框架为我们提供了很多 的操作模板类。
操作关系型数据的: JdbcTemplate HibernateTemplate
操作 nosql 数据库的: RedisTemplate
操作消息队列的: JmsTemplate
我们今天的主角在 spring-jdbc-5.0.2.RELEASE.jar中,我们在导包的时候,除了要导入这个 jar 包 外,还需要导入一个spring-tx-5.0.2.RELEASE.jar(它是和事务相关的)
`
JdbcTemplate有什么作用:
它就是用于和数据库交互的,实现对表的CRUD的操作。

我们在学一个新的东西的时候,通常在想它有什么作用,如何创建,又有什么方法,接下来我们在程序中操作一下去明白,新建一个maven工程,配置pom.xml:首先需要spring-context依赖,还有就是刚刚说说的spring-jdbc和spring-tx的依赖,还需要一个mysql的依赖。



    4.0.0

    com.itheima
    spring04_eesy_01jdbctemplate
    1.0-SNAPSHOT
    
        
            org.springframework
            spring-context
            5.1.2.RELEASE
        
    
        mysql
        mysql-connector-java
        8.0.15
    
        
        
            org.springframework
            spring-jdbc
            5.2.0.RELEASE
        
        
        
            org.springframework
            spring-tx
            5.2.1.RELEASE
        
    
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.1
                
                    1.8
                    1.8
                
            
        
    

接下来创建实体类Account,为成员变量生成get/set方法还有toString方法。

package com.itheima.domain;

public class Account {
    private Integer id;
    private String name;
    private Float money;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getMoney() {
        return money;
    }

    public void setMoney(Float money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

现在我们创建Jdbctemplate类
我们仍然使用我们之前为学习spring所创建的数据库eesy,我们需要创建jdbcTemplate对象,这里的方式是直接new一个出来使用,另外我们还需要配置数据源,spring内置的数据源是 DriverManagerDataSource,通过它设置Driver,url,user,password。
当我们创建好jdbcTemplate对象时,就可以使用它的excute方法来执行sql语句了,数据源可以通过jdbcTemplate的构造方法直接在new的时候就添加上,也可以用jdbcTemplate的setDataSource方法。

package com.itheima.jdbctemplate;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

public class Jdbctemplate {
    public static void main(String[] args) {
        //准备数据源,spring的内置数据源
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT%2B8&useSSL=false");
        ds.setUsername("root");
        ds.setPassword("password");
        //创建JdbcTemplate对象
        JdbcTemplate jtl = new JdbcTemplate(ds);
        //jtl.setDataSource(ds);
        //执行语句
        jtl.execute("insert into account(name, money) value ('ccc',1000)");

    }
}

这个就是JdbcTemplate的最基本的使用

现在来看,JdbcTemplate的最基本使用是有很多问题的,耦合性太强,数据源部分写死知类的问题。

3.JdbcTemplate在spring的ioc中使用

我们如果要解决以上问题,那很简单,用spring来管理他们。
通过IOC容器来创建JdbcTemplate

 
    
        
    
 
    
    
    
    
    
    
    

这里出现了一个问题:
使用原来的url时,会报出:javax.net.ssl.SSLException:closing inbound before receiving peer's close_notify的错误,这个问题的解决办法是 配置连接数据库的url时 ,加上useSSL=false。如以下格式,注意将数据库名(db_testjpa)改为你自己的数据库名。参考来源
之前就抛出这个异常,按照网上的搜寻结果我在url后i添加了jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT%2B8&useSSL=false

09.JdbcTemplate的基本使用_第1张图片
javax.net.ssl.SSLException:closing inbound before receiving peer's close_notify

不过把它引用到配置文件的时候会有一个转义符的错误 &看起来需要使用转义符解决,ALT+ENTER让IDE自动帮我解决了
其实只需要 加上useSSL=false就可以了,也能成功执行的。
09.JdbcTemplate的基本使用_第2张图片
&需要转义

转义后

&的转义是 &

4.JdbcTemplate的CRUD操作

接下来我们需要讲讲JdbcTemplate的CRUD的操作
这些都是单表的操作,多表查询不是JdbcTemplate的事,而是SQL语句的事

  • 保存
 //保存
 jtl.update("insert  into  account (name, money) VALUES (?,?)","ppp",1000f);
  • 更新
    有了保存为基础,更新如法炮制
 //更新
 jtl.update("update account SET name=?,money=? WHERE id = ?","ggg",1000f,18);
  • 删除
    有了保存为基础,更新如法炮制
//删除
jtl.update("delete  from account where id= ? ", 18);
  • 查询所有
    接下来是查询所有,需要用到的方法是jdbcTemplate的query()方法,query方法有很多,如何选择我们需要的query方法呢?
    09.JdbcTemplate的基本使用_第3张图片
    jdbcTemplate的query()方法

如何快速定位自己想要的方法?要明确两点:

  • 我们有什么? SQL语句 语句的参数
  • 我们要什么? 返回一个List结果集

基于这两点,所以方法里 有void 和T就不用考虑了,只考虑LIST
最后筛选出来,就只剩这两个方法,这两个方法的不同是针对于不同的JDK版本, 第一个是所有版本都可以用,第二个版本是JDK1.5以上可使用


09.JdbcTemplate的基本使用_第4张图片
查询所需的方法.png

我们已有第一个参数SQL语句,第三个参数变量,这第二个参数RowMapper是一个T类型的接口


09.JdbcTemplate的基本使用_第5张图片
image.png

我们无法拿来直接使用,但是我们可以写一个类来implements这个接口

/**
 * 定义Account的封装策略
 */
class AccountRowMapper1 implements RowMapper{
    /**
     * 把结果集中的数据装到Account中,然后由spring把Account加到集合中
     * @param resultSet
     * @param i
     * @return
     * @throws SQLException
     */
    @Override
    public Account mapRow(ResultSet resultSet, int i) throws SQLException {
        return null;
    }
}

RowMappler的T类型就写Account类型就好了,需要重载mapRow方法,这个方法是用来定义Account的封装策略的,其实就是把结果集的数据封装到Account中,然后由spring把Account加载到集合中。
(这是因为query.()方法返回的是一个List,而mapRow返回的是Account,我们只需要返回Account就行了,spring会帮我加到集合里)

public Account mapRow(ResultSet resultSet, int i) throws SQLException {
        Account account = new Account();
        account.setId(resultSet.getInt("id"));
        account.setName(resultSet.getString("name"));
        account.setMoney(resultSet.getFloat("money"));
        return  account;
    }

当我们把AccountRowMapper写完,第二个参数就可以填上 new AccountRowMapper了


09.JdbcTemplate的基本使用_第6张图片
query方法返回的T类型是由RowMapper里的T类型决定的

所以我们可以定义 List account 来接受query方法返回的结果,并遍历打印出来看结果

List accounts = jtl.query("select * from account where money > ?",new AccountRowMapper(), 800f);
        for (Account account:accounts){
            System.out.println(account);
        }

dbutils中的QueryRunner的query方法第一个参数也是SQL语句,第二个参数是ResultSetHandler,第三个参数是参数变量,这第二个参数ResultSetHandler作用其实跟RowMapper的作用是一样的,都是把结果集封装进类中。这是因为Dbutils提供了这样的方法。

我们Spring也提供了这样的方法,spring提供的这个方法叫BeanProperyRowMapper,这个方法里面的参数要加上类的字节码,可以看到运行结果是一样的

09.JdbcTemplate的基本使用_第7张图片
BeanProperyRowMapper

如果以后我们要把一个对象封装到集合里面,就不用自己写,直接拿spring提供的BeanProperyRowMapper使用就可以了。

  • 查询一个
    有了查询所有的基础,查询一个就变得更简单了,直接拿来用就完事儿了
        //查询一个
        List accounts = jtl.query("select * from account where id = ?",
                new BeanPropertyRowMapper(Account.class), 1);
        System.out.println(accounts);
  • 查询返回一行一列(使用聚合函数,但不包括group by语句)
    查询返回一行一列只能用queryForObject方法,也是三个参数,第一个SQL语句,第二个参数是字节码,因为我们要返回的interger类型,所以写interger.class就可以了,写第三个是我们的条件。
        //查询返回一行一列(使用聚合函数,但是不加group by语句)
        Integer integer = jtl.queryForObject("select count(*) from account where money = ?", Integer.class, 1000);
        System.out.println(integer);
5.JdbcTemplate在Dao中的使用

CRUD就讲完了 实际上在开发中是基于Dao的,那我们还是写的稍微规范点。

创建IAccountDao接口和AccountDaoImpl,我就写了一个方法来实现。

package com.itheima.dao;

import com.itheima.domain.Account;

import java.util.List;

/**
 * 账户持久层接口
 */
public interface IAccountDao {

    /**
     * 通过id查询账户
     * @return
     */
    List findAccountbyId(Integer accountId);
}
public class AccountDaoImpl implements IAccountDao {

    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

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

    public List findAccountbyId(Integer accountId) {
        List accountList = jdbcTemplate.query("select * from account where id = ?",
                new BeanPropertyRowMapper(Account.class), accountId);
        return accountList;
    }

我们是要交给Spring来控制的,接下来来配置bean.xml



    
    
        
    
    
    
        
    
    
    
    
    
    
    
    
    

测试------------->

package com.itheima;

import com.itheima.dao.IAccountDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test {
    @Test
     public void testDao(){
        ApplicationContext ac  = new ClassPathXmlApplicationContext("bean.xml");
        IAccountDao dao = (IAccountDao) ac.getBean("accountDao");
        System.out.println(dao.findAccountbyId(1));
    }
}
6.JdbcDaoSupport的使用以及Dao的两种编写方式

如果我们存在很多Dao,比如productDao和OtherDao等等


09.JdbcTemplate的基本使用_第8张图片
各种各样的dao

那么在前面这段jdbcTemplate将会在Dao里重复出现


09.JdbcTemplate的基本使用_第9张图片
那么在前面这段jdbcTemplate将会在Dao里重复出现

如何减少这种重复代码?

我们可以把JdbcTemplate抽取出来,创建JdbcSupport类,为jdbcTemplate生成set&get方法,然后让AccountDaoImpl继承jdbcSupport,用父类的getJdbcTemplate()来得到JdbcTemplate,减少代码重复。

package com.itheima.jdbctemplate;

import org.springframework.jdbc.core.JdbcTemplate;

public class JdbcSupport {
    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

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

接下来在daoImpl的代码进行改动


09.JdbcTemplate的基本使用_第10张图片
AccountDaoImpl

既然JdbcSupport能够抽取jdbcTemplate,那么能不能抽取dataSource呢,我们为dataSource创建了get&set方法,并且判断,如果jdbcTemplate为空的时候,创建一个jdbcTemplate,createJdbcTemplate方法传入dataSource 通过构造方法就能new 一个JdbcTemplate返回。

package com.itheima.jdbctemplate;

import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

public class JdbcSupport {
    private JdbcTemplate jdbcTemplate;
    private DataSource dataSource;

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

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

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        if(jdbcTemplate == null){
            jdbcTemplate = createJdbcTemplate(dataSource);
        }
    }

    private JdbcTemplate createJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

此时开始配置bean.xml,把jdbcSupport扔入IOC容器,并且注入jdbcTemplate和dataSourece,并且在accountDao的注入屏蔽掉jdbcTemplate又注入dataSource时仍然能执行成功。



    
    
        
    
    
    
        
        
    
    
    
      

    
    
    
    
    
    
    
    
    

其实我们写的这个,Spring是为我们提供的,这个类叫JdbcDaoSupport,一样的可以去除定义和set&get的重复代码,当我们有多个dao的时候,就没有必要定义和生成get&ser方法。


09.JdbcTemplate的基本使用_第11张图片
可以看到定义和get&set方法都有,也有createJdbcTemplate方法

所以我们dao就有两种写法,一种不继承JdbcTemplate 一种是继承了JdbcTemplate


09.JdbcTemplate的基本使用_第12张图片
dao的第一种写法

09.JdbcTemplate的基本使用_第13张图片
dao第二种写法,继承了jdbcDaoSupport

那么这两种有什么区别呢

可以看到JdbcDaoSupport的源码是不可以打上注解的,所以当我们的dao使用注解的时候,继承jdbcDaoSupport的使用将变得麻烦。


09.JdbcTemplate的基本使用_第14张图片
JdbcDaoSupport @Nullable

使用注解开发建议采用不继承JdbcDaoSupport的写法,使用xml的配置就可以使用继承JdbcDaoSupport的写法。

你可能感兴趣的:(09.JdbcTemplate的基本使用)