1 什么是事务
1.1事务的概念
事务是一系列的操作,这些操作构成了一次完整的动作单元。这些操作必须全部成功,如果其中某个操作失败,则全部回滚到初始状态。事务是为了保证数据的完整性和一致性。
1.2 事务的特性
事务的ACID特性:
(1) 原子性:确保所有操作要么全部成功,要么全部失败。
(2) 一致性:一旦事务完成(无论成功还是失败),系统必须确保业务处于一致状态。
(3) 隔离性:事务之间不能相互影响,以保证数据的一致性。
(4) 持久性:一旦事务完成,无论系统发生任何状况,都不会影响已完成的结果。
2 Spring事务核心
2.1 PaltformTransactionManager接口
PaltformTransactionManager接口是Spring事务定义的抽象策略接口。Spring事务并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给如Hibernate、Mybatis等持久化框架的事务来实现。
public interface PlatformTransactionManager {
TransactionStatus getTransaction(
TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
PaltformTransactionManager接口中的getTransaction()方法,是根据TransactionDefinition参数返回一个TransactionStatus对象,该对象可以表示一个新的事务,也可以表示一个已存在的事务。
TransactionStatus接口为事务代码提供了一种控制事务执行和查询事务状态的简单方法。
public interface PlatformTransactionManager {
TransactionStatus getTransaction(
TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
2.2 Spring事务属性
Spring在TransactionDefinition中定义了事务的属性。包括:传播性、隔离性、超时、只读、回滚规则。
传播性
事务的传播性是指,如果在开始当前事务之前,已经存在一个事务,此时有多个选项来指定当前事务的执行行为。事务的传播属性包括以下7个。
(1) Required:如果当前存在事务,则加入该事务;如果不存在,则创建新的事务。
(2) Required_new:如果当前存在事务,则挂起该事务,创建一个新的事务;如果不存在,则创建新事务。
(3) Supports:如果当前存在事务,则加入该事务;如果不存在,则以非事务方式运行。
(4) Not_Supports:以非事务方式运行,如果当前存在事务,则挂起该事务。
(5) Never:以非事务方式运行,如果当前存在事务,则抛出异常。
(6) Mandatory:如果当前存在事务,则加入该事务;如果不存在,则抛出异常。
(7) Nested:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务;如果不存在,则按照Required的方式执行。
前六种传播行为是Spring从EJB中引入的。而Nested是Spring特有的。以Nested启动的事务内嵌与外部事务,内嵌事务并不是一个独立的事务。只有外部事务提交后,内嵌事务才能提交。外部事务回滚也会导致内嵌事务回滚。
隔离性
事务的隔离性是指,当前事务与其他事务的工作隔离程度。例如:当时事务是否能看到其他事务未提交的数据。
Spring在TransactionDefinition定义了5个隔离属性的常量。
(1) Default:默认值,表示使用底层数据库的默认隔离级别。对于大多数数据库该级别就是Commit;
(2) UnCommit:该级别表示一个事务可以读取另一个事务未提交的数据。该级别不能防止脏读和不可重复读。
(3) Commit:该级别表示一个事务只能读取另一个事务提交的数据。可以防止脏读。大多数情况下推荐使用的级别。
(4) Repeatable_Read:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询,这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
(5) Serializable:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
超时
由于事务的执行会占用数据库资源,为避免数据库资源被长期占用,所以事务的超时属性就是设定事务在指定的时间内没有执行完毕就自动回滚。默认是不限制超时时间。
只读
数据库可以利用事务的只读属性来进行一些特定的优化。
回滚规则
默认情况下Spring事务只会在系统抛出运行时未检查的异常时进行回滚。也就是说,当抛出的异常是RuntimeException或其子类时。Spring事务可以指定rollback-for和not-roolback-for。
3 声明式事务
声明式事务是通过AOP动态代理实现的,可以有效的与业务代码解耦。
3.1 配置方法
在spring配置文件中加入以下配置:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(
TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
注意:
如果要连接的PlatformTransactionManager的bean名称为transactionManager,那么可以忽略<tx:annotation-driven />标记中的transaction-manager属性。 如果您想要依赖注入的PlatformTransactionManager bean具有任何其他名称,那么您必须显式地使用transaction-manager属性,如前面的示例。
3.2使用方法
在代码中使用@Transactional注解来实现事务控制,示例如下:
@Transactional
public void insert(){
//业务代码
}
@Transactional属性如下表:
属性 | 类型 | 描述 |
Value | String | 指定要使用的事务管理器标识 |
Propagation | enum | 事务传播属性(默认为required) |
Isolation | enum | 事务隔离属性(默认为default) |
readonly | boolean | 默认为false |
timeout | Int(seconds) | 事务超时时间,默认-1 |
rollbackFor | Class[] | 指定回滚异常类 |
foolbackForClassName | String[] | 指定回滚异常类名 |
NotRollbackFor | Class[] | 指定不回滚异常类 |
NotRollbackForClassName | String[] | 指定不回滚异常类名 |
4 编程式事务
Spring还提供了编程式事务,可以在代码中精确的控制事务。Spring提供了两种编程式事务实现方式。第一种是使用TransactionTemplate;第二种是使用PlatformTransactionManager。
4.1 TransactionTemplate
(1)配置方式
在配置文件中加入以下配置:
<bean id="sharedTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED"/>
<property name="timeout" value="30"/>
</bean>
(2)使用方法
@Resource
private TransactionTemplate transactionTemplate;
//没有返回
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
}
});
//有返回
return transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
return resultOfUpdateOperation2();
}
});
//还可以手动执行回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
4.2 PlatformTransactionManager
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);