关于理论性的内容,我在之前的一篇文章中介绍过,这里不再过多阐述,这里给出之前文章的链接:Spring 事务管理
是一组逻辑操作,要么执行,要么不执行。
ACID
(原子性、一致性、隔离性、持久性)
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
PlatformTransactionManager
:(平台)事务管理器TransactionDefinition
: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)TransactionStatus
: 事务运行状态该接口主要有三个方法:
Public interface PlatformTransactionManager()...{
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
Void commit(TransactionStatus status) throws TransactionException;
Void rollback(TransactionStatus status) throws TransactionException;
}
getTransaction
:根据指定的传播行为,返回当前活动的事务或创建一个新事务commit
:使用事务目前的状态提交事务rollback
:对执行的事务进行回滚一般情况下用的比较多的就是 commit
提交事务和 rollback
回滚事操作了。
该接口主要定义了一些表示事务属性(如隔离级别,传播行为等)的常量。当然还有一些方法,仅有篇幅,不对方法做介绍。
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT
: 使用后端数据库默认的隔离级别。Mysql 默认采用 REPEATALBE-READ
隔离级别;Oracle 默认采用 READ_COMMITTED
隔离级别。TransactionDefinition.ISOLATION_READ_UNCOMMITTED
:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。TransactionDefinition.ISOLATION_READ_COMMITTED
:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。TransactionDefinition.ISOLATION_REPEATABLE_READ
:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。TransactionDefinition.ISOLATION_SERIALIZABLE
:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRED
:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。TransactionDefinition.PROPAGATION_SUPPORTS
:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。TransactionDefinition.PROPAGATION_MANDATORY
: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)不支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRES_NEW
:创建一个新的事务,如果当前存在事务,则把当前事务挂起。TransactionDefinition.PROPAGATION_NOT_SUPPORTED
: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。TransactionDefinition.PROPAGATION_NEVER
:以非事务方式运行,如果当前存在事务,则抛出异常。其他情况:
TransactionDefinition.PROPAGATION_NESTED
:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED
。TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。
TransactionStatus 接口方法如下:
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
事务操作一般都是在 service 层编写,结合增删改查方法。我举个栗子:
class Test {
private PlatformTransactionManager transactionManager;
public void saveFromDB() {
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);
try {
// 增删改查操作(使用 dao 中的方法)
//...
transactionManager.commit(transactionStatus);
// 删除本地缓存操作
//...
} catch (Exception e) {
transactionManager.rollback(transactionStatus);
}
}
}
这里需要注意的是:当我们执行增删查改操作时,应该在 service 层添加事务,并且删除之前的缓存(本地缓存和 redis 缓存),然后再执行增删查改操作,这三方面都兼顾到了才是一个比较好的增删查改操作。
https://juejin.im/post/5b00c52ef265da0b95276091
原文:https://www.cnblogs.com/weixuqin/p/11374069.html