spring-JdbcTemplate学习总结
1、持久层总图
spring 框架提供很多操作模板类
- 操作关系型数据:
- JdbcTemplate
- HibernateTemplate
- 操作 nosql 数据库:
- RedisTemplate
- 操作消息队列:
- JmsTemplate
Mybatis 与 Spring-JdbcTemplate 的选择
- 小型项目
- Spring-JdbcTemplate 的性能更好,更适合管理域的sql语句
- 大型项目
- mybatis可以将sql语句批量的管理起来,还可以达到sql的重用
- mybatis还做数据库的驱动注册加载,数据库连接的创建与销毁等数据库的管理
- 可以让开发人员更关注于业务,更适合在业务域使用
2、JdbcTemplate:概述
- spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装
- 导包:spring-jdbc-5.0.2.RELEASE.jar、spring-tx-5.0.2.RELEASE.jar(事务)
3、JdbcTemplate:作用
- 用于和数据库进行交互,实现对数据库表的 CRUD操作
4、JdbcTemplate:对象
- 创建 spring16_JdbcTemplate 的工程,演示 JdbcTemplate对象的创建和使用
1. 编写 账户实体类
- 对应 spring_test 数据库中的 account账户表创建账户实体类,并实现序列化接口
// 账户的实体类
public class Account implements Serializable {
private Integer id;
private String name;
private Float money;
public Account() {
}
public Account(Integer id, String name, Float money) {
this.id = id;
this.name = name;
this.money = 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 +
'}';
}
}
2. 编写 Pom.xml 文件
- 导入 spring-context、spring-jdbc、spring-tx、mysql 的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.idea.spring</groupId>
<artifactId>spring16_JdbcTemplate</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>
</dependencies>
</project>
3. 编写 JdbcTemplate类
-
数据源的选择与配置:
-
使用 spring的内置数据源:DriverManagerDataSource 类
-
配置 C3P0 数据源:
- 导入 c3p0 的 Jar包
- 配置文件中配置数据源:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/spring_test"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean>
-
配置 DBCP 数据源:
- 导入 dbcp 的 Jar包
- 配置文件中配置数据源:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/spring_test"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean>
-
-
编写 JdbcTemplate1 类:
// JdbcTemplate的最基本用法
public class JdbcTemplateDemo1 {
public static void main(String[] args){
// 准备数据源:spring的内置数据源
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_test");
ds.setUsername("root");
ds.setPassword("123456");
//1.创建JdbcTemplate对象
JdbcTemplate jt = new JdbcTemplate();
// 给jt设置数据源
jt.setDataSource(ds);
//2.执行操作
jt.execute("insert into account(name,money) values('ccc',1000)");
}
}
=================================================================
运行结果: 插入账户 ccc 成功
4. 发现、解决问题
-
问题:
- 数据源的设置被固定,并且是以 Set 方法设置数据源的基本信息
- JdbcTemplate 对象是以 构造函数 创建
-
解决方式:
-
可以在 Spring框架的 IOC配置文件中直接配置
<?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> <!-- 配置数据源 --> <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_test"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property> </bean> </beans>
-
引入外部配置文件
配置属性文件 jdbc.properties:
jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/spring_test jdbc.username=root jdbc.password=123456
方式一:
<bean> class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"/> </bean>
方式二:
<context:property-placeholder location="classpath:jdbc.properties"/>
-
-
运行 JdbcTemplateDemo2 类:
// JdbcTemplate的最基本用法
public class JdbcTemplateDemo2 {
public static void main(String[] args){
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
//3.执行操作
jt.execute("insert into account(name,money) values('ddd',2000)");
}
}
- 运行结果:插入账户 ddd 成功
- 用配置文件的方式:创建 JdbcTemplate 对象并调用 execute ( ) 方法,避免数据源信息固定的弊端
5、JdbcTemplate:CRUD
- 创建 JdbcTemplateDemo3 类,测试 JdbcTemplate对象的 CRUD操作
1. 获取容器和对象
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
JdbcTemplate jt = (JdbcTemplate) ac.getBean("jdbcTemplate");
2. 保存
- 调用 update ( Insert 语句、参数 ) 方法
jt.update("insert into account(name,money) values(?,?)","eee",3333f);
3. 更新
- 调用 update ( update 语句、参数 ) 方法
jt.update("update account set name = ? , money = ? where id = ?","test",4567f,10);
3. 删除
- 调用 update ( delete 语句、参数 ) 方法
jt.update("delete from account where id = ? ",8);
4. 查询所有
① 方式一:
- 手动创建 AccountRomMapper 类继承 RowMapper
// 定义 Account 的封装策略
class AccountRomMapper implements RowMapper<Account>{
@Override
// 把结果集中的数据封装到Account中,然后由spring把每个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;
}
}
- 调用 query( 查询语句、new RowMapper ( )、参数)方法
List<Account> accounts = jt.query("select * from account where money > ? ",new AccountRomMapper(),1000f);
for (Account account : accounts) {
System.out.println(account);
}
② 方式二:
- Spring框架提供的 BeanPropertyRowMapper< 封装类型 >( .class字节码 )
- 调用 query(查询语句、new BeanPropertyRowMapper<>()、参数)方法
List<Account> accounts = jt.query("select * from account where money > ? ",new BeanPropertyRowMapper<Account>(Account.class),1000f);
for(Account account : accounts) {
System.out.println(account);
}
5. 与 QueryRunner 区别
- QueryRunner 的 query ( ) 方法返回的结果只有一个泛型
- Spring-JdbcTemplate 的 query ( ) 方法返回的结果可以是泛型、集合等
6. 查询一个
- 查询单个记录时,与查询多条记录时调用方法相同
- 调用 query ( 查询语句+条件、new BeanPropertyRowMapper<>(),参数 )
- 也存在专门查询单条记录的方法,只不过使用较少
List<Account> accounts = jt.query("select * from account where id = ? ",new BeanPropertyRowMapper<Account>(Account.class),1);
System.out.println(accounts.isEmpty()?"没有内容":accounts.get(0));
7. 查询返回一行一列
- 调用 queryForObject(查询语句、结果类型、参数)方法
Long count = jt.queryForObject("select count(*) from account where money > ?", Long.class, 1000f);
System.out.println(count);
- 问题:spring-jdbc版本过新,无法查询到结果,会报异常
- 解决:将 spring-jdbc 的 Jar包版本选用低版本的,即可查询成功
6、JdbcTemplate:Dao 使用
- 创建 jdbcTemplateDemo4 类,演示 JdbcTemplate 在 Dao持久层的使用
1. 编写 账户持久层
- 编写 账户持久层接口 AccountDao
// 账户的持久层接口
public interface AccountDao {
// 根据Id查询账户
Account findAccountById(Integer accountId);
// 根据名称查询账户
Account findAccountByName(String accountName);
// 更新账户
void updateAccount(Account account);
}
- 编写 账户持久层接口实现类 AccountDaoImpl
// 账户的持久层实现类
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
// Set方法等待spring注入
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Account findAccountById(Integer accountId) {
List<Account> accounts = jdbcTemplate.query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
@Override
public Account findAccountByName(String accountName) {
List<Account> accounts = jdbcTemplate.query("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class), accountName);
if(accounts.isEmpty()){
return null;
}else if(accounts.size()>1){
throw new RuntimeException("结果集不唯一");
}else {
return accounts.get(0);
}
}
@Override
public void updateAccount(Account account) {
jdbcTemplate.update("update account set name = ? ,money = ? where id = ? ",account.getName(),account.getMoney(),account.getId());
}
}
2. 方法测试
- 在 JdbcTemplateDemo4 类中,对 Dao层方法进行测试
// JdbcTemplate的CRUD操作
public class JdbcTemplateDemo4 {
public static void main(String[] args){
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取 accountDao对象
AccountDao accountDao = (AccountDao) ac.getBean("accountDao");
//3.执行方法
Account account1 = accountDao.findAccountById(1);
System.out.println(account1);
Account account2 = accountDao.findAccountByName("ccc");
System.out.println(account2);
account2.setMoney(9999f);
accountDao.updateAccount(account2);
}
}
3. 发现问题
- 问题:Dao类有很多,每个Dao接口实现类中,都存在重复代码
private JdbcTemplate jdbcTemplate;
// Set方法等待spring注入
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
-
解决:
- 每个Dao接口实现类继承 spring框架提供的 JdbcDaoSupport 类
import org.springframework.jdbc.core.support.JdbcDaoSupport;
4. 解决问题
-
使用情况不同:
-
当使用 注解配置时,不继承 JdbcDaoSupport 类,使用注解等待 spring框架自动依赖注入
// 账户的持久层实现类 // 演示基于注解配置时,不需要继承 JdbcDaoSupport类,直接使用注解配置等待注入即可 @Repository public class AccountDaoImpl2 implements AccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public Account findAccountById(Integer accountId) { List<Account> accounts = jdbcTemplate.query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), accountId); return accounts.isEmpty()?null:accounts.get(0); } @Override public Account findAccountByName(String accountName) { List<Account> accounts = jdbcTemplate.query("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class), accountName); if(accounts.isEmpty()){ return null; }else if(accounts.size()>1){ throw new RuntimeException("结果集不唯一"); }else { return accounts.get(0); } } @Override public void updateAccount(Account account) { jdbcTemplate.update("update account set name = ? ,money = ? where id = ? ",account.getName(),account.getMoney(),account.getId()); } }
-
当使用 XML配置时,继承 spring框架提供的 JdbcDaoSupport 类
- 修改 bean.xml 文件中,向 AccountDaoImpl1 类中注入 dataSource 数据源即可
<bean id="accountDao" class="dao.Impl.AccountDaoImpl1"> <property name="dataSource" ref="dataSource"></property> </bean>
// 账户的持久层实现类 // 演示继承 spring框架提供的 JdbcDaoSupport 类 public class AccountDaoImpl1 extends JdbcDaoSupport implements AccountDao { @Override public Account findAccountById(Integer accountId) { List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), accountId); return accounts.isEmpty()?null:accounts.get(0); } @Override public Account findAccountByName(String accountName) { List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?", new BeanPropertyRowMapper<Account>(Account.class), accountName); if(accounts.isEmpty()){ return null; }else if(accounts.size()>1){ throw new RuntimeException("结果集不唯一"); }else { return accounts.get(0); } } @Override public void updateAccount(Account account) { super.getJdbcTemplate().update("update account set name = ? ,money = ? where id = ? ",account.getName(),account.getMoney(),account.getId()); } }
-