事务失效隔离传播

编程入门 行业动态 更新时间:2024-10-09 16:23:13

<a href=https://www.elefans.com/category/jswz/34/1770772.html style=事务失效隔离传播"/>

事务失效隔离传播

1.未指定回滚异常
@Transactional注解默认的回滚异常类型是运行时异常(RuntimeException),
如果我们自定义了一个异常直接继承了Exception,代码如下:
public class CustomException extends Exception{}
所以我们需要在@Transactional指定回滚异常的类型,遇到异常就要回滚:
@Transactional(rollbackFor = Exception.class)

2.try-catch异常被捕获
当抛出的异常被try-catch捕获时,事务也会失效,具体看代码:
@Transactional(rollbackFor = Exception.class)
public void insert(){
try {

}catch (Exception e){
e.printStackTrace();
}
}

我们也可以修改catch包裹的代码,以此来达到回滚的目的。
throws CustomException。
或者
}catch (Exception e){
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}

3.方法内部直接调用
在Spring的Aop代理下,只有目标方法在外部进行调用,目标方法才会由Spring生成的代理对象来进行管理,
如果是其他不包含@Transactional注解的方法中调用包含@Transactional注解的方法时候,
有@Transactional注解的方法的事务会被忽略,则不会发生回滚。

public void insert() throws CustomException {
doSomething();
}

@Transactional(rollbackFor = Exception.class)
public void doSomething() throws CustomException {}

4.异步多线程
这里我撰写了一个新的myService2用于保存history对象,并在myService2的方法上加上了@Async的注解,并休眠了5s。
注:主启动类需要加上@EnableAsync
@Async
public void save(Notice notice) throws CustomException, InterruptedException {}

@Transactional(rollbackFor = Exception.class)
public void insert() throws CustomException, InterruptedException {}

这是因为@Async注解使用的是独立线程和独立的事务,和notice的不处于同一个事务当中,所以notice回滚了,但是history入库了。
同一个事务:公用的同一个数据库链接。
对于这种失效的场景,将 @Transactional和@Async绑定在一起进行使用,事务才是生效的,请看如下代码:

@Transactional(rollbackFor = Exception.class)
@Async
public void insert() throws CustomException, InterruptedException {}

5.使用了错误的事务传播机制
先简单介绍一下Spring事务的7种传播机制:
PROPAGATION_MANDATORY 必须运行在已存在的事务中,否则抛出异常
PROPAGATION_SUPPORTS 如果当前存在事务,则加入该事务;如果没有事务,则以非事务方式继续运行
PROPAGATION_REQUIRED 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
PROPAGATION_REQUIRES_NEW 创建一个新事务,如果已经存在一个事务,则把当前事务挂起,新事务提交不影响老事务回滚
PROPAGATION_NESTED 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则等同于PROPAGATION_REQUIRED
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果当前存在事务,则把当前事务挂起
PROPAGATION_NEVER 以非事务方式运行,如果当前存在事务,则抛出异常。
课补事务隔离级别
根据 SQL 标准,定义了四种隔离级别,从低到高分别为:
读未提交(Read Uncommitted)
读已提交(Read Committed)oracle
可重复读(Repeatable Read) mysql
串行化(Serializable)。
不同的隔离级别对应着不同的并发访问问题和性能影响。
不同隔离级别的定义与特点
读未提交(Read Uncommitted)
读未提交是最低的隔离级别,一个事务可以看到其他事务尚未提交的修改。这种隔离级别可能导致脏读(Dirty Read,
一个事务读到另一个事务未提交的数据)问题。性能较高,但并发安全性较差。

读已提交(Read Committed)
读已提交是一种较为常用的隔离级别,一个事务只能看到其他事务已经提交的修改。这种隔离级别可以避免脏读问题,
但仍可能发生不可重复读(Non-repeatable Read,一个事务在多次读取同一数据时,发现数据被其他事务修改并提交)问题。
性能较好,适用于大多数场景。

可重复读(Repeatable Read)
可重复读是一种较高的隔离级别,一个事务可以多次读取同一数据并获得相同的结果,即使其他事务已经修改并提交了数据。
这种隔离级别可以避免脏读和不可重复读问题,但仍可能发生幻读(Phantom Read,一个事务在多次读取同一范围的数据时,
发现其他事务插入了新的数据)问题。性能较低,但并发安全性较好。

串行化(Serializable)
串行化是最高的隔离级别,事务被强制按顺序执行,完全避免了脏读、不可重复读和幻读问题。然而,这种隔离级别的性能最差,
因为它限制了事务的并发执行。在高并发场景下,这可能导致性能瓶颈。

如何选择合适的隔离级别

在实际业务中,选择合适的事务隔离级别需要权衡数据一致性和性能之间的关系。以下是一些建议:

如果数据一致性要求较低,可以选择读未提交或读已提交隔离级别。这两种隔离级别的性能较好,但可能存在脏读和不可重复读问题。

如果数据一致性要求较高,可以选择可重复读或串行化隔离级别。这两种隔离级别可以避免脏读、不可重复读和幻读问题,但性能较低。

在大多数场景下,读已提交是一个较为合适的选择,因为它提供了较好的性能和一定程度的数据一致性保障。对于特定的业务场景,可以根据实际需求调整隔离级别。

6.方法被private或者final修饰
这种情况下,事务也是会失效的。

@Transactional(rollbackFor = Exception.class)
private void insert() throws CustomException {}

@Transactional(rollbackFor = Exception.class)
public final void insert() throws CustomException {}

7.当前类没有被Spring容器托管

8.数据库不支持事务

更多推荐

事务失效隔离传播

本文发布于:2023-11-15 09:29:02,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1597435.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:事务

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!