springboot注解事务(SpringBoot 之@Transactional事务回滚)
本文目录
- SpringBoot 之@Transactional事务回滚
- 如何关闭springboot事务支持
- springservice层不加注解默认有事务吗
- SpringBoot进阶之事务管理及并发问题
- Spring Boot中Service用@Transactional 注解在方法上,只在最外层方法起作用吗
- springboot 的事务与锁
- SpringBoot如何注解事务声明式事务
- Spring Boot 项目中配置多数据源@Transactional注解失效问题
- springboot 手动开启事务以及手动提交事务
- springmvc不使用xml的transaction配置
SpringBoot 之@Transactional事务回滚
在开发过程中,经常会出现一个接口多表插入的情况,当其中一张表插入失败时就需要进行事务回滚了,SpringBoot为我们提供了@Transactional注解来进行事务回滚
1.需要将使用事务注解的方法设置为public;
2.如果没有在注解后做异常配置,只会对手动抛出的 throw new RuntimeException() 起作用;
3.若想对其余异常起作用,则需做类似配置 @Transactional(rollbackFor= Exception.class) ;
如果异常被抓起之后,需要回滚只能手动回滚,否则事务会认为异常已经被处理,就不在进行回滚
在使用注解后,在需要执行事务回滚的地方,很多时候往往抛出异常进行回滚后无法return或者做一些其余的逻辑,那么这种情况使用手动事务回滚是非常不错的。
如何关闭springboot事务支持
关闭springboot事务支持通过Rest接口,SpringApplication的exit静态方法,JMX,使用第三方进程管理工具。Rest接口:使用spring-boot-starter-actuator模块里的ShutdownEndpoint,SpringApplication的exit静态方法:直接调用该静态方法即可,JMX:使用SpringBoot内部提供的MXBean,使用第三方进程管理工具。
springservice层不加注解默认有事务吗
springservice层不加注解默认有事务。只是默认单条sql一个事务,如果我们在Service层的方法上加Transaction注解,那么事务的范围就会扩大,包含在service方法执行的所有sql。Mysql默认的隔离级别是可以防止不可重复读的,所以,加上Transactional,里面如果涉及多次查询一条记录,中间即使被其它事务修改,这条记录还是一样的。这和是否加readOnly没有关系,加了只会告诉数据库底层驱动,达到一个好的效率,仅此而已。但如果不加Transactional,那么每条sql一个事务,中间被其它事务改了数据,都会实时读取到最新值。
SpringBoot进阶之事务管理及并发问题
大家好,一直以来我都本着用最通俗的话理解核心的知识点, 我认为所有的难点都离不开 「基础知识」 的铺垫。目前正在出一个 SpringBoot 长期系列教程,从入门到进阶, 篇幅会较多~
「大佬可以绕过 ~」
如果你是一路看过来的,很高兴你能够耐心看完。之前带大家学了 Springboot 基础部分,对基本的使用有了初步的认识, 接下来的几期内容将会带大家进阶使用,会先讲解基础 中间件 的使用和一些场景的应用,或许这些技术你听说过,没看过也没关系,我会带大家一步一步的入门,耐心看完你一定会有 收获 ~
上期带大家学习了 SpringBoot 中如何去拦截请求, 本期将带大家学习 MyBatis 中如何进行 事务管理 ,同样的,我们集成到 Springboot 中。最近github可能会被墙,所以我把源码放到了国内gitee上,本节我们依然使用上期的代码
我们先了解一下它的基本概念。其实 事务 它不仅是在这里我们提到的 mybatis ,其实它在数据库中也是存在的。 事务 我们从字面意思理解,它好比烤面包,经过一些列的步骤之后,最终提供给客户完整的面包,也就是说中间出现差错,就得回退。可能举这个例子不大合适,再举一个我们业务中的场景吧。用户购买一个商品,首先下单,下完单之后进行支付,支付成功后订单为支付成功状态,跳转成功页,这一系列操作就是一个事务,要么成功要么失败。
在通过上面的例子有了大概了解之后,我们再看看它的基本概念。
下面带大家看看 sql 如何执行事务操作。下面举个例子比较一下
没有事务操作的时候:
以之前的场景给大家举例, 用户支付减少余额 并改订单状态为成功。 当我们的程序执行了上边的两条 sql ,大家觉得有问题吗?这肯定得出事,这不得被人薅死。虽然语句没报错,但是逻辑错了,为啥 因为余额变成负数了,这不是没钱白嫖,还指望用户给你冲上吗。然后订单还给成功了,如果遇到并发大的时候,这得多少钱,发还是不发货呢?告诉用户系统问题?老板看了得哭死。
所以不管是程序上的错误(sql执行错误),还是逻辑上的错误都不能进行下一步操作,所以事务显的尤为重要。那么 sql 怎么提交事务呢?
上边只是给大家举个例子,生成中我们还得用 mybatis **作。
在 SpringBoot 中执行事务非常简单,首先要开启事务 @EnableTransactionManagement ,在启动类上加上:
添加***方法:
我们访问 ***隐藏网址*** , 发现数据库并没有产生新纪录和更新记录, @Transactional(rollbackFor = Exception.class) 表示开启一个事务,当捕获到 Exception 异常就进行回滚。把 name 换掉会发现,执行成功了。
执行失败的时候:
那有没有 手动 去执行回滚操作的呢?有时候,我们总不能靠异常来判断,需要通过逻辑判断:
上边的方法 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 就是干这个的。
其实本节到这里差不多就结束了,给大家多讲一点, 其实这一块内容理论知识点还是比较多多的,这也是面试比较喜欢问的,因为这里真就靠大家自己去理解和学习了,写代码谁都会,但是讲出来,不一定每个人都讲的好和清楚,因为每个人的理解和认知不一样。
有时候,客户反馈有 bug ,反馈到你这边,你可能会说,我这都是好的。因为我们是本地的,不是跑在线上的,本地就你自己完,所以觉得没啥问题。但线上是很多用户在使用,当多用户使用的时候就会产生并发问题,所以也就是在接口测试的时候为什么要进行一下测试环境的压测,合格后上线。
那么在并发大的时候,我们数据库可能会产生什么问题呢?
好,我们一个一个讲,首先说说什么是丢失更新?
一个事务覆盖另一个事务已提交的更新数据叫丢失更新。这里提到过它存在两种丢失情况,为了让大家能够更加直观的感受,我以存钱和取钱为例讲一下。
首先说说第一种丢失情况
先分配一下角色,事务A,事务B,账户C。 首先A对C进行账户查询,余额为5000,B对A查询,余额为5000,此时余额一样没啥问题。紧接着B对C进行存钱操作,存了1000, 存完B提交事务。而此时A呢,正对着C进行取钱,取了1000, 它也提交了事务。那么问一下大家, C还有多少钱?
最后A查了一下账户,发现只有4000, 发现少了1000。
下边我们把压力给到A这边,第二种其实跟上边是反过来,情况是怎么样的呢?首先A,B跟之前一样,查了下C,余额为5000。此时,A对C进行取钱操作,取了1000,然后提交事务,B呢对A进行存钱操作,存了1000,提交事务。最后B一查,发现账户有6000, C开心极了, 多了1000
上边这两种情况都属于丢失更新的情况
一个事务读取到另一个事务还没提交的数据叫脏读。我们还以上边的为例:
这个稍微好理解一点,事务A和B, 事务A对C进行取钱操作,取了1000, 余额还剩 4000, 此时B呢对C进行查询操作,读到余额为4000。这时产生问题了,因为A现在还是一个未提交的事务,A对账户C取钱操作进行了 回滚 , 紧接着存了1000, 然后进行了 事务提交 , 此时余额为6000。而我们的B读到的数据是4000,所以这就是 脏读
一个事务先后读到另一个事务提交之前的数据和已提交的更新数据。同样的以上边为例,这个大家可能不好理解,下面好好分析一下:
首先事务A和B, A先查询C余额还有 5000, B 查询C,余额还有5000, 紧接着A对C执行取钱操作,取了1000, 提交事务, 此时B执行查询操作,发现C只有4000了。你可能想,这没问题啊,取了1000还有4000,没毛病啊。没问题吗?重复读了两次,结果不一致,这肯定是有问题的。
事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据。这有点抽象,同样的,还以上边为例
事务A和B,B查询C,余额5000, A注销了C,提交了事务,此时B又去查询C, 发现C没了,B事务查询两次,结果确不一致,跟产生了幻觉一样,刚刚还在的,这会没了。
通过上边的几个例子,带大家认识了,并发中可能产生的事务问题,下边给大家总结一下事务的特点, 事务有4个特性,被称为 ACID
下边就给大家讲讲这几个特性:
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
在事务开始之前和事务结束以后,数据库的完整性没有被破坏
一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成
隔离级别就不给大家讲了,这不是本节的重点内容。本节的重点是大家要学会在 SpringBoot 中如何去执行 事务操作 ,如果你对上边提到的一些概念性的东西还不能理解,也没关系,等以后回过头来看看也许就明白了,做个简单的了解。
有时候我们的系统需要对用户进行区分,也就是不同的用户角色访问不同的资源,比如管理员可以访问后台,而普通用户只能访问前台的页面,再或者只有登录的用户才能访问特定功能,高级管理员可以掌管大局,普通的管理员只能查看某一个菜单。这就是涉及到权限问题了,几乎所有的系统都需要权限管理,这样能保证系统资源的安全性。下期将会带大家学习 Shiro权限 框架, 它是一个轻量级框架,但它的功能确不小, 我会从入门到进阶讲起, 会分为多期去讲。
下期见,关注我,不迷路~
Spring Boot中Service用@Transactional 注解在方法上,只在最外层方法起作用吗
一般来说function2和function1用的是同一个Transaction。
这个取决于@Transactional 的 propagation设置(事务的传播性)
默认的是
@Transactional(propagation=propagation.REQUIRED)
也就是使用同一个Transaction。也可以按需求设置成 NESTED 或者 REQUIRES_NEW。
//in A.java
Class A {
@Transactional(propagation=propagation.REQUIRED)
public void aMethod {
B b = new B();
b.bMethod();
}
}
//in B.java
Class B {
@Transactional(propagation=propagation.REQUIRED)
public void bMethod { //something }
}在上面这个例子中,传播性被设为了REQUIRED,注意,这是默认值,也即不进行该参数配置等于配置成REQUIRED。
REQUIRED的含义是,支持当前已经存在的事务,如果还没有事务,就创建一个新事务。在上面这个例子中,假设调用aMethod前不存在任何事
务,那么执行aMethod时会自动开启一个事务,而由aMethod调用bMethod时,由于事务已经存在,因此会使用已经存在的事务(也就是执行
aMethod之前创建的那个事务)。
对于这样的配置,如果bMethod过程中发生异常需要回滚,那么aMethod中所进行的所有数据库操作也将同时被回滚,因为这两个方法使用了同一个事务。
MANDATORY的含义是,支持当前已经存在的事务,如果还没有事务,就抛出一个异常。如果上例中aMethod的传播性配置为
MANDATORY,我们就无法在没有事务的情况下调用aMethod,因此,传播性为MANDATORY的方法必定是一个其他事务的子事务,当逻辑上独
立存在没有意义或者可能违反数据、事务完整性的时候,就可以考虑设置这样的传播性设置。
NESTED的含义是,在当前事务中创建一个嵌套事务,如果还没有事务,那么就简单地创建一个新事务。
REQUIRES_NEW的含义是,挂起当前事务,创建一个新事务,如果还没有事务,就简单地创建一个新事务。
请注意以上两者的区别,大多数情况下一上两种传播性行为是类似的,不过在事务回滚的问题上,以上两者有很大的区别。
首先,REQUIRES_NEW会创建一个与原事务无关的新事务,尽管是由一个事务调用了另一个事务,但却没有父子关系。
如果bMethod的传播性是REQUIRES_NEW,而抛出了一个异常,则bMethod一定会被回滚,而如果aMethod捕获并处理了这个
bMethod抛出的异常,那么aMethod仍有可能成功提交。当然,如果aMethod没有处理这个异常,那么aMethod也会被回滚。
如果aMethod在bMethod完成后出现了异常,那么bMethod已经提交而无法回滚,只有aMethod被回滚了。
而对于NESTED,虽然也会创建一个新事务,但是这个事务与调用者是有父子关系的相互依存的。
如果bMethod的传播性是NESTED,而抛出了一个异常,事务的回滚行为与REQUIRES_NEW是一致的。
但是如果aMethod在bMethod完成后出现了异常,bMethod同样也会被回滚。因为事实上,EJB中没有对于NESTED传播性的类似实现,NESTED并不是真正启动了一个事务,而是开启了一个新的savepoint。
NEVER的含义很简单,就是强制要求不在事务中运行,如果当前存在一个事务,则抛出异常,因此如果bMethod传播性是NEVER,则一定抛出异常。
NOT_SUPPORTED的含义是,强制不在事务中运行,如果当前存在一个事务,则挂起该事务。
SUPPORTS的含义是,支持当前事务,如果没有事务那么就不在事务中运行。SUPPORTS传播性的逻辑含义比较模糊,因此一般是不推荐使用的。
springboot 的事务与锁
最近有一个需求,需要在事务的基础上增加锁,实现同步,过程中使用到了springboot的注解和synchronized,但是结果是同步成功,事务失败了
执行结果如下:
这里是一个坑,由于在方法的外层加的事务,所以需要整个方法执行完才会提交,但是多线程情况下,第二次查找,很多情况下会查不到,因为第一次拿到锁的事务还没有提交
SpringBoot如何注解事务声明式事务
springboot的事务也主要分为两大类,
一是xml声明式事务,
二是注解事务,注解事务也可以实现类似声明式事务的方法,
springboot 之 xml事务
使用 @ImportResource("classpath:transaction.xml") 引入该xml的配置
springboot 注解事务
Transactional注解事务
注:需要在进行事物管理的方法上添加注解@Transactional,或者偷懒的话直接在类上面添加该注解
注解声明式事务
@Configuration
public class TxConfigBeanName {
@Autowired
private DataSourceTransactionManager transactionManager;
// 创建事务通知
@Bean(name = "txAdvice")
public TransactionInterceptor getAdvisor() throws Exception {
Properties properties = new Properties();
properties.setProperty("get*", "PROPAGATION_REQUIRED,-Exception,readOnly");
properties.setProperty("add*", "PROPAGATION_REQUIRED,-Exception,readOnly");
properties.setProperty("save*", "PROPAGATION_REQUIRED,-Exception,readOnly");
properties.setProperty("update*", "PROPAGATION_REQUIRED,-Exception,readOnly");
properties.setProperty("delete*", "PROPAGATION_REQUIRED,-Exception,readOnly");
TransactionInterceptor tsi = new TransactionInterceptor(transactionManager,properties);
return tsi;
}
@Bean
public BeanNameAutoProxyCreator txProxy() {
BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
creator.setInterceptorNames("txAdvice");
creator.setBeanNames("*Service", "*ServiceImpl");
creator.setProxyTargetClass(true);
return creator;
}
}
Spring Boot 项目中配置多数据源@Transactional注解失效问题
当一个Spring Boot 项目在配置了多个数据源 , 在编写 Service层方法 的时候 , 直接在service方法的上添加的 @Transactional 直接实现事务管理的方式是失效的 .
以最近接触到的一个持久层框架使用的是Jpa的项目为例 , 该项目通过硬编码(配置类)的方式 , 在项目中配置了两个不同的数据源 , 所以这个项目分别根据两个数据源配置了各自的事务管理器 PlatformTransactionManager , 如下 :
第一个数据源的事务管理器配置类 :
第二个数据源事务管理器配置类 :
可以看到第二个事务管理器的Bean方法上添加了 @Primary 注解 , 所以在通过 PlatformTransactionManager 类型注入事务管理器的bean时 , 默认是根据类型去注入 , 如果该类型有多个 Bean , 如不通过bean的名字去注入 , 则默认是会注入被 @Primary 标识的bean的 ;
所以在这个项目中 , 当在业务层方法添加 @Transactional 注解时 , 默认是调用了 transactionManagerTwo 这个bean , 而我在编写service层的方法时 , 调用的是第一个数据源对应的Dao层方法 , 所以直接添加 @Transactional 是不能实现事务管理的 ,
需要在使用 @Transactional 注解时指定使用的事务管理器的bean的名字 , 比如我这里调用的是第一个数据源的dao层方法 , 所以需要指定对应的事务管理器 : @Transactional(transactionManager = "transactionManagerOne") .
springboot 手动开启事务以及手动提交事务
添加依赖,sprongboot 会默认开启事务管理
org.springframework.boot
spring-boot-starter-jdbc
在需要的服务类里添加注解
springmvc不使用xml的transaction配置
在SpringMVC中,我们可以使用注解的方式配置事务,从而避免使用XML进行配置。具体步骤如下:
1. 首先,在SpringMVC的配置类中加入@EnableTransactionManagement注解,开启事务支持。
2. 在需要进行事务管理的方法上,使用@Transactional注解,标注该方法需要进行事务管理。同时,可以在注解中指定事务管理的属性,如事务传播属性、隔离级别、超时时间等等。
3. 在SpringMVC的配置类中,需要配置一个事务管理器。可以使用Spring提供的DataSourceTransactionManager或者Hibernate的HibernateTransactionManager。在配置事务管理器时,需要指定数据源和事务管理属性。
4. 如果需要在同一事务中进行多个数据库操作,可以将多个操作放在同一个方法中,并使用@Transactional注解进行标注。这样,在方法执行时,就会自动开启一个事务,并将多个操作放在同一个事务中进行。
使用注解配置事务可以简化配置过程,减少代码量,提高开发效率。同时,也可以使代码更加清晰易懂,便于维护。不过,在使用注解配置事务时,需要注意事务的传播属性和隔离级别,避免出现事务管理的问题。
更多文章:
stackoverflow异常(电脑出现 “stack overflow at line 1” 如何解决求解)
2026年4月3日 19:20
recordset属性(vb中 recordset如何使用和理解)
2026年4月3日 19:00
bochs上面运行电脑时显示的no boot table device是什么意思?bochs配置文件在哪下载
2026年4月3日 18:40
sql for循环语句(如何写**L循环语句,更新多个表.)
2026年4月3日 18:20
php中session的用法(PHP session干嘛用的举个简单易懂的例子)
2026年4月3日 18:00
springboot注解事务(SpringBoot 之@Transactional事务回滚)
2026年4月3日 17:40
class文件是什么文件(J**A中.class文件是什么意思有什么用吗)
2026年4月3日 17:00
keygen并行配置不正确(应用程序无法启动,因为应用程序的并行配置不正确)
2026年4月3日 16:40




