SpringBoot中@Transiactional注解没有效果的解决

网友投稿 380 2022-10-04


SpringBoot中@Transiactional注解没有效果的解决

目录SpringBoot @Transiactional注解没有效果背景问题解决SpringBoot 使用Transaction注解遇到的坑一、场景二、Spring中使用的使用方式三、使用中遇到的问题1、使用Transaction注解时抛出异常但是事务不起作用,异常时事务没有进行回滚?2、刚插入的数据,无法马上查询到?总结:

SpringBoot @Transiactional注解没有效果

背景

数据库为mysql

问题

使用SpringBoot操作数据库插入两条数据,service层的方法出现了异常,按理说两条数据都该插不进去的,可以数据库中却还是有一条数据。

数据库表格式:

service层代码:

package com.example.demo.service;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.example.demo.domain.Girl;

import com.example.demo.repository.GirlRepository;

@Service

public class GirlService {

@Autowired

private GirlRepository girlRepository;

@Transactional

public void transiactionTest() {

Girl g1 = new Girl();

g1.setAge(33);

g1.setCupSize("B");

girlRepository.save(g1);

Girl g2 = new Girl();

g2.setAge(33);

g2.setCupSize("FFFFF"); // 长度和数据库的长度不符,会出异常

girlRepository.save(g2);

}

}

启动SpringBoot后,访问对应的方法,控制台也报错,但是表中是有一条数据的(原本是空表)。

查了查资料说的是在设计表的时候要选取的InnoDB引擎。

回头看我的表引擎:

还真的是。。。。。。

解决

将数据表的引擎设置为InnoDB引擎。 然后再次执行,@Transitional注解才起了作用,数据表中没有了数据。

SpringBoot 使用Transaction注解遇到的坑

一、场景

开发一个多批次入库的功能,功能中涉及到多个表间的操作,对数据库表的操作要么同时成功,要么同时失败,不然就会存在脏数据,所以使用到了事务这个知识点()。

划重点:重要的都使用红色标出来了,大家如果不想看我废话,直接跳到红色字体即可0...0

二、Spring中使用的使用方式

1、使用传统的手动开始,手动提交事务即:beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。

2、使用Transaction注解的声明式事务,将事务的开启和提交交给Spring容器完成,这个也是本次我使用的方式,简单,但是使用时需要注意很多细节。

3、基于Spring AOP的切面的事务配置(本人很少使用这个,所以本文不重点刨析该知识点,想了解的可以到其他博客进行查看)

三、使用中遇到的问题

1、使用Transaction注解时抛出异常但是事务不起作用,异常时事务没有进行回滚?

答:经过排查,查询在开启事务的方法中最外层使用了try...catch进行了异常的捕获,因此抛出的异常本捕获了,切面无法捕获到异常,所以不会进行回滚。

解决:

(1) 手动指定切面捕获的异常类型(因为默认情况下只会在RuntimeExceptionimeException情况下才会进行事务的回滚),方式:@Transaction(rollbcackFor=Exception.class)

(2) 在catch中手动抛出一个运行时异常即:throw new RuntimeException();

(3) 如果需要在事务回滚时,给调用当前方法的调用者返回错误信息的话,用第二种方案就是不行的,因为抛出异常后的语句时不会执行的,包括return后面的语句,所以,此时可以手动进行事务回滚的语句调用即:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

2、刚插入的数据,无法马上查询到?

答: 这个问题是个大坑,整整苦恼了我两天(可能是之前使用事务相关的知识比较少,所以遇到了根本就不知道是什么原因),因为项目中使用的是MybatisPlus框架,一开始便怀疑是框架的缓存问题,因为刚插入马上查询时,查询的SQL语句并没有执行,即根本没到数据库去查,但是,手动关闭了缓存之后并没起效果,最后大佬看了代码后,一眼就指出问题所在(现在不得不感慨,经验时多么重要)。

要解决这个问题,首先要知道使用Transaction是怎么进行事务增强的,说白了,是通过生成代理对象进行切面注入的,当前对象并没有增强的作用,刚开始我插入和查询的方法都是写在一个service中,然后使用this调用这些方法,而this表示的是当前的service对象,所以这些方法根本就不在当前的事务中,因为刚插入的数据无法马上查询到0....0(我踩的大坑希望大家不要再踩了,太难受了..)

解决方法:说了这么多废话,现在知道问题产生的原因,所以就好解决了:

(1) 将所有的数据库操作方法抽取到另外一个Service对象中,然后通过@Autowire注入调用即可。

(2)DLdBG 自己注入自己的对象即当前Service为A,可以直接使用:@Autowire private A a; 然后通过a调用相关数据库操作的方法(注意不要使用this,使用this的话无效),@AutowDLdBGire private A a这句话实际上返回的是当前Service的代理对象,但特别需要注意的是:所有操作数据库相关的方法,访问权限都需改成public,不然会出现mapper和service注入为null---这个是个大坑,具体原因还不知道(这个方式推荐使用)

(3) 使用:((A) AopContext.currentProxy()).方法名()进行调用(听说这个方式在打包发布的时候会出现问题,本次没有试过这个方式,所以不推荐)

总结:


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:「运维有小邓」账户锁定解决方案
下一篇:在多次 DDoS 攻击后,安全公司联手消除 WireX 僵尸网络(在多次尝试后你的电脑操作系统无法启动)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~