SpringJdbcTemplate是Spring框架中对Jdbc的封装。其提供了常用的数据库操作方法,包括:
并且,JdbcTemplate提供了对查询结果进行封装的方法,这极大的减少了我们花在封装返回结果集的工作量。
1、导入依赖
要使用JdbcTemplate,首先要做的就是导入所需的依赖。这里使用的是Maven工程的方式导入,如果不是Maven工程请自行下载相关的Jar包导入即可。
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>5.2.6.RELEASEversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.17version>
dependency>
2、创建jdbcTemplate对象
创建JdbcTemplate对象之间呢,我们打开它所在的类,发现有三个构造方法,这里选择带一个参数的构造方法。既然选择了这个方法,那创建JdbcTemplate对象之前应该先获取一个DateSource对象。DateSource对象我们都很熟悉了,它里面包含了用户要连接数据库的相关信息。
// 准备数据源:spring内置数据源,DriverManagerDataSource
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT");
ds.setUsername("root");
ds.setPassword("811236");
//1. 创建对象
JdbcTemplate jt = new JdbcTemplate(ds);
3、 使用JdbcTemplate对象执行操作
这里使用的是JdbcTemplate的query方法,这个方法有很多的重载。我们使用的是带sql语句和RowMapper参数的这一个。RowMapper是一个接口,要使用的话,我们还要实现它的mapRow方法。其中的泛型是要封装的实体类,参数中的ResultSet是键值对形式的结果集,i表示第几行结果,从0开始。
//2. 执行操作
List<Account> accounts = jt.query("select * from account", new RowMapper<Account>() {
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;
}
});
for (Account account : accounts) {
System.out.println(account);
}
经过上面一顿操作,我们已经可以使用JdbcTemplate对象来查询数据库中的数据了。
但是,上面的使用是有问题的。首先DataSource是写死在代码中的无法在运行的过程中修改。其次JdbcTemplate对象是使用new关键字new出来的。最后对结果集的封装代码还是要我们自己手动去完成。
package cn.snowing.jdbctemplate;
import cn.snowing.domain.Account;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
// 准备数据源:spring内置数据源,DriverManagerDataSource
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT");
ds.setUsername("root");
ds.setPassword("811236");
//1. 创建对象
JdbcTemplate jt = new JdbcTemplate(ds);
//2. 执行操作
List<Account> accounts = jt.query("select * from account", new RowMapper<Account>() {
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;
}
});
for (Account account : accounts) {
System.out.println(account);
}
}
}
其实在导入Jar的时候,我们导入整个spring.framework的内容,但是在上面的代码中,我们仅仅只是用到了其中的jdbc相关的内容。并没有用到spring的核心容器来做IOC,也没有将依赖注入交给spring来处理。
此外,在上面的操作中,我们是把使用和定义都放在了同一个类中,这明显违背了职责单一性原则。因此,首先要做的就是将责任分离。
在实际的开发当中,通常将对数据库操作的方法放在Dao层。基于面向接口编程的原则,这里首先定义一个Dao的接口,然后再实现这个接口。这个接口应当包含对数据操作的常用方法,比如常用的增删改查方法等等。这里只是描述问题,因此只是定义了三个方法。
Dao接口
package cn.snowing.dao;
import cn.snowing.domain.Account;
/**
* 账户的持久层接口
*/
public interface IAccountDao {
/**
* 根据id查询账户
* @param id
* @return
*/
Account findAccountById(Integer id);
/**
* 根据名称查询账户
* @param name
* @return
*/
Account findAccountByName(String name);
/**
* 更新账户
* @param account
*/
void updateAccount(Account account);
}
Dao实现类
package cn.snowing.dao.impl;
import cn.snowing.dao.IAccountDao;
import cn.snowing.domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
/**
* 账户的持久层实现类
*/
public class AccountDaoImpl implements IAccountDao {
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;
}
if (accounts.size()>1){
throw new RuntimeException("结果集不唯一");
}
return accounts.get(0);
}
public void updateAccount(Account account) {
jdbcTemplate.update("update account set name = ?, money = ? where id = ?"
, account.getName(), account.getMoney(), account.getId());
}
}
接口比较简单,我们就不看了,这进而直接看实现类。实现类定义了jdbctemplate成员变量,类中的所有方法都使用这个对象来执行Sql语句。但是这里并没有创建这个对象。
这就是我们上面说的要解决的问题。我们需要将jdbcTemplate对象的创建交给Spring框架来完成。要想spring框架帮我们创建对象,就要进行相应的配置。那我们就配置一个jdbcTemplate对象,但是发现jdbcTemplate对象需要一个DataSource对象。所以,还需要配置一个DataSource对象,然后通过property中的ref属性来引用。这样一来DataSource写死和new JdbcTemplate对象的问题都得到了解决。
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<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 name="url" value="jdbc:mysql://localhost:3306/eesy?serverTimezone=GMT"/>
<property name="username" value="root"/>
<property name="password" value="811236"/>
bean>
beans>
完成了上面的配置,那么DataSource对象有了,创建jdbcTemplate的参数也就有了。但是执行查询方法时,封装结果集的方法还没有讲。其实上面的代码中已经给出了,BeanPropertyRowMapper是RowMapper的一个实现类。我们只需要向其提供泛型和字节码,就能够自动的帮我们实现对结果集的封装。而不需要我们再写RowMapper的实现类。
经过上面的操作,貌似所有的操作都已经完成了。那就写一个测试类吧。等等,我们要使用这个dao的实现类是不是还要new一个dao实现类的对象?那不行,我千辛万苦才解决new一个jdbcTemplate对象的问题,结果又来一个new dao实现类的操作? 这显然不合理,怎么办呢?当然还是交给spring框架来处理。
在上面的bean.xml中加入以下内容,这样dao实现类的对象也加入到了spring的核心容器中。需要使用这个对象时直接从spring核心容器中拿就可以。
<bean id="accountDao" class="cn.snowing.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
bean>
下面就是测试类。
package cn.snowing.jdbctemplate;
import cn.snowing.dao.IAccountDao;
import cn.snowing.dao.impl.AccountDaoImpl;
import cn.snowing.domain.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class JdbcTemplateDemo4 {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
IAccountDao accountDao = ac.getBean("accountDao", IAccountDao.class);
//2. 执行操作
Account account = accountDao.findAccountByName("bbb");
System.out.println(account);
account.setMoney(10010f);
accountDao.updateAccount(account);
account = accountDao.findAccountById(account.getId());
System.out.println(account);
}
}