1. 事务概述
1.1 事务的四个特性 ACID
- 原子性(Automic): 事务作为一个整体被执行,包含在事务中对数据库的操作,要么全部被执行,要么全部不被执行。
- 一致性(Consistency): 事务应该保证数据库从一个一致状态转变为另外一个状态。
- 隔离性(Isolation): 多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
- 持久性 (Durability) : 已被提交的事务对数据库的修改应该被永久的保存在数据库中。
1.2 事务的隔离级别
首先有如下三个并发问题:
- 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
MySQL事务隔离级别如下所示:
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
2. Spring 中的事务
3 个 核心接口 :PlatformTransactionManager、TransactionStatus、TransactionDefinition。
2.1 PlatformTransactionManager
PlatformTransactionManager 平台事务管理器。Spring4中的源码如下所示:
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}
- TransactionStatus getTransaction(TransactionDefinition var1) throws TransactionException; 获取事务状态
- void commit(TransactionStatus var1) throws TransactionException; 提交事务
- void rollback(TransactionStatus var1) throws TransactionException; 回滚事务
2.2 TransactionDefinition
TransactionDefinition 事务定义对象,定义了事务规则和获取事务相关信息的方法。Spring4中的源码如下所示:
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();
}
- int getPropagationBehavior(); 获取事务的传播行为
- int getIsolationLevel(); 获取事务的隔离级别
- int getTimeout(); 获取事务的超时时间
- boolean isReadOnly(); 获取事务是否只读
- String getName(); 获取事务对象名称
在TransactionDefinition接口中定义了五个不同的事务隔离级别:
ISOLATION_DEFAULT | 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应 |
ISOLATION_READ_UNCOMMITTED | 这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读 |
ISOLATION_READ_COMMITTED | 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。 |
ISOLATION_REPEATABLE_READ | 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。 |
ISOLATION_SERIALIZABLE | 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。 |
事务的7种传播级别:
PROPAGATION_REQUIRED | 默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景。 |
PROPAGATION_SUPPORTS | 从字面意思就知道,supports,支持,该传播级别的特点是,如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。这个通常是用来处理那些并非原子性的非核心业务逻辑操作。应用场景较少。 |
PROPAGATION_MANDATORY | 该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。 |
PROPAGATION_REQUIRES_NEW | 从字面即可知道,new,每次都要一个新事务,该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
这是一个很有用的传播级别,举一个应用场景:现在有一个发送100个红包的操作,在发送之前,要做一些系统的初始化、验证、数据记录操作,然后发送100封红包,然后再记录发送日志,发送日志要求100%的准确,如果日志不准确,那么整个父事务逻辑需要回滚。
怎么处理整个业务需求呢?就是通过这个PROPAGATION_REQUIRES_NEW 级别的事务传播控制就可以完成。发送红包的子事务不会直接影响到父事务的提交和回滚。 |
PROPAGATION_NOT_SUPPORTED | 这个也可以从字面得知,not supported ,不支持,当前级别的特点就是上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务。 这个级别有什么好处?可以帮助你将事务极可能的缩小。我们知道一个事务越大,它存在的风险也就越多。所以在处理事务的过程中,要保证尽可能的缩小范围。比如一段代码,是每次逻辑操作都必须调用的,比如循环1000次的某个非核心业务逻辑操作。这样的代码如果包在事务中,势必造成事务太大,导致出现一些难以考虑周全的异常情况。所以这个事务这个级别的传播级别就派上用场了。用当前级别的事务模板抱起来就可以了。 |
PROPAGATION_NEVER | 该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!这个级别上辈子跟事务有仇。 |
PROPAGATION_NESTED | 字面也可知道,nested,嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。 |
2.3 TransactionStatus
TransactionStatus 事务的状态,他描述了某一时间点上事务的状态信息,Spring4中的源码如下所示。
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}
- boolean isNewTransaction(); 获取是否是新事务
- boolean hasSavepoint(); 获取事务是否存在保存点
- void setRollbackOnly(); 设置事务回滚
- boolean isRollbackOnly(); 获取是否回滚
- void flush(); 刷新事务
- boolean isCompleted(); 获取事务是否完成
4. Spring事务的实现
两种方法:传统的编程式事务 和 声明式事务。
编程式事务,通过编写代码实现事务,包括定义事务的开始,事务正常执行的提交和异常时事务的回滚。
声明式事务,使用 Spring 的 AOP 面向切面编程,又分为基于 xml 的声明式事务 和 使用注解的声明式事务。
参考文献:
- https://yq.aliyun.com/articles/48893
- JavaEE 企业级应用开发教程(Spring + SpringMVC + MyBatis)/ 黑马程序员编著. ——北京 :人民邮电出版社,2017.9 (2018.2 重印)
标签:事务管理,事务,int,Spring,PROPAGATION,boolean,级别,TransactionStatus From: https://blog.51cto.com/xuxiangyang/9038463