1.持久层总图

如图所示,在持久层中,最终完成数据库操作的是MySQL、Oracle等工具,要想让编程语言操作数据库软件,需要由数据库厂商提供各种数据库驱动,不同的驱动都可以被JDBC所调用,因为JDBC是访问数据库的标准规范,它由接口和抽象类组成。再往上走是更加高层的封装,封装的是JDBC的操作,其中就包含一个JDBCTemplate的工具,他是由Spring提供的,对JDBC进行了薄薄的封装,其实和我们使用的Commons-dbutils功能是一样的。

2.JDBCTemplate概述

JDBCTemplate的作用就是用于和数据库进行交互的,从而实现对表的CURD操作,要想使用JDBCTemplate,需要导入如下的jar包。一个是spring-jdbc、一个是数据库驱动mysql-connector-java

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
  
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
</dependency>

3.JDBCTemplate使用

3.1 创建账户实体类

com.eastnotes.domain包下创建一个账户的实体类Account

/**
 * 账户的实体类
 */
public class Account implements Serializable {
    private String name;
    private Double money;
    private Integer id;

    public String getName() {
        return name;
    }

    public Double getMoney() {
        return money;
    }

    public Integer getId() {
        return id;
    }

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

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

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

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

3.2 jdbcTemplate简单使用

com.eastnotes.jdbcTemplate包下创建一个使用JDBCTemplate的类jdbcTemplateDemo1,然后就可以使用JDBCTemplate进行数据库操作了。在创建jdbcTemplate对象之前,还需要给他准备一个数据源对象:

/**
 * 写JDBCTemplate的基本用法
 * 此种写法可以用IOC进行优化
 */
public class dbcTemplateDemo1 {
    public static void main(String[] args) {
        //1.准备数据源,这里使用spring的内置数据源
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring");
        ds.setUsername("root");
        ds.setPassword("root");

        //2.创建jdbcTemplate对象
        JdbcTemplate jt = new JdbcTemplate();

        //3.给jt配置数据源
        jt.setDataSource(ds);

        //4.执行操作
        jt.execute("insert into account(name,money)values ('ccc',10000)");
    }
}

如上就是使用JDBCTemplate进行数据库操作的基本步骤了。但是此程序还存在着很多可以使用Spring IOC完善的地方。

4.使用IOC完善JDBCTemplate操作

创建bean.xml配置文件:

<?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">


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

    <!--配置数据源,Spring内置数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/spring"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

于是,jdbcTemplate操作类的写法可以改成:

/**
 * 配合IOC的JDBCTemplate使用
 */
public class jdbcTemplateDemo2 {
    public static void main(String[] args) {
        //1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

        //2.获取bean对象
        JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);

        //3.执行操作
        jt.execute("insert into account(name,money)values ('ccc',10000)");
    }
}

5.JDBC常用操作

###5.1插入、更新、删除操作

jt.update("insert into account(name,money)values (?,?)","eee",333);

###5.2 查询所有操作

其实关于query的语句有很多,在选择的时候,关注两个问题就够了:我们有什么(sql语句,参数),我们要什么(得到的返回值)。

List<Account> accountss = jt.query("select * from account where id > ?", new BeanPropertyRowMapper<Account>(Account.class),1);

其中,BeanPropertyRowMapper的作用是把查询的结果集封装到Account实体类中,然后将每个Account加到集合中。然后我们可以使用下面的语句,打印一下集合看效果:

for(Account account : accountss){
    System.out.println(account);
}

5.3 查询一个操作

List<Account> account = jt.query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class),10018);

5.4 返回一行一列

Integer num = jt.queryForObject("select count(*) from account",Integer.class);
System.out.println(num);

其中,第二个参数Integer.class代表的是你想要的返回值的类型,也就是num的类型。这个可以自定义。

6.JDBCTemplate在DAO中的使用

在实际开发中,我们常常在DAO中使用JDBCTemplate,因此这一节介绍JDBCTemplate在DAO中的使用,首先要在com.eastnotes.dao中创建一个AccountDao的接口和实现类,接口的代码:

import com.eastnotes.domain.Account;

public interface AccountDao {

    /**
     * 根据ID查询账户
     * @param id
     * @return
     */
    Account findAccountById(Integer id);

    /**
     * 根据名称查询账户
     * @param name
     * @return
     */
    Account findAccountByName(String name);

    /**
     * 更新账户
     * @param account
     */
    void updataAccount(Account account);
}

实现类的代码:

import com.eastnotes.domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;

import java.util.List;

/**
 * 账户的持久层接口实现
 * 通过集成JDBCDaoSupport,可以去除获取jdbcTemplate的重复代码,这样适用于多个DAO的时候
 * 使用xml配置可以使用spring 自带的jdbcDaoSupport,如果使用注解的方式,可以使用自定义的jdbcDaoSupport
 */
public class AccountDaoImpOld implements AccountDao {

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

    public Account findAccountById(Integer id) {
        List<Account> accounts = jdbcTemplate.query("select * from account where id = ? ",new BeanPropertyRowMapper<Account>(Account.class),id);
        return accounts.isEmpty() ? null : accounts.get(0);
    }

    public Account findAccountByName(String name) {
        List<Account> accounts = jdbcTemplate.query("select * from account where name = ? ",new BeanPropertyRowMapper<Account>(Account.class),name);
        if(accounts.isEmpty()){
            return null;
        }

        //因为id要有就要一个,但是其他的字段不一样
        if(accounts.size() > 1 ){
            throw new RuntimeException("结果集不唯一");
        }

        return accounts.get(0);
    }

    public void updataAccount(Account account) {
        jdbcTemplate.update("update account set name = ?, money = ? where id = ?",account.getName(),account.getMoney(),account.getId());
    }
}

##6.JDBCTemplate在DAO中的改进

上一节中我们在AccountDAO中使用set方法进行依赖注入,但是如果我们创建了其他的xxxDAO类,意味着我们还要写下面的重复代码:

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

如果我们单独写一个类,在此类中把获取jdbcTemplate的代码,然后在xxxDAO中去继承这个类就可以解决这个重复代码,其实Spring已经为我们写好了这个类,我们只需要在xxxDAO中继承他就好了,改进后的代码如下:

/**
 * 账户的持久层接口实现
 * 通过集成JDBCDaoSupport,可以去除获取jdbcTemplate的重复代码,这样适用于多个DAO的时候
 * 使用xml配置可以使用spring 自带的jdbcDaoSupport,如果使用注解的方式,可以使用自定义的jdbcDaoSupport
 */
public class AccountDaoImp extends JdbcDaoSupport implements AccountDao {

    public Account findAccountById(Integer id) {
        List<Account> accounts = getJdbcTemplate().query("select * from account where id = ? ",new BeanPropertyRowMapper<Account>(Account.class),id);
        return accounts.isEmpty() ? null : accounts.get(0);
    }

    public Account findAccountByName(String name) {
        List<Account> accounts = getJdbcTemplate().query("select * from account where name = ? ",new BeanPropertyRowMapper<Account>(Account.class),name);
        if(accounts.isEmpty()){
            return null;
        }

        //因为id要有就要一个,但是其他的字段不一样
        if(accounts.size() > 1 ){
            throw new RuntimeException("结果集不唯一");
        }

        return accounts.get(0);
    }

    public void updataAccount(Account account) {
        getJdbcTemplate().update("update account set name = ?, money = ? where id = ?",account.getName(),account.getMoney(),account.getId());
    }
}