Spring中事务几个常见的问题解决

目录
  • 前言
  • Spring如何处理事务
    • 1、编程式事务,可以使用TransactionTemplate
    • 2、声明式事务
  • Spring事务传播机制
  • Spring事务隔离级别

前言

首先,事务这个概念是数据库层面的,Spring只是基于数据库中的事务进行扩展,以及提供了一些能让程序员更新方便操作事务的方式

Spring如何处理事务

Spring中支持编程式事务和声明式事务管理两种方式

1、编程式事务,可以使用TransactionTemplate

public class B {
    @Autowired
    private TransactionTemplate template;

    public void sout(){
        TransactionCallback<Integer> transactionCallback = new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus transactionStatus) {
                //jdbcTemplate.update
                //jdbcTemplate.update
                if(执行失败){
                    //回滚事务
                    transactionStatus.setRollbackOnly();
                    return -1;
                }
                return 1;
            }
        };

        Integer result =  template.execute(transactionCallback);
    }

当加了@Transactional注解后,Spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当在使用这个代理对象的方法时,如果这个方法上存在@Transactional注解,那么代理逻辑会先把事务的自动提交设置为false,然后再去执行原本的业务逻辑方法,如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务提交,如果执行业务逻辑方法出现了异常,那么会将事务进行回滚。

好处:代码级别的事务控制,可以自己控制事务的逻辑,比较灵活
缺点:太麻烦,需要自己实现所有的事务逻辑

2、声明式事务

是Spring在AOP基础上提供的事务实现机制。

public class B {
    @Autowired
    private TransactionTemplate template;

    @Transactional
    public void sout(){
  System.out.println("=================A=====================");
    }
}

优点:不需要在业务代码中添加事务管理的代码,只需要在配置文件中做相关的事务规则声明规则就可以了。
缺点:只能只能针对方法级别,无法控制代码级别。

Spring事务传播机制

Propagation:多个事务方法相互调用时,事务是如何在这些方法键传播

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

a调用b,以下描述,当前均只a,自己均指b

  • REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务。
  • SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
  • MANDATORY:当前存在事务,则加入当前事务,如果当前没有事务,则抛出异常
  • REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务(互不干扰)
  • NOT_SUPPORTED:以非事务方法执行,如果当前存在事务,则挂起当前事务。
  • NEVER:不使用事务,如果当前存在事务,则抛出异常
  • NESTED:如果当前存在事务,则嵌套事务中执行,否则REQUIRED操作一样(开启一个事务)

和REQUIRES_NEW的区别:
REQUIRES_NEW是新建一个事务,并且新开启的事务与原事务无关,而NESTED则是当前存在事务时(我们把当前事务成为父事务)会开启一个嵌套事务(称之为一个子事务)。在NESTED情况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW情况下,原有事务回滚,不会影响新开启的子事务。

和REQUIRED的区别:
REQUIRED情况下,调用方存在事务时,则被调用和调用方法使用同一事务,那么被调用方出现异常时,由于共用一个事务,所以无论调用方法是否catch异常,事务都会回滚(父子事务一起回滚),而在NESTED情况下,被调用方发生异常时,调用发可以catch其异常,这样只有子事务回滚,父事务不受影响(父事务是否需要回滚可以自行决定)

Spring事务隔离级别

  • ISOLATION:Spring的事务隔离级别
  • DEFAULT:使用数据库默认的事务隔离级别
  • READ_UNCOMMITTED:读未提交,允许事务在执行过程中,读取其他事务未提交的数据
  • READ_COMMITTED:读已提交,允许事务在执行过程中,读取其他事务已提交的数据
  • REPEATABLE_READ:可重复读,在同一个事务内,任意时刻的查询结果是一致的
  • SERIALIZABLE:所有事务依次执行

数据库配置的隔离级别是read commited,而spring配置的隔离级别是repeatable read,这个时候隔离级别以哪个为准?
以Spring为准(spring配置的会覆盖数据库的隔离级别),如果Spring配置的隔离级别数据库不支持,效果取决于数据库

到此这篇关于Spring中事务几个常见的问题解决的文章就介绍到这了,更多相关Spring事务 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringMVC中事务是否可以加在Controller层的问题

    目录 SpringMVC中事务是否可以加在Controller层 Spring在Controller层的事务操作 以下是代码 SpringMVC中事务是否可以加在Controller层 一般而言,事务都是加在Service层的,但是爱钻牛角尖的我时常想:事务加在Controller层可不可以. 我一直试图证明事务不止可以加在Service层,还可以加在Controller层,但是没有找到有力的论据来支持我这个想法,搞得我一度认为事务只能加在Service层,直到我读过spring官方文档并实践之

  • 详解Spring Boot微服务如何集成fescar解决分布式事务问题

    什么是fescar? 关于fescar的详细介绍,请参阅fescar wiki. 传统的2PC提交协议,会持有一个全局性的锁,所有局部事务预提交成功后一起提交,或有一个局部事务预提交失败后一起回滚,最后释放全局锁.锁持有的时间较长,会对并发造成较大的影响,死锁的风险也较高. fescar的创新之处在于,每个局部事务执行完立即提交,释放本地锁:它会去解析你代码中的sql,从数据库中获得事务提交前的事务资源即数据,存放到undo_log中,全局事务协调器在回滚的时候直接使用undo_log中的数据覆

  • Spring事务失效问题分析及解决方案

    这篇文章主要介绍了Spring事务失效问题分析及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 隔离级别 在 TransactionDefinition.java 接口中,定义了"四种"的隔离级别枚举: /** * [Spring 独有]使用后端数据库默认的隔离级别 * * MySQL 默认采用的 REPEATABLE_READ隔离级别 * Oracle 默认采用的 READ_COMMITTED隔离级别 */ int ISOL

  • 解决spring mvc 多数据源切换,不支持事务控制的问题

    一个项目中需要使用两个数据库,Oracle 和Mysql,于是参考各个blog,实现此功能.写好后才发现,原来的事务失效了,我去... spring-mybatis.xml 配置 <bean id="configReader" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"> <property name="location

  • Spring事务失效的一种原因关于this调用的问题

    PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务.如果没有事务则开启事务: PROPAGATION_REQUIRES_NEW:总是开启一个新的事务.如果一个事务已经存在,则将这个存在的事务挂起: 问题: Spring中一个没有事务的方法A调用一个默认事务(PROPAGATION_REQUIRED)的方法B时,如果使用this调用方法B,方法B抛出RuntimeException,此时方法B事务未生效,不会回滚. @Service public class Employ

  • JAVA Spring中让人头痛的JAVA大事务问题要如何解决你知道吗

    目录 前言 大事务引发的问题 解决办法 少用@Transactional注解 将查询(select)方法放到事务外 事务中避免远程调用 事务中避免一次性处理太多数据 非事务执行 总结 前言 最近有个网友问了我一个问题:系统中大事务问题要如何处理? 正好前段时间我在公司处理过这个问题,我们当时由于项目初期时间比较紧张,为了快速完成业务功能,忽略了系统部分性能问题.项目顺利上线后,专门抽了一个迭代的时间去解决大事务问题,目前已经优化完成,并且顺利上线.现给大家总结了一下,我们当时使用的一些解决办法,

  • 解决try-catch捕获异常信息后Spring事务失效的问题

    一.首先在Spring Boot项目中,手动添加异常方法进行测试 @Transactional(rollbackFor=Exception.class) //表示此方法有异常时触发Spring事务 @Override public CommonResult<User> saveUser(User user) { int insert = baseMapper.insert(user); try { // 添加异常,并进行捕获 int a = 10/0; }catch (Exception e)

  • 解决Spring或SpringBoot开启事务以后无法返回自增主键的问题

    Spring或SpringBoot开启事务以后无法返回自增主键 场景:保存订单和订单详情,订单详情需要订单id,数据库中的订单表是自增主键,开启事务后,导致订单主键无法返回 1.开启事务前(以下代码只是样例,实际可能无法运行) OrderMapper.xml配置 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapp

  • SpringBoot内部调用事务不起作用问题的解决方案

    在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景,大概的调用方式就如下面的代码这样. @Override @Transactional(rollbackFor = RuntimeException.class) public void insertUser(User user) { userMapper.insertUser(user); thr

  • Spring声明式事务和@Aspect的拦截顺序问题的解决

    在使用AbstractRoutingDataSource配置多数据源时,发现使用@aspect配置的DataSourceSwitchAspect总是在声明式事务之后执行,配置了Order依然不行,经过调研发现是由于两者的aop代理方式不一致导致. 在spring内部,是通过BeanPostProcessor(<spring 攻略>一书中翻译为,后处理器)来完成自动创建代理工作的.根据匹配规则的不同大致分为三种类别: 1.匹配Bean的名称自动创建匹配到的Bean的代理,实现类BeanNameA

随机推荐