Spring-JDBCTemplate
Spring的JDBC的模板
- Spring是EE开发的一站式的框架,有EE开发的每层的解决方案。
- Spring对持久层也提供了解决方案:ORM模块和JDBC的模板。
- Spring提供了很多的模板用于简化开发。
- JDBC
org.springframework.jdbc.core.jdbc.jdbcTemplate
- Hibernate
orm.springframework.orm.hibernamte.HibernateTemplate
- JDBC
JDBC模板使用的入门
- 1.引入jar包
- Spring开发基本Jar包
- 数据库驱动
- Spring的JDBC模板的jar包
- 2.创建数据库和表
create table account(
id int primary key auto_increment,
name varchar(20),
money double
);
- 3.使用JDBC的模板
@Test
public void test1(){
// 1.创建连接池(数据库相关信息)
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("1234");
// 2.创建JDBC模板
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("INSERT INTO account VALUES (null,?,?)","XhhBlog",100d);
}
将连接池和模板交给Spring管理
创建 application.xml
配置文件配置Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<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/spring?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
使用jdbcTemplate注解插入数据
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void test(){
jdbcTemplate.update("INSERT INTO account VALUES (null,?,?)","Xhh",1000D);
}
}
使用开源连接池
DBCP
引入jar包
配置DBCP连接池
C3P0
引入jar包
c3p0配置数据库连接属性有点不一样
DRUID
引入jar包
配置
使用属性文件配置数据库连接信息
创建属性文件
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
jdbc.username=root
jdbc.password=1234
配置文件中引入属性文件
<bean>
<context/>
JDBC模板CRUD操作
我这里只粘代码,没有粘截图,自己看代码模板的语句即可。
插入操作
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void test(){
jdbcTemplate.update("INSERT INTO account VALUES (null,?,?)","Xhh",2000D);
}
}
删除操作
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void test(){
jdbcTemplate.update("DELETE FROM account WHERE id = ?",13);
}
}
更新操作
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void test() {
jdbcTemplate.update("UPDATE account SET name = ?,money = ? WHERE id = ?", "小灰灰", 2000D, 12);
}
}
查询操作
查询某一个字段
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void test() {
// String.class 查询结果的类型
String name = jdbcTemplate.queryForObject("SELECT name FROM account WHERE id = ?", String.class, 12);
System.out.println(name);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void test() {
// Long.class 查询结果的类型
Long count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM account", Long.class);
System.out.println(count);
}
}
查询多条返回对象的集合
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void test() {
List<Account> list = jdbcTemplate.query("SELECT * FROM account", new MyRowMapper());
for (Account account : list) {
System.out.println(account);
}
}
}
class MyRowMapper implements RowMapper<Account> {
@Override
public Account mapRow(ResultSet rs, int i) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getDouble("money"));
return account;
}
}
public class Account {
private Integer id;
private String name;
private Double 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 Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
查询单条
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void test() {
Account account = jdbcTemplate.queryForObject("SELECT * FROM account WHERE id = ?", new MyRowMapper(), 12);
System.out.println(account);
}
}
class MyRowMapper implements RowMapper<Account> {
@Override
public Account mapRow(ResultSet rs, int i) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getDouble("money"));
return account;
}
}
事务
事务概述
什么是事务
逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败。
事务的特性
原子性:事务不可分割
一致性:事务执行前后数据完整性保持一致
隔离性:一个事务的执行不应该受到其他事务的干扰
持久性:一旦事务结束,数据就持久化到数据库
如果不考虑隔离性引发安全性问题
读问题
脏读 :一个事务读到另一个事务未提交的数据。
不可重复读 :一个事务读到另一个事务已经提交的update的数据,导致一个事务中多次查询结果不一致。
虚读、幻读 :一个事务读到另一个事务已经提交的insert的数据,导致一个事务中多次查询结果不一致。
写问题
- 丢失更新
解决读问题
设置事务的隔离级别
Read uncommitted :未提交读,任何读问题解决不了。
Read committed :已提交读,解决脏读,但是不可重复读和虚读有可能发生。
Repeatable read :重复读,解决脏读和不可重复读,但是虚读有可能发生。
Serializable :解决所有读问题。
Spring的事务管理的API
PlatformTransactionManager
PlatformTransactionManage: 平台事务管理器 是一个接口,下面有两个实现类
- DataSourceTransactionManager:底层使用JDBC管理事务
- HibernateTransactionManager:底层使用Hibernate管理事务
TransactionDefinition
- 事务定义信息: 用于定义事务的相关的信息,隔离级别、超时信息、传播行为、是否只读。
TransactionStatus
- 事务状态:用于记录在事务管理过程中,事务的状态的对象。
事务管理的API的关系
- Spring进行事务管理的时候,首先平台事务管理器根据事务定义信息进行事务的管理。
- 在事务管理过程中,产生各种状态,将这些状态的信息记录到事务状态的对象中。
Spring的事务的传播行为
什么是传播行为
一个业务方法当中,调用另一个业务的方法。
Spring中提供了七种事务的传播行为
保证多个操作在同一个事务中
PROPAGATION_REQUIRED | 默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来 |
---|---|
PROPAGATION_SUPPORTS | 支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。 |
PROPAGATION_MANDATORY | 如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。 |
保证多个操作不在同一个事务中
PROPAGATION_REQUIRES_NEW | 如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。 |
---|---|
PROPAGATION_NOT_SUPPORTED | 如果A中有事务,将A的事务挂起。不使用事务管理。 |
PROPAGATION_NEVER | 如果A中有事务,报异常。 |
嵌套式事务
PROPAGATION_NESTED
- 嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点。
- 执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。
Spring事务管理
1.搭建Spring事务管理环境
创建AoccuntDao
public interface AccountDao {
public void OutMoney(String from,Double money);
public void InMoney(String to,Double money);
}
实现Dao接口
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void OutMoney(String from, Double money) {
this.getJdbcTemplate().update("update account set money=money-? where name =?",money,from);
}
@Override
public void InMoney(String to, Double money) {
this.getJdbcTemplate().update("update account set money= money+? where name=?",money,to);
}
}
把Dao交给Spring管理
在Dao中注入数据源
在DAO当中注入jdbc模板,要保证dao继承了JdbcDaoSupport
继承之后, 就有了datasource的set方法,就可以注入了
Dao继承JdbcDaoSupport
DAO注入JDBC模板
创建Account业务
public interface AccountService {
public void transferMoney(String from,String to, Double money);
}
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transferMoney(String from, String to, Double money) {
accountDao.InMoney(to, money);
accountDao.OutMoney(from, money);
}
}
配置service 交给spring 并注入dao
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringJDBCTest2 {
@Resource
private AccountService accountService;
@Test
public void test() {
accountService.transferMoney("XhhBlog","小灰灰",100D);
}
}
2.添加事务
编程式事务
需要手动编写代码
配置平台事务管理器
<!--配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Spring提供了事务管理的模板类
<!--配置事务管理模板-->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
在业务层注入事务管理的模板
编写事务管理的代码
声明式事务
XML方式声明事务管理
引入aop的开发包
配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
AOP的配置
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
配置
<aop:config>
<aop:pointcut id="pointcut1" expression="execution(* com.qc.demo1.service.AccountServiceImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
注解方式声明事务管理
配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
开启注解事务
<!--配置增强-->
<tx:annotation-driven transaction-manager="transactionManager"/>
在业务层添加注解
@Transactional