事务
异常
事务失效的原因
事务在某些情况下可能不会按预期那样工作,以下是一些常见的原因:
- 子线程中的事务不会生效
- 主线程中的事务对子线程是不可见的。
- 子线程可以访问主线程中已经存在于内存中的值,例如事务中生成的对象ID。
- 在子线程中尝试查询未提交事务中的数据可能会返回
null
,因为数据尚未被持久化到数据库中。
- 异常处理不当
- 如果业务代码中的异常被
try...catch
语句捕获,并且没有通过throw new RuntimeException
重新抛出,则事务不会回滚。 - 这种情况是最难发现的,也是最容易被忽略的。
- 错误的事务传播行为配置
- 使用
@Transactional(propagation = Propagation.NOT_SUPPORTED)
会导致事务不起作用。 - 这种配置通常不是预期的行为,因此很少被使用。
- 不支持事务的存储引擎
- 如果使用的MySQL存储引擎是MyISAM而不是InnoDB,则事务特性将不起作用。
- 非运行时异常
- 如果业务代码抛出的是
RuntimeException
之外的异常,而这些异常又不在@Transactional
的rollbackFor
属性中声明,则事务不会回滚。
- 事务配置缺失或不正确
- 比如未正确声明事务管理器或者
@Transactional
注解使用不当。
挂载事务提交之后处理
事务传播行为
事务传播行为描述了当一个事务方法调用另一个事务方法时,如何处理这些事务之间的关系。以下是几种不同的传播行为及其含义:
Propagation.REQUIRED
- 如果当前存在事务,则加入该事务;否则创建一个新的事务。
Propagation.SUPPORTS
- 如果当前存在事务,则加入该事务;否则以非事务的方式继续运行。
Propagation.MANDATORY
- 如果当前存在事务,则加入该事务;否则抛出异常。
Propagation.REQUIRES_NEW
- 创建一个新的事务,如果当前存在事务,则暂停当前的事务。
Propagation.NOT_SUPPORTED
- 以非事务的方式运行,如果当前存在事务,则暂停当前的事务。
Propagation.NEVER
- 以非事务的方式运行,如果当前存在事务,则抛出异常。
Propagation.NESTED
- 类似于
Propagation.REQUIRED
,但在支持嵌套事务的平台(如Hibernate)上,允许内部事务比外部事务更早地回滚。
事务的隔离级别
事务的隔离级别定义了事务之间数据的可见性和一致性。下面是四种主要的隔离级别,按照严格程度从高到低排列:
SERIALIZABLE
(序列化)- 所有事务依次执行,避免了所有并发问题,但也导致最低的并发性能。
REPEATABLE_READ
(可重复读)- 保证在一个事务中多次读取同一数据的结果相同,但不能防止“幻影读”。
READ_COMMITTED
(已提交读)- 可以读取其他事务提交的数据,但可能导致“不可重复读”。
READ_UNCOMMITTED
(未提交读)- 可以读取其他事务未提交的数据,可能导致“脏读”
Loading...