spring和数据库事务相关知识总结

spring和数据库事务相关知识总结,第1张

前言:首先,事务这个概念是数据库层面的,数据库事务和spring事务本质上其实都是同一个概念,spring的事务是对数据库的事务的封装,最后本质的实现还是在数据库,假如数据库不支持事务的话,spring的事务是没有作用的。数据库的事务说简单就只有开启,回滚和关闭,spring对数据库事务的包装,原理就是拿一个数据连接,根据spring的事务配置, *** 作这个数据连接对数据库进行事务开启,回滚或关闭 *** 作。但是spring除了实现这些,还配合spring的传播行为对事务进行了更广泛的管理。其实这里还有个重要的点,那就是事务中涉及的隔离级别,以及spring如何对数据库的隔离级别进行封装。事务与隔离级别放在一起理解会更好些。

文章目录 一、spring事务的实现方式和原理以及隔离级别1、spring事务的实现方式2、spring事务隔离级别 二、spring事务传播机制三、spring事务什么时候会失效四、案例&注意点&大坑五、分布式事务

一、spring事务的实现方式和原理以及隔离级别 1、spring事务的实现方式

在使用Spring框架时,可以有两种使用事务的方式,一种是编程式的,一种是申明式的。

【1】- @Transactional注解就是申明式的。
比如我们可以通过在某个方法上增加@Transactional注解,就可以开启事务,这个方法中所有的sql都会在一个事务中执行,统一成功或失败。
在一个方法上加了@Transactional注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当在使用这个代理对象的方法时,如果这个方法上存在@Transactional注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法,如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务进行提交,如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚。
当然,针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的rollbackFor属性进行配置,默认情况下会对RuntimeException和Error进行回滚。
PS:这里可以结合编程使用:
方式一:

@Transactional(rollbackFor = Exception.class)
public R function() {
    try {
        // 业务代码
        ......
    } catch (Exception e) {
        // 手动回滚事务
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        return R.fail();
    }
    return R.suc();
}

方式二:

@Transactional(rollbackFor = Exception.class)
public R function() {
    try {
        // 业务代码
        ......
       // 设置事务回滚点
        Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
       // 业务代码
        ......
    } catch (Exception e) {
       // 手动回滚到savePoint事务点
        TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
        return R.fail();
    }
    return R.suc();
}

当然,自己设定回滚的条件也可以,即如果满足什么条件,就手动回滚事务。

【2】- 编程式可以手动创建、回滚和提交事务。
例如:
1.注入DataSourceTransactionManager

@Autowired
private DataSourceTransactionManager dataSourceTransactionManager;

2.手动开启事务

DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(defaultTransactionDefinition);

3.try catch业务代码

try{
    // 业务代码
   ......
    // 手动提交事务
    dataSourceTransactionManager.commit(transaction);
} catch {
    // 手动回滚事务
    dataSourceTransactionManager.rollback(transaction);
}

PS:如果A方法调用了B方法,想在A方法中开启事务,B方法中提交事务,那么可以将TransactionStatus transaction作为参数传递给B方法。

2、spring事务隔离级别

spring事务隔离级别就是数据库的隔离级别:外加一个默认级别

read uncommitted(未提交读)read committed(提交读、不可重复读)repeatable read(可重复读)serializable(可串行化)

相关知识:
【数据库】数据库中事务的隔离级别(读未提交、读已提交、重复读、可串行化)
【数据库】幻读与不可重复读

数据库的配置隔离级别是Read Commited,而Spring配置的隔离级别是Repeatable Read,请问这时隔离 级别是以哪一个为准?
以Spring配置的为准,如果spring设置的隔离级别数据库不支持,效果取决于数据库。

二、spring事务传播机制

多个事务方法相互调用时,事务如何在这些方法间传播?

方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。

REQUIRED(Spring默认的事务传播类型):如果(B)当前没有事务,则自己新建一个事务,如果当前存在事务,则加入(A)这个事务。

其它作为了解吧:
SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行。
MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务。
NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务
NEVER:不使用事务,如果当前事务存在,则抛出异常
NESTED:如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的 *** 作一样(开启一个事务)

三、spring事务什么时候会失效

spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不起作用了!常见情况有如下几种:

发生自调用,类里面使用this调用本类的方法(this通常省略),此时这个this对象不是代理类,而
是UserService对象本身!
解决方法很简单,让那个this变成UserService的代理类即可!方法不是public的:@Transactional 只能用于 public 的方法上,否则事务不会失效,如果要用在非 public 方法上,可 以开启 AspectJ 代理模式。数据库不支持事务。没有被spring管理。异常被吃掉,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)。 四、案例&注意点&大坑

如果一个方法使用@Transactional开启了事务,方法的业务中修改了A表,接着方法又调用异步服务修改A表,则会发生死锁问题。
原因:事务先给A表上了表锁,紧接着执行的异步方法是新开的线程,无法加入到主线程的事务中,所以需要释放了A表的锁才能够修改A表,而因为整个方法未执行完,事务未提交,所以就释放不了锁,最后造成死锁问题。
解决方法:去掉@Transactional,使用编程方法,手动添加、回滚和提交事务(在开启异步服务前就将事务提交)。
这个问题涉及到事务的原理,可以回看前言或前面的内容。

如果业务中修改了A表,然后调用其它异步服务,其它异步服务修改了B表,若这个异步服务出现异常,A表仍然会被修改,不会受其它异步服务影响。若不是异步服务,是同步的话,则受事务影响,即其它服务出现异常,AB表都不会被修改。(以上说的服务都是属于同一个微服务中,若是涉及到远程调用其它微服务,则属于分布式事务,以上讨论的是本地事务。)

五、分布式事务

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/2990086.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-23
下一篇 2022-09-23

发表评论

登录后才能评论

评论列表(0条)

保存