Spring事务
2018-07-07 本文已影响0人
萧衍_
一. 事务特性ACID
- 原子性
- 一致性
- 隔离性
- 持久性
二. 事务管理器
Spring并不直接管理事务,而是提供事务管理器接口,让框架自己(包括JDBC、hibernate、JPA、JTA等)实现具体的事务管理。
2.1 spring提供的事务管理器接口
包括3个接口:获取事务状态、提交、回滚
package org.springframework.transaction;
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}
2.2 具体实现(以JDBC为例)
DataSourceTransactionManager通过DataSource获取到java.sql.Connection,再调用java.sql.Connection来管理事务
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="具体数据源"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
三. 事务基本属性
上文提到的spring事务管理器接口中,用于获取事务状态的getTransaction方法参数定义了一个事务的基本属性
TransactionStatus getTransaction(TransactionDefinition var1)
事务基本属性包括5类:
- 传播行为
- 隔离级别
- 是否只读
- 超时时间
- 回滚规则
public interface TransactionDefinition {
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
3.1 传播行为 PROPAGATION
定义一个事务被另一个事务调用时,两个事务之间的关系,如:被调用事务合并到调用事务中运行,或者独立开启一个新事务运行等。
Spring定义了七种传播行为:
- require_new(本身执行时是事务,被事务调用时也不合并为同一个事务)
- require(本身执行时是事务,被事务调用时可合并在同一个事务里)
- support(本身执行时不是事务,被事务调用时可合并在同一个事务里)
- not_support(总是非事务地执行,并挂起任何存在的事务)
- mandatory(本身执行时抛出异常,被事务调用时可合并在同一个事务里)
- never(总是非事务地执行,如果被其它事务调用则抛出异常)
- nest(嵌套事务,本身执行时是事务,被事务调用时也不合并为同一+ 个事务,但是外层事务失败时内层事务也要回滚)
3.2 隔离级别
定义了一个事务可能受其他并发事务影响的程度
1.并发事务问题:
- 脏读(一个事务读取了另一个事务改写但尚未提交的数据时,改写在稍后被回滚了,那么第一个事务获取的数据就是无效的)
- 不可重复读
- 幻读(事务T1读取了几行数据,接着另一个并发事务T2插入了一些数据,故在随后的查询中,事务T1就会发现多了一些原本不存在的记录)
不可重复读的重点是同一个数据被修改了,幻读的重点在于有数据新增或者删除。
从结果看, 似乎不可重复读和幻读都表现为两次读取的结果不一致。但如果从控制的角度来看, 两者的区别就比较大:
- 对于前者, 只需要锁住满足条件的记录
- 对于后者, 要锁住满足条件及其相近的记录
2.隔离级别
- defaul(使用数据库默认隔离级别)
- read_uncommit(允许读取未commit数据,会导致上面3种问题)
- read_commit(允许读取commit数据,仅可避免脏读)
- repeatable_read(数据只可被自身事务修改,可避免脏读、不可重复读)
- Serializable(完全满足ACID,通常是锁表实现)
3.3 是否只读
如果事务只对数据库进行读操作,则数据库可以进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。
3.4 超时时间
事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。
3.5 回滚规则
默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)
但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
四. spring事务实现方式
- 编程式事务(侵入到业务代码里,但提供了更加详细的事务管理)
- 声明式事务(基于AOP,不影响业务代码的具体实现)
4.1 编程式事务
- 使用TransactionTemplate
- 直接使用PlatformTransactionManager
4.2 声明式事务
- 每个Bean都有一个代理
- 所有Bean共享一个代理基类
- 使用拦截器
- 使用tx标签配置的拦截器
- 全注解
4.3 demo(声明式事务,全注解方式)
使用@Transactional注解
/**
* 1.propagation 指定事务的传播行为
* 默认取值为REQUIRED,即使用调用方法的事务
* 设置为REQUIRES_NEW,即使用自己的事务,调用方法的事务被挂起
* 2.isolation 指定事务的隔离级别,最常用的取值为READ_COMMITTED
* 3.Spring 的声明式事务默认对所有运行时异常进行回滚,也可以通过对应的属性进行自行设置
* 4.readOnly 指定事务是否为只读,若这个事务只读取数据则设置为true,可帮助数据库引擎优化事务
* 5.timeOut 指定强制回滚之前事务可以占用的时间
*/
@Transactional(propagation=Propagation.REQUIRES_NEW,
isolation=Isolation.READ_COMMITTED,
noRollbackFor={UserAccountException.class},
readOnly=true, timeout=3)
@Override
public void purchase(String username, String isbn) {
//1.获取书的单价
int price = bookShopDao.findBookPriceByIsbn(isbn);
//2.更新书的库存
bookShopDao.updateBookStock(isbn);
//3.更新用户余额
bookShopDao.updateUserAccount(username, price);
}
测试事务的传播行为
@Transactional
@Override
public void checkout(String username, List<String> isbns) {
for(String isbn : isbns) {
bookShopService.purchase(username, isbn);
}
}