目录
- spring事务传播属性
- 数据库定义隔离级别
- spring定义隔离级别
1. spring事务传播属性
Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的
spring保护的事务传播属性有以下这些(枚举类Propagation定义,引用TransactionDefinition类的常量)
常量名称 | 常量解释 |
---|---|
PROPAGATION_REQUIRED | 支持当前事务,如果当前没有事务,就新建一个事务,spring默认属性 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前没有事务,就抛出异常 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED 属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影 |
1.1 PROPAGATION_REQUIRED
**作用:**支持当前事务,如果当前没有事务,就新建一个事务
举例:
//事务属性 PROPAGATION_REQUIRED
methodA{
……
methodB();
……
}
//事务属性 PROPAGATION_REQUIRED
methodB{
……
}
说明: 当方法B执行时,会启动事务,方法A使用与B同一个事务
1.2 PROPAGATION_SUPPORTS
**作用:**支持当前事务,如果当前没有事务,就以非事务方式执行
举例:
//事务属性 PROPAGATION_REQUIRED
methodA(){
methodB();
}
//事务属性 PROPAGATION_SUPPORTS
methodB(){
……
}
说明: 单纯使用B方法时,以非事务的方式执行,执行A方法时,方法B加入A的事务进行执行。
1.3 PROPAGATION_MANDATORY
**作用:**支持当前事务,如果当前没有事务,就抛出异常
举例:
//事务属性 PROPAGATION_REQUIRED
methodA(){
methodB();
}
//事务属性 PROPAGATION_MANDATORY
methodB(){
……
}
说明: 单纯使用B方法时,因为当前方法没有一个活动的事务,会报IllegalTransactionStateException异常,执行A方法时,方法B加入A方法事务正常执行
1.4 PROPAGATION_REQUIRES_NEW
**作用:**总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起,需要使用JtaTransactionManager作为事务管理器
举例:
//事务属性 PROPAGATION_REQUIRED
methodA(){
doSomeThingA();
methodB();
doSomeThingB();
}
//事务属性 PROPAGATION_REQUIRES_NEW
methodB(){
……
}
说明: 单纯使用B方法时,正常启用一个事务进行执行。
使用方法A时运行流程
main(){
TransactionManager tm = null;
try{
//获得一个JTA事务管理器
tm = getTransactionManager();
tm.begin();//开启一个新的事务
Transaction ts1 = tm.getTransaction();
doSomeThing();
tm.suspend();//挂起当前事务
try{
tm.begin();//重新开启第二个事务
Transaction ts2 = tm.getTransaction();
methodB();
ts2.commit();//提交第二个事务
} Catch(RunTimeException ex) {
ts2.rollback();//回滚第二个事务
} finally {
//释放资源
}
//methodB执行完后,恢复第一个事务
tm.resume(ts1);
doSomeThingB();
ts1.commit();//提交第一个事务
} catch(RunTimeException ex) {
ts1.rollback();//回滚第一个事务
} finally {
//释放资源
}
}
1.5 PROPAGATION_NOT_SUPPORTED
**作用:**以非事务方式执行操作,如果当前存在事务,就把当前事务挂起,需要使用JtaTransactionManager作为事务管理器,可以参考上面一个属性,只是不重启新的第二个事务
PROPAGATION_NEVER
**作用:**总是非事务地执行,如果存在一个活动事务,则抛出异常
1.6 PROPAGATION_NESTED
**作用:**如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。这是一个嵌套事务,使用JDBC 3.0驱动时,仅仅支持DataSourceTransactionManager作为事务管理器。需要JDBC 驱动的java.sql.Savepoint类。有一些JTA的事务管理器实现可能也提供了同样的功能。使用PROPAGATION_NESTED,还需要把PlatformTransactionManager的nestedTransactionAllowed属性设为true;而 nestedTransactionAllowed属性值默认为false。
举例:
//事务属性 PROPAGATION_REQUIRED
methodA(){
doSomeThingA();
methodB();
doSomeThingB();
}
//事务属性 PROPAGATION_NESTED
methodB(){
……
}
说明: 当方法B执行时,按照REQUIRED属性方式执行
执行方法A时
main(){
Connection con = null;
Savepoint savepoint = null;
try{
con = getConnection();
con.setAutoCommit(false);
doSomeThingA();
savepoint = con2.setSavepoint();
try{
methodB();
} catch(RuntimeException ex) {
con.rollback(savepoint);
} finally {
//释放资源
}
doSomeThingB();
con.commit();
} catch(RuntimeException ex) {
con.rollback();
} finally {
//释放资源
}
}
当methodB方法调用之前,调用setSavepoint方法,保存当前的状态到savepoint。如果methodB方法调用失败,则恢复到之前保存的状态。但是需要注意的是,这时的事务并没有进行提交,如果后续的代码(doSomeThingB()方法)调用失败,则回滚包括methodB方法的所有操作。
嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚
2. 数据库定义隔离级别
隔离级别 | 值 | 导致的问题 |
---|---|---|
Read-Uncommitted | 0 | 导致脏读 |
Read-Committed | 1 | 避免脏读,允许不可重复读和幻读(默认的) |
Repeatable-Read | 2 | 避免脏读,不可重复读,允许幻读 |
Serializable | 3 | 串行化读,事务只能一个一个执行,避免了脏读、不可重复读、幻读。执行效率慢,使用时慎重 |
2.1 脏读:
一事务对数据进行了增删改,但未提交,另一事务可以读取到未提交的数据。如果第一个事务这时候回滚了,那么第二个事务就读到了脏数据。
2.2 不可重复读:
一个事务中发生了两次读操作,第一次读操作和第二次操作之间,另外一个事务对数据进行了修改,这时候两次读取的数据是不一致的。
###2.3 幻读:
第一个事务对一定范围的数据进行批量修改,第二个事务在这个范围增加一条数据,这时候第一个事务就会丢失对新增数据的修改。
2.4 总结:
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
大多数的数据库默认隔离级别为Read Commited,比如SqlServer、Oracle
少数数据库默认隔离级别为:Repeatable Read 比如: MySQL InnoDB
3. spring定义隔离级别
Isolation枚举类中定义了值
隔离级别 | 含义 |
---|---|
ISOLATION_DEFAULT | 使用数据库默认的事务隔离级别,默认的隔离级别 |
ISOLATION_READ_UNCOMMITTED | 对应数据库级别的Read-Uncommitted |
ISOLATION_READ_COMMITTED | 对应数据库级别的Read-Committed,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读 |
ISOLATION_REPEATABLE_READ | 对应数据库级别的Repeatable-Read,可以防止脏读,不可重复读。但是可能出现幻像读 |
ISOLATION_SERIALIZABLE | 对应数据库级别的Serializable,串行化读,事务只能一个一个执行 |