自定义切面会吃掉异常,导致事务不生效的问题。
问题描述
我们都知道,我们定义一个切面,然后绑定一个切点后,这个切面就能在合适的时间自动切入切点。对于@AfterThrowing
和@Around
,我们可以再切面中捕获异常,处理异常。
我们也知道,我们对一个方法添加事务,那么当此方法抛出异常后,事务会捕获异常,自动执行混滚。
那么,如果添加事务的方法就是我们说的那个切点呢?这个方法(切点)在同时添加了事务和切面的情况下,如果这个方法抛出了异常,代码会怎么执行呢?
对结果的猜测
代码执行的效果无非以下三种情况:
1. 切面执行,事务不执行;
2. 切面不执行,事务执行;
3. 切面和事务都执行;
我们对这三种猜测进行如下的验证。
验证
1、创建一张表
CREATE TABLE `tb_test` (`username` varchar(12) NOT NULL,`password` varchar(12) NOT NULL,UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2、定义一个pojo
import java.io.Serializable;public class MyTestDO implements Serializable {private static final long serialVersionUID = 1431573779444162048L;private String userName;private String password;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
3、写dao层代码
//定义dao接口:boolean insertTest(MyTestDO myTestDO);
#配置mapper.xml
<insert id="insertTest" parameterType="MyTestDO">INSERT INTO tb_test (username, password)values (#{userName}, #{password});</insert>
4、直接在controller层调用dao层代码
@RequestMapping(value = "/daoTest", method = RequestMethod.GET)public boolean daoTest() {MyTestDO myTestDO = new MyTestDO();myTestDO.setUserName("wei.hu");myTestDO.setPassword("123456");return stubbingDao.insertTest(myTestDO);}
5、让代码run起来(本地启的8088端口),调用http://localhost:8088/daoTest
,可以看到返回true
,证明准备工作ready。
到这里,我们准备工作已经做好了,我们可以在此基础上进行验证了。
6、我们先来验证切面和事务同时存在的情况。
6.1、添加声明式事务:
//修改controller类,在方法上添加 @Transactional@RequestMapping(value = "/daoTest", method = RequestMethod.GET)
@Transactional
public boolean MyTestDO myTestDO = new MyTestDO();myTestDO.setUserName("wei.hu");myTestDO.setPassword("123456");return stubbingDao.insertTest(myTestDO);
}
6.2、在启动类(这里使用的是springboot)上添加注解 @EnableTransactionManagement
@SpringBootApplication
@ServletComponentScan
@MapperScan(basePackages = "cn.***.mockcloud.store.dao")
@EnableTransactionManagement
public class MockcloudApplication {public static void main(String[] args) {SpringApplication.run(MockcloudApplication.class, args);}
}
到这里,声明式事务已经添加完成。
7、我们开始为controller类的daoTest()方法添加切面。
7.1、定义一个切面类ConfigControllerAop
,并将controller类的daoTest()方法作为切入点:
package cn.tongdun.mockcloud.container.aop;import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;@Aspect
@Component
public class ConfigControllerAop {private static final Logger logger = LoggerFactory.getLogger(ConfigControllerAop.class);@Pointcut("execution(* cn.tongdun.mockcloud.web.controller.*.*(..))")private void controllerPointcut() {}@AfterThrowing(throwing = "e", pointcut = "controllerPointcut()")public void exceptionDeal(Exception e) {e.printStackTrace();logger.error("[MOCKCLOUD - ConfigControllerAop - exceptionDeal]");}}
8、为了验证问题,我们连续向库中写入两条一样的记录。因为库表中username是惟一的,因此连续两条插入动作,第二条插入动作将会抛异常。我们将controller类的daoTest()方法的方法体修改为如下:
@RequestMapping(value = "/daoTest", method = RequestMethod.GET)
@Transactional
public boolean daoTest() {MyTestDO myTestDO = new MyTestDO();myTestDO.setUserName("wei.hu");myTestDO.setPassword("123456");System.out.println(stubbingDao.insertTest(myTestDO));return stubbingDao.insertTest(myTestDO);
}
9、让代码run起来,调用http://localhost:8088/daoTest
。然后我们查看数据库,发现库表中写入了一条数据。
这代表什么?如果说事务生效,那么库表中应该是一条数据都没有的(我们队controler类的daoTest()方法添加了@Transactional声明式事务,同时又在daoTest()方法中添加连续对数据库做了两次insert动作。第一次insert成功,第二次失败)。但是我们在库表中确确实实插入了一条数据,并且应用后台抛出了异常。
因此,在对同一个方法同时添加事务和切面,当发生异常时,事务是不生效的!!!
10、我们重置实验条件(删除上面操作在库中插入的数据),注释掉切面代码,然后从新run代码,执行’http://localhost:8088/daoTest‘,就会发现,库表中一条数据都没有,此时事务生效了。
结论
如果一个方法,不仅作为切点添加了切面,而且还添加了事务,那么当这个方法抛出异常时,总是切面先捕获到异常,并且吞掉了这个异常。而事务是捕获不到这个异常的,因此事务是不生效的。
自定义切面会吃掉异常,导致事务不生效的问题。相关推荐
- spring 事务应用误区总结:那些导致事务不回滚的坑
基于JDBC的 Spring事务在项目中常用来保证数据的一致性, 想要正确的使用,绝不是加一个@Transactional那么简单.最近团队内在排查事务不生效的问题时,就遇到了一个很典型的错误应用的场 ...
- 避坑spring整合mybatis事务不生效问题
作者最近在用spring整合mybatis的时候碰到一个问题就是开启声明式事务之后发现事务不生效,出现异常之后不回滚,在网上查阅很多资料后都没有成功解决.最后仔细检查代码之后发现SqlSessionF ...
- spring同类调用事务不生效-原因及三种解决方式
spring提供的声明式事务注解@Transactional,极大的方便了开发者管理事务,无需手动编写开启.提交.回滚事务的代码. 但是也带来了一些隐患,如果注解使用不当,可能导致事务不生效,最终导致 ...
- c++ 外部组件发生异常_谁再悄咪咪的吃掉异常,我上去就是一 JIO
又到周末了,周更选手申请出站~ 这图太魔性了啊 这次分享一下上个月碰到的离奇的问题.一个简单的问题,硬是因为异常被悄咪咪吃掉,过关难度直线提升,导致小黑哥排查一个晚上. 这个美好的晚上,本想着开两把 ...
- 谁再悄咪咪的吃掉异常,我上去就是一 JIO
这图太魔性了啊 这次分享一下上个月碰到的离奇的问题.一个简单的问题,硬是因为异常被悄咪咪吃掉,过关难度直线提升,导致小黑哥排查一个晚上. 这个美好的晚上,本想着开两把 LOL 无限火力,在召唤师峡谷来 ...
- 解决android 异常导致应用程序停止运行的错误
(一) 前言 各位亲爱的午饭童鞋,是不是经常因为自己的程序中出现未层捕获的异常导致程序异常终止而痛苦不已?嗯,是的.. 但是,大家不要怕,今天给大家分享一个东东可以解决大家这种困扰,吼吼! (二) U ...
- day056-58 django多表增加和查询基于对象和基于双下划线的多表查询聚合 分组查询 自定义标签过滤器 外部调用django环境 事务和锁...
一.多表的创建 from django.db import models# Create your models here. class Author(models.Model):id = model ...
- spring事务管理中,用try-catch处理了异常,事务也会回滚?
在平时的开发中,如果在事物方法中用 try-catch处理了异常,那么spring aop不能捕获到异常信息,从而会导致spring不能对事务方法正确的进行管理,不能及时回滚错误信息. 下面用代码演示 ...
- Seata分布式事务控制整合Mybatis-Plus导致事务控制失效
解决方案 1. pom文件引入Druid数据源 <!--druid--> <dependency> <groupId>com.alibaba</groupId ...
最新文章
- 香港中文大学 (深圳) -博士硕士招生 -智能优化及规划方向
- php判断手机浏览器,PHP环境下判断客户端是否为手机浏览器
- 将矩阵转为一行_LeetCode1253:矩阵重构
- c语言编译器怎么用scanfkl,C语言一些笔记
- leetcode1292. 元素和小于等于阈值的正方形的最大边长(二分法+前缀和)
- 从概念到落地,中台可以解决哪些问题?怎么做?(附PPT)
- 汇编语言---函数调用栈
- LeetCode 1004. 最大连续1的个数 III(双指针+滑动窗口)
- androidru使用adb启动activity和monkeyrunner启动activity
- 后台第三方编辑器接入秀米编辑器整体流程
- split 分割 字符串(分隔符如:* ^ : | , .) 及注意点
- 企业间数据竞争规则研究
- 零基础个人网站搭建教程(一个完全的新人如何搭建自己的个人网站)
- 一张图理解栈顶指针加加减减的问题
- 运用windows shell修复Wannacry漏洞
- BPMN2.0协议解析
- php秒杀负库存问题,店铺商品出现负库存原因分析,负库存商品处理规范
- Allegro原理图反标教程
- 文献:利用自驱动分子马达并行计算子集和问题 Parallel computation with molecular-motor-propelled agents...(PNAS)
- 爱快路由系统带PPPOE服务器吗,爱快路由+华为交换机 实现vlan下拨号到爱快pppoe服务器...
热门文章
- linux系统如何修复分区工具,推荐一个Linux分区恢复工具Testdisk(Windows也能用)...
- Android系统开机到Launcher启动流程分析
- laravel laracasts/flash使用
- 挖潜无极限---数据挖掘技术与应用热点扫描
- 后宫宛如传服务器维护,更新丨《后宫宛如传》1.17.0版本更新公告
- 苹果CMS v10模板 - JOEOEL模板/苹果CMS手机端模板
- 海底捞,我们该学什么?--《海底捞你学不会》读后感
- vue根据数字显示对应的文字状态
- TCP传输的终极秘密
- Java线程思想模拟电影院卖票