Spring 的事务一直是面试官经常询问的一个话题,但很多人只知道 @ Transactional 这个注解,但对 Spring 的事务体系,实现方式等方面却知之甚少,本文就将以图文结合的方式向读者介绍关于 Spring 事务。
题目
Spring 的事务了解吗?
推荐解析什么是事务?
事务是逻辑上的一组操作,要么都执行,要么都不执行。
在 MySQL 数据库中只有 InnoDB 引擎才支持事务。
事务的 ACID 特性
原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。
一致性(Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的。
隔离性(Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的。
持久性(Durability):一个事务被提交之后。它对数据库中数据的改变是持久的。
Spring 支持事务的两种方式
1)编程式事务:在代码中硬编码(不推荐使用) : 通过 TransactionTemplate 的 execute 或者 TransactionManager 的 commit 和 rollback 手动管理事务,实际应用中很少使用,但是对于你理解 Spring 事务管理原理有帮助。2)声明式事务:在 XML 配置文件中配置或者直接基于注解(推荐使用) : 实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)
事务属性介绍
事务属性包含了 5 个方面
1)隔离级别
2)传播行为
3)回滚规则
4)是否只读
5)事务超时
隔离级别
隔离级别默认和数据库是一致的,一般不需要进行改动。
package org.springframework.transaction;
import org.springframework.lang.Nullable;
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;
// 返回事务的传播行为,默认值为 REQUIRED。
int getPropagationBehavior();
//返回事务的隔离级别,默认值是 DEFAULT
int getIsolationLevel();
// 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
int getTimeout();
// 返回是否为只读事务,默认值为 false
boolean isReadOnly();
@Nullable
String getName();
}
传播行为
1)TransactionDefinition.PROPAGATION_REQUIRED
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
举个例子:
如果只要 A 或者 B 任意一个方法有异常,那么整个事务都会回滚。
@Service
Class A {
@Autowired
B b;
@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
b.bMethod();
}
}
@Service
Class B {
@Transactional(propagation = Propagation.REQUIRED)
public void bMethod {
}
}
2)TransactionDefinition.PROPAGATION_REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。
举个例子:
B 事务开启了独立的事务,如果 A 抛出异常回滚,B 不会回滚,但 B 如果抛出异常回滚,那么 A 会回滚。
@Service
Class A {
@Autowired
B b;
@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
b.bMethod();
}
}
@Service
Class B {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void bMethod {
}
}
3)TransactionDefinition.PROPAGATION_NESTED
如果当前存在事务,就在嵌套事务内执行;如果当前没有事务,就单独开启一个事务。
举个例子:
当 A 回滚,B 是嵌套事务,会跟着一起回滚。当 B 回滚,A 不会跟着回滚。
@Service
Class A {
@Autowired
B b;
@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
b.bMethod();
}
}
@Service
Class B {
@Transactional(propagation = Propagation.NESTED)
public void bMethod {
}
}
4)TransactionDefinition.PROPAGATION_MANDATORY
如果当前存在事务就加入该事务,如果当前没有事务,就抛出异常。
5)TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务的方式继续运行。
6)TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
7)TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
事务回滚规则
默认情况下,只有遇到运行时异常 RuntimeException 的子类才会回滚,Error 也会导致事务回滚。
可以指定要回滚的异常类型
@Transactional(rollbackFor= BusinessException.class)
介绍一下 @Transactional 的作用范围
1)方法(只对 Public 方法生效)
2)类(整个类的 Public 方法都生效)
3)接口(不推荐)
是否只读
readOnly,指定事务是否为只读事务,默认为 false。用来优化事务的执行,默认情况下每一个 SQL 放入单独的事务,事务要提交多次,如果声明了只读事务的话,数据库就会去优化它的执行。
事务超时
timeout 指定事务的超时时间,默认为-1(永远不会超时回滚),指定后超过时间会自动回滚。
注意事项:同类方法自调用会让 AOP 的代理模式失效。因此事务会失效。
其他补充
鱼聪明 AI 的回答:
鱼聪明 AI 地址:
事务的基本概念:
隔离级别(Isolation Levels):
传播行为(Propagation Behavior):
超时时间(Timeout):
回滚规则(Rollback Rules):
是否只读(Read-Only):
示例:
@Transactional(
isolation = Isolation.READ_COMMITTED,
propagation = Propagation.REQUIRED,
timeout = 30,
rollbackFor = {SQLException.class},
readOnly = true
)
public void myTransactionalMethod() {
// 事务处理逻辑
}
这是一个简单的例子,实际使用时根据具体情况选择合适的隔离级别、传播行为、超时时间、回滚规则和只读属性。
七种传播行为
创业/副业必备:
本站已持续更新1W+创业副业顶尖课程,涵盖多个领域。
点击查看详情
评论(0)