美文网首页
09.JdbcTemplate的基本使用

09.JdbcTemplate的基本使用

作者: 吃伏冒有礼貌 | 来源:发表于2020-02-08 23:59 被阅读0次

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的依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         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.itheima</groupId>
    <artifactId>spring04_eesy_01jdbctemplate</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.15</version>
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

接下来创建实体类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

 <!--配置JdbcTemplate-->
    <bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
 <!-- 配置数据源-->
    <bean id = "dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!--连接数据库的必备信息-->
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
    <property name="username" value="root"></property>
    <property name="password" value="password"></property>
    </bean>

这里出现了一个问题:
使用原来的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

javax.net.ssl.SSLException:closing inbound before receiving peer's close_notify
不过把它引用到配置文件的时候会有一个转义符的错误 &看起来需要使用转义符解决,ALT+ENTER让IDE自动帮我解决了
其实只需要 加上useSSL=false就可以了,也能成功执行的。
&需要转义
转义后
&的转义是&amp😁

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方法呢?
    jdbcTemplate的query()方法

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

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

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


查询所需的方法.png

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


image.png

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

/**
 * 定义Account的封装策略
 */
class AccountRowMapper1 implements RowMapper<Account>{
    /**
     * 把结果集中的数据装到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了


query方法返回的T类型是由RowMapper里的T类型决定的

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

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

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

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

BeanProperyRowMapper
如果以后我们要把一个对象封装到集合里面,就不用自己写,直接拿spring提供的BeanProperyRowMapper使用就可以了。
  • 查询一个
    有了查询所有的基础,查询一个就变得更简单了,直接拿来用就完事儿了
        //查询一个
        List<Account> accounts = jtl.query("select * from account where id = ?",
                new BeanPropertyRowMapper<Account>(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<Account> 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<Account> findAccountbyId(Integer accountId) {
        List<Account> accountList = jdbcTemplate.query("select * from account where id = ?",
                new BeanPropertyRowMapper<Account>(Account.class), accountId);
        return accountList;
    }

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jdbc
        http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置accountDao-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
    <!-- 配置数据源-->
    <bean id = "dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!--连接数据库的必备信息-->
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT%2B8&amp;useSSL=false"></property>
    <property name="username" value="root"></property>
    <property name="password" value="password"></property>
    </bean>
</beans>

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

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等等


各种各样的dao

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


那么在前面这段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的代码进行改动


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时仍然能执行成功。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jdbc
        http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
    <!--配置JdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置jdbcSupport-->
    <bean id="jdbcSupport" class="com.itheima.jdbctemplate.JdbcSupport">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--配置accountDao-->
    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<!--
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
-->      <property name="dataSource" ref="dataSource"></property>

    </bean>
    <!-- 配置数据源-->
    <bean id = "dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <!--连接数据库的必备信息-->
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT%2B8&amp;useSSL=false"></property>
    <property name="username" value="root"></property>
    <property name="password" value="password"></property>
    </bean>
</beans>

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


可以看到定义和get&set方法都有,也有createJdbcTemplate方法

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


dao的第一种写法
dao第二种写法,继承了jdbcDaoSupport
那么这两种有什么区别呢

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


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

相关文章

  • 09.JdbcTemplate的基本使用

    2.JdbcTemplate的概述和入门 它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对...

  • 基本的使用

    存cookie 取cookie 存session 取session

  • Flutter--Text/Container/Image

    Text基本使用 Container基本使用 Image基本使用

  • 基本使用

    1、 打开需要上传的文件夹执行: git init 格式化窗口 2、执行 git add . 上传文件 3、执行 ...

  • 基本使用

    href="javascript:;" 其中javascript: 是一个伪协议。它可以让我们通过一个链接来调用...

  • 基本使用

    数据库: 什么是数据库?简单来说就是存数据的。 都有什么是数据库? oracle(强大,跟金融政府打交道的,安全,...

  • 基本使用

    本文参考:https://morvanzhou.github.io/tutorials/machine-learn...

  • SQL语句基本使用

    SQL语句基本使用——增删改查 SQL语句基本使用——WHERE子句 SQL语句基本使用——AND和OR的使用 S...

  • 6-xpath和css select基本使用

    Xpath基本使用 css select基本使用

  • NSInvocation的基本使用

    前提: 在 iOS中可以直接调用某个对象的消息方式有两种:一种是performSelector:withObjec...

网友评论

      本文标题:09.JdbcTemplate的基本使用

      本文链接:https://www.haomeiwen.com/subject/xhwmnctx.html