博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
自定义切面会吃掉异常,导致事务不生效的问题。
阅读量:4080 次
发布时间:2019-05-25

本文共 3965 字,大约阅读时间需要 13 分钟。

问题描述

我们都知道,我们定义一个切面,然后绑定一个切点后,这个切面就能在合适的时间自动切入切点。对于@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 INTO tb_test (username, password) values (#{userName}, #{password});

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)@Transactionalpublic 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")@EnableTransactionManagementpublic 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@Componentpublic 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)@Transactionalpublic 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://ngini.baihongyu.com/

你可能感兴趣的文章
支付宝生活号服务号 用户信息获取 oauth2 登录对接 springboot java
查看>>
CodeForces #196(Div. 2) 337D Book of Evil (树形dp)
查看>>
uva 12260 - Free Goodies (dp,贪心 | 好题)
查看>>
uva-1427 Parade (单调队列优化dp)
查看>>
【设计模式】学习笔记14:状态模式(State)
查看>>
poj 1976 A Mini Locomotive (dp 二维01背包)
查看>>
斯坦福大学机器学习——因子分析(Factor analysis)
查看>>
linux对于没有写权限的文件如何保存退出vim
查看>>
IntelliJ IDEA 下的svn配置及使用的非常详细的图文总结
查看>>
【IntelliJ IDEA】idea导入项目只显示项目中的文件,不显示项目结构
查看>>
ssh 如何方便的切换到其他节点??
查看>>
JSP中文乱码总结
查看>>
Java实现DES加密解密
查看>>
HTML基础
查看>>
Java IO
查看>>
Java NIO
查看>>
Java大数据:Hbase分布式存储入门
查看>>
大数据学习:Spark RDD操作入门
查看>>
大数据框架:Spark 生态实时流计算
查看>>
大数据入门:Hive和Hbase区别对比
查看>>