最近看了不少关于spring事务的博客,自己也动手实践了一番,决定自己也写一篇博客整理一下,算是学习吧。
一、事务的四大特性ACID:
(1)原子性 Atomicity
事务是一系列操作的集合,但是也是原子性的,事务的原子性确保事务操作要么全部成功,要么全部失败。
(2)一致性 Consistency
一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
(3)隔离性 Isolation
可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
(4)永久性 Durability
事务对数据的操作因该是永久的,一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
二、Spring事务核心接口
Spring的核心接口是 PlatformTransactionManager ,其他的事务管理器都需要实现这个接口。
1、PlatformTransactionManager 源码:
package org.springframework.transaction;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}
PlatformTransactionManager 接口主要定义了三个方法:
(1)TransactionStatus getTransaction(TransactionDefinition var1)
由TransactionDefinition得到TransactionStatus对象
(2)void commit(TransactionStatus var1)
提交事务
(3)void rollback(TransactionStatus var1)
回滚事务
2、TransactionDefinition接口源码:
package org.springframework.transaction;
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
TransactionDefinition 接口主要定义了五个方法:
(1)int
getPropagationBehavior();
返回事务的传播行为。
(2)int
getIsolationLevel();
返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据。
(3)int
getTimeout();
返回事务必须在多少秒内完成。
(4)boolean
isReadOnly();
事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的。
(5)String getName();
获取事务名称。
3、主要的几种事务管理器
(1)
DataSourceTransactionManager 当应用程序中直接使用JDBC来进行持久化时适用
(2)
HibernateTransactionManager 当应用程序的持久化是通过Hibernate实现时适用
(3)
JpaTransactionManager 当使用Java持久化API事务(JPA)时适用
(4)
JtaTransactionManager Java原生API事务,跨越了多个事务管理源时适用
三、七种事务传播行为(propagation behavior):
(1)PROPAGATION_REQUIRED (默认)支持使用当前事务,如果当前事务不存在,创建一个新事务。
(2)PROPAGATION_SUPPORTS 支持使用当前事务,如果当前事务不存在,则不使用事务。
(3)PROPAGATION_MANDATORY 中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出异常。
(4)PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
(5)PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
(6)PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
(7)PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前不存在事务,则以REQUIRED的方式执行。
关于回滚需要注意的地方:
1、PROPAGATION_REQUIRES_NEW 外层事务回滚不影响内层事务的提交,内层事务不会回滚,也就是说两个事务是独立的。外层事务可以捕获内层事务的异常,至于需不需要捕获回滚,外层事务可以根据实际情况自己决定。
2、PROPAGATION_NESTED 如果当前有事务,属于嵌套执行,和新起事务不同的是,NESTED嵌套执行可以看作一个整体,内层事务是外层事务的子事务,内层事务会受到外层回滚的影响,如果外层回滚,内层也会回滚;如果内层事务回滚,则会回滚到事先设置好的回滚点(savepoint),内外层事务将一起提交。
四、脏读,不可重复读,幻读:
(1)脏读:一个事务读取到另一个事务未提交的数据。如果事务B第一步修改了数据,这时候这个修改的数据别事务A读到了事务B为提交的数据,但是事务B最后回滚了,这时候事务A读到的数据就是错误的,不被承认的数据。
(2)不可重复读:一个事务有多次查询操作,在两次查询操作期间,另外一个事务对数据进行了修改,导致两次查询得到的结果不一致。即事务A读到了事务B已经提交的修改的数据。
(3)幻读:一个事务有多次查询操作,在两次查询操作期间,另外一个事务对表进行了插入,导致两次查询得到的结果不一致。即事务A读到了事务B已经提交的插入插入数据。如在事务A有两次 select count(*) 查询数据量操作,但是在两次查询期间,事务B对相应的表执行了insert操作,则会导致两次查询结果不一样,多出来的一条数据好像幻象一样,所以叫幻读。
五、四种事务隔离级别:
这里的四种事务隔离级别与MySQL的四种事务隔离级别对应,含义也是一样的。
(1)ISOLATION_READ_UNCOMMITTED 读取未提交: 级别最低的隔离级别,允许出现脏读,不可重复读,幻读。
(2)ISOLATION_READ_COMMITTED 读取已提交: 不允许脏读,但是允许不可重复读,和幻读。
(3)ISOLATION_REPEATABLE_READ 可重复读: 不允许脏读,不可重复读,但是允许幻读。
(4)ISOLATION_SERIALIZABLE 可串行化: 不允许脏读,不可重复读和幻读。
另外:
(5)TIMEOUT_DEFAULT 使用数据库默认隔离级别
注意:
1、MySQL支持上述4种事务隔离级别,默认事务隔离级别为 ISOLATION_REPEATABLE_READ。
2、Oracle只支持ISOLATION_READ_COMMITTED和ISOLATION_SERIALIZABLE两种,默认为READ_COMMITTED。