zoukankan      html  css  js  c++  java
  • @Transactional注解为什么不生效

    一、背景

    • 方法添加了@Transactional注解,为什么事务不生效

    二、步骤

    • 测试用表结构
    CREATE TABLE `test_aop` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `name` varchar(100) DEFAULT NULL,
        PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    • 事务方法所在类
    @Component
    @Slf4j
    public class AopDataService {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Autowired
        private AopDataService aopDataService;
    
        // 写入数据
        @Transactional
        public void insert(String value) {
            jdbcTemplate.update("insert into test_aop(name) values('" + value + "')");
        }
    
        // 写入数据后抛异常
        @Transactional
        public void insertAndRollback(String value) {
            log.info("insertAndRollback {}", value);
            jdbcTemplate.update("insert into test_aop(name) values('" + value + "')");
            throw new RuntimeException();
        }
    
        // 使用this调用事务方法
        public void invokeMethod() {
    
            try {
    
                this.insertAndRollback("invokeMethod");
    
                // 这里的this就是AopDataService,不是代理对象。
                // 所以调用的insertAndRollback方式是原生方法,不是@Transactional注解代理后的对象
    
            } catch (RuntimeException ex) {
                log.warn("Catch an Exception in invokeMethod()");
            }
        }
    
        // 使用this.aopDataService调用事务方法
        public void invokeMethodAutowired() {
    
            try {
    
                this.aopDataService.insertAndRollback("invokeMethodAutowired");
                // this.aopDataService 代理对象,事务生效
    
            } catch (RuntimeException ex) {
                log.error("Catch an Exception in invokeMethodAutowired()");
            }
        }
    
        // 使用getBean调用事务方法
        public void invokeMethodGetBean() {
    
            try {
    
                AopDataService aopDataService = SpringUtil.getBean("aopDataService", AopDataService.class);
                aopDataService.insertAndRollback("invokeMethodGetBean");
    
                // aopDataService 代理对象,事务生效
    
            } catch (RuntimeException ex) {
                log.warn("Catch an Exception in invokeMethodGetBean()");
            }
        }
    
    }
    • 调用事务方法单元测试
      @Autowired
        private AopDataService aopDataService;
    
        // 写入成功(this.aopDataService是代理对象)
        @Test
        public void insert() {
    
            this.aopDataService.insert("insert");
        }
    
        // 抛异常,数据写入不成功(this.aopDataService是代理对象)
        @Test
        public void insertAndRollback() {
    
            this.aopDataService.insertAndRollback("insertAndRollback");
        }
    
        // 抛异常,数据写入成功(invokeMethod方法内未使用AopDataService代理对象)
        @Test
        public void invokeMethod() {
    
            this.aopDataService.invokeMethod();
        }
    
        // 抛异常,数据写入不成功(invokeMethodAutowired方法内使用了AopDataService代理对象)
        @Test
        public void invokeMethodAutowired() {
    
            this.aopDataService.invokeMethodAutowired();
        }
    
        // 抛异常,数据写入不成功(invokeMethodGetBean方法内使用了AopDataService代理对象)
        @Test
        public void invokeMethodGetBean() {
    
            this.aopDataService.invokeMethodGetBean();
        }

    三、总结&问题

    • invokeMethod通过 this方式调用insertAndRollback方法,该方法抛异常但是写入成功,原因是
      这里的this就是 AopDataService,不是代理对象。 
      所以调用的insertAndRollback方式是原生方法,不是@Transactional注解代理后的对象
    • invokeMethodAutowired、invokeMethodGetBean调用成功是因为都使用的AopDataService代理对象
  • 相关阅读:
    自我分析和展望
    测试设计说明及结队反思总结
    WordCount项目
    结对编程
    第一周的博客作业
    第一次作业:统计文件字符串字符行的个数
    系统分析与设计结对项目———Wordcount
    第一周的博客作业
    第一次 作业 workcount (基础功能实现)
    触摸点为scrollview上的子控件时,scrollview不能滚动(iOS8)
  • 原文地址:https://www.cnblogs.com/gossip/p/14280772.html
Copyright © 2011-2022 走看看