• 大刘哥
    2019-02-17
    第一步:注入实例
      @Autowired
        private FooService fooService;
    第二步:添加实现
       //把自己的实例注入进来,比较方便理解
        @Override
        public void invokeInsertThenRollbackBySelfService() throws RollbackException {
            fooService.insertThenRollback();
        }
        //获取当前代理,这样写避免了自己调用自己的实例
        @Override
        public void invokeInsertThenRollbackByAopContext() throws RollbackException {
            ((FooService) (AopContext.currentProxy())).insertThenRollback();
        }
        //再加一层事务
        @Transactional(rollbackFor = RollbackException.class)
        @Override
        public void invokeInsertThenRollbackAddTransactional() throws RollbackException {
            insertThenRollback();
        }
    第三步:添加测试方法
    可以先注释CommandLineRunner里面的内容
    @Slf4j
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class DeclarativeTransactionDemoApplicationTests {
        @Autowired
        private FooService fooService;
        @Autowired
        private JdbcTemplate jdbcTemplate;
        @Test
        public void invokeInsertThenRollback() {
            try {
                fooService.invokeInsertThenRollback();
            } catch (Exception e) {
                log.info("BBB {}",
                        jdbcTemplate
                                .queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='BBB'", Long.class));
            }
        }
        @Test
        public void invokeInsertThenRollbackBySelfService() {
            try {
                fooService.invokeInsertThenRollbackBySelfService();
            } catch (Exception e) {
                log.info("BBB {}",
                        jdbcTemplate
                                .queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='BBB'", Long.class));
            }
        }
        @Test
        public void invokeInsertThenRollbackByAopContext() {
            try {
                fooService.invokeInsertThenRollbackByAopContext();
            } catch (Exception e) {
                log.info("BBB {}",
                        jdbcTemplate
                                .queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='BBB'", Long.class));
            }
        }
        @Test
        public void invokeInsertThenRollbackAddTransactional() {
            try {
                fooService.invokeInsertThenRollbackAddTransactional();
            } catch (Exception e) {
                log.info("BBB {}",
                        jdbcTemplate
                                .queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='BBB'", Long.class));
            }
        }

    }
    展开

    作者回复: 干得漂亮

    
     74
  • T
    2019-02-13
    ...
    @Autowired
    private FooService fooService;
    ..
    @Override
    public void invokeInsertThenRollback() throws RollbackException{
      fooService.insertThenRollback();
    }
    ...
    展开
    
     43
  • 骄阳登峰
    2019-02-11
    在当前类的方法中通过AopContext.currentProxy()获取当前类的代理对象,再调用的代理对象的方法(其实是增强后的方法),事务就会生效了。

    作者回复: 是的,你提到了代理,可以把自己的实例注入进来,内部方法调用改为直接调用注入的实例。因为Spring其实是为你创建了一个代理,那我们调用代理就好了。其效果是一样的。

    
     18
  • 翟毅
    2019-02-11
    思考题答案:((FooService) (AopContext.currentProxy())).insertThenRollback();测过了是对的。
    但我觉得最好的方法是避免这种内部调用

    作者回复: 这是一种方法,还有种更简单的做法是把自己的实例注入进来,内部方法调用改为直接调用注入的实例。因为Spring其实是为你创建了一个代理,那我们调用代理就好了。

     1
     13
  • 楼下小黑哥
    2019-02-27
    以前就踩过这个坑。默认情况下 Spring Aop 同级调用会失效,原因是同级无法创建代理对象.
    
     9
  • 北极的大企鹅
    2019-04-11
    比较想问的是学完框架后,是先学设计模式还是先学JVM原理,并发与线程安全,然后中间件和架构设计,数据库设计,Linux学习,跨语言学习顺序,这些都是按照什么样的顺序学习的,还有源码阅读顺序

    作者回复: 你说的这些如果是做Java后端的话,迟早都是要接触到的,个人觉得无所谓先后,建议先广泛地涉猎这些知识,并不一定要很精通,但要知道了解,一旦遇到了问题,要能在第一时间想到在哪里能找到相关的材料,能快速拎起来。

    
     6
  • 十一
    2019-02-13
    方法添加事务注解,应该就可以了

    作者回复: 这……也是个办法,但不是我这个问题的本意哈

    
     6
  • 小肩膀
    2019-02-13
    一个类自身调用自身的方法,例如A()调用B(),此时B方法的事务不起作用,由于事务增强处理是交给aop生成的代理类完成,A()方法未做事务处理,那么调用代理类的A()方法同样不具备事务。
     需要把A()移到不同于B()的类中,即可达到预期效果

    作者回复: 事务的确是AOP代理来实现的,不过你这里的A和B把我说晕了……把类的内部调用改成不同类之间的调用,其本质其实也是调用代理类的方法,所以效果是一样的。

    
     6
  • jackiesteed
    2019-03-06
    注入自己,通过类名.调用就可以了。在这里踩过坑,所以记忆犹新。不实现接口的cglib代理也是一样
    
     5
  • Im 刘朋
    2019-03-07
    如果把FooServiceImpl类中的方法全部去掉@Transactional注解,然后在类上加上@Transactional(rollbackFor = RollbackException.class),也能产生同样的结果,这样可以吗?

    作者回复: 在类上加@Transacational注解,则类里的public方法都会带上事务。而且属性都是用同一个。

    
     4
  • 碧雪天虹
    2019-02-15
    @Component
    public class FooServiceImpl implements FooService {
        @Autowired
        private JdbcTemplate jdbcTemplate;

        @Autowired
        private FooServiceImpl self;

        @Override
        @Transactional(rollbackFor = Exception.class)
        public void insertRecord() {
            jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('AAA')");
        }

        @Override
        @Transactional(rollbackFor = RollbackException.class)
        public void insertThenRollback() throws RollbackException {
            jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('BBB')");
            throw new RollbackException();
        }

        @Override
        public void invokeInsertThenRollback() throws RollbackException {
            self.insertThenRollback();
        }
    }
    展开
    
     4
  • 天王
    2019-02-13
    讲的内容偏重于应用,是否可以深入的说下,比如,事物执行的原理,详细的说下,这样能加深理解,也能明白各个属性具体怎么工作的, 在执行过程中,怎么起作用。只讲偏应用,过去之后,就忘记了。

    作者回复: 你好,这个部分的确以应用为主一些,后续的章节有些地方会做展开,考虑到大部分同学的情况,不会在课程中就每个点都去展开,还请理解。相信你提了这个问题,那应该也能从我在课程中说道的Spring的事务其实是通过AOP实现的这句中理解事务的原理,对吧:-)

    
     4
  • try_catch
    2019-02-14
    ApplicationContext.getBean("fooService" ).insert...

    作者回复: 只要能取得代理对象,执行代理的方法就行。

    
     2
  • Earth Dog
    2019-12-30
    好吧,在优化一点点,不过不知道好不好,这种也可以用注入或者单例来调用把,原理就是避免内部调用就好了把??
    new WeakReference<>(new FooServiceImpl()).get().insertThenRollback();

    作者回复: 很抱歉,你的所有做法都是错的,光在自己内部new一个FooServiceImpl的实例是不行的,因为我们的实例其实还经过了Spring的代理增强,然后才有了事务的支持,自己new的没这道增强。你之所以看到BBB 0是因为你new的实例没有注入JdbcTemplate,所以在执行SQL那步时就报错了,根本没插入数据。

     2
     1
  • helloworld
    2019-09-10
    想问下老师,1. 一般我们是在service接口层加注解,还是应该在serviceImpl类上加注解?
    2. 想问下,为什么我们autowire 接口层,就直接能试用到impl实现的方法,原理是什么呢?

    作者回复: 1. 加实现类上
    2.注入的其实是接口的实现,注入的是Bean,而Bean一定是一个实现

    
     1
  • 凌尘
    2019-07-19
    老师,我想问下为什么把@EnableTransactionManagement(mode= AdviceMode.PROXY)这一行注释掉,
    效果也是一样的,也用了事务。只用@Transactional就可以开启事务了吗?那@EnableTransactionManagement的具体作用又是什么呢?谢谢老师,如果有大佬看到了,也希望回答下我的问题,谢谢了~

    作者回复: 你没写并不代表没有,Spring Boot给我们做了自动配置

    
     1
  • 马鹿
    2019-06-18
    老师 请问一下 我的方法中有操作不同数据库的操作 比如操作mysql redis ,在异常后无法回滚。这种情况我该怎么办呢

    作者回复: Redis不算RDBMS,算NoSQL,MySQL和Redis本来就没有自动的事务关联,你只能手写,在MySQL回滚时自己清理Redis。哪怕是两个MySQL,也没有很好的分布式事务实现,JTA这种性能不是很理想,基本都是要靠自己实现,关于分布式事务可以了解下BASE和TCC的概念。

    
     1
  • t
    2019-06-05
    插个眼,这个肯定以后会碰到这个坑
    
     1
  • T^T
    2019-02-16
    老师能不能把每次提的问题,在下一小节中做一个解答呢?比如说第三个方法的调用,有人说通过获取代理对象,然后调用增强后的方法。而您有更好的解决办法,希望补充一个代码示例。

    作者回复: 在答疑的课程中会简单说明的,这里大家解决的思路都大同小异。

    
     1
  • 亨亨亨
    2019-02-13
    将普通方法调用的方式改为使用代理的方式进行访问
    
     1
我们在线,来聊聊吧