Java小强个人技术博客站点    手机版
当前位置: 首页 >> 框架 >> Aspect声明式事物解决Spring事物内部调用不生效

Aspect声明式事物解决Spring事物内部调用不生效

20620 框架 | 2022-5-29

在之前解释Spring事物不生效时,列举了很多方面的原则,详细参考

Spring事物不生效的原因

http://www.javacui.com/framework/560.html 

其中说到了一点:在类内部调用调用类内部@Transactional标注的方法。这种情况下也会导致事务不开启


假如有如下实例类:

@Service
public class T1ServiceImpl extends ServiceImpl<T1EntityMapper, T1Entity> implements T1Service {

    @Autowired
    private T2Service t2Service;

    @Override
    public void insertT1() {
        doInsert();
    }

    @Transactional(rollbackFor = Exception.class)
    public void doInsert(){
        T1Entity t1Entity = new T1Entity();
        t1Entity.setName("t1");
        T2Entity t2Entity = new T2Entity();
        t2Entity.setName("t2");

        save(t1Entity);
        System.out.println(1/0);
        t2Service.save(t2Entity);
    }
}


如上模拟了一个异常,因为是运行时异常,所以增加注解rollbackFor,原因不生效那篇里面也说过:

(6)注解为事务范围的方法中,事务的回滚仅仅对于unchecked的异常有效。对于checked异常无效。也就是说事务回滚仅仅发生在出现RuntimeException或Error的时候。如果希望一般的异常也能触发事务回滚,需要在注解了@Transactional的方法上,将@Transactional回滚参数设置


那么调用insertT1()时,insertT1()调用doInsert(),虽然该方法标记了事物,但是实际上事物是不起作用的。

如果要解决这个问题,要么就是再写一个Service,要么就是写到一个方法里面,即一定要使用Spring代理来调用这个方法,否则Spring无法帮我们处理事物

但是如果你一定要这样写,而且要在一个Service里面,那么可以通过如下方式解决:

首先拿到当前对象的代理对象,一般你在哪个ServiceImpl里面,就是哪个Service,然后通过代理对象进行调用,例如:

package com.example.springboot.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springboot.entity.T1Entity;
import com.example.springboot.entity.T2Entity;
import com.example.springboot.mapper.T1EntityMapper;
import com.example.springboot.service.T1Service;
import com.example.springboot.service.T2Service;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class T1ServiceImpl extends ServiceImpl<T1EntityMapper, T1Entity> implements T1Service {

    @Autowired
    private T2Service t2Service;

    @Override
    public void insertT1() {
        T1Service t1Service = (T1Service)AopContext.currentProxy();
        t1Service.doInsert();
    }

    @Transactional(rollbackFor = Exception.class)
    public void doInsert(){
        T1Entity t1Entity = new T1Entity();
        t1Entity.setName("t1");
        T2Entity t2Entity = new T2Entity();
        t2Entity.setName("t2");

        save(t1Entity);
        System.out.println(1/0);
        t2Service.save(t2Entity);
    }
}


POM引入

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

 

SpringBoot启动的话,要增加一个注解

@EnableAspectJAutoProxy(exposeProxy = true)

如下

package com.example.springboot;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@EnableAspectJAutoProxy(exposeProxy = true)
@MapperScan("com.example.springboot.mapper")
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}


这样就成了,这个方法也是通过代理进行调用的,事物才会正常生效。



END

推荐您阅读更多有关于“ spring 注解 事物 springboot Aspect 声明式 ”的文章

上一篇:基于Redis的SETNX命令实现锁 下一篇:使用Redis实现全局唯一ID

猜你喜欢

发表评论: