@Transactional注解失效场景及解决方案

@Transactional注解不生效原因及解决方案

今天再工作中遇到了一个问题:再插入数据前需要进行操作记录,因此再service层调用的保存操作记录的方法,考虑到操作记录不应被后面的操作所影响,因此将事务的传播型为设置为REQUIRES_NEW(如果当前有事务存在,将当前事务挂起,重新开启新事务执行。事务的提交或回滚不受之前事务的影响)测试时发现即使设置了REQUIRES_NEW后保存操作记录的方法仍然回被后面的代码所影响,后面代码报错,操作记录的事务也被回滚了,原因是没有通过代理对象去调用方法,因此事务没有被代理对象处理@Transactional事务失效了。

模拟当时的场景:

数据库内有user1表,name的长度为5,serivice中有save和saveLog方法再save方法内调用saveLog方法。

create table user1(
	id int primary key auto_increment,
	name varchar(5),
	create_date datetime
);

service:

@Service
public class User1Service {
    
    

    @Autowired
    private User1Mapepr user1Mapepr; //mybaits的mapper
	
    //这里传播行为声明为REQUIRED(如果当前没事务,创建事务,否则加入到当前事务)
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void save(){
    
    
		//先保存记录
        saveLog();
        //后保存用户(这里会报错,因为name字段长度超过数据库规定的5字符)
        user1Mapepr.save(new User1(null,"zs1111111111",new Date()));
    }

    //传播行为声明为REQUIRES_NEW(不管当前是否有事务,都创建新事务运行)
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    public void saveLog(){
    
    
        //这里保存用户,能正常执行
        System.out.println("saveLog");
        user1Mapepr.save(new User1(null,"s1",new Date()));
        System.out.println("=======保存成功=======");
    }
}

执行后发现,虽然事务传播行为为REQIREES_NEW但是并没有创建新事务去执行,原因是没有通过代理对象调用saveLog方法,因此@Transactional事务失效

解决办法:

通过AopContext获取当前对象的代理对象后调用saveLog方法

@Service
public class User1Service {
    
    

    @Autowired
    private User1Mapepr user1Mapepr;

    @Autowired
    private Service2 service2;


	//这里传播行为声明为REQUIRED(如果当前没事务,创建事务,否则加入到当前事务)
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void save(){
    
    
        //通过AopContext.currentProxy()获取当前对象的代理对象
        User1Service aopService = (User1Service)AopContext.currentProxy();
        //spring还为我们提供了AopUtils工具类
        System.out.println("是否是aop对象===>"+AopUtils.isAopProxy(service));
        System.out.println("是否是CGLIB===>"+AopUtils.isCglibProxy(service));
        System.out.println("是否是JDK===>"+AopUtils.isJdkDynamicProxy(service));
        //调用aop代理对象保存日志
        aopService.saveLog();
		
        user1Mapepr.save(new User1(null,"zs1111111111",new Date()));

    }
	//传播行为声明为REQUIRES_NEW(不管当前是否有事务,都创建新事务运行)
    @Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
    public void saveLog(){
    
    
        //这里保存用户,能正常执行
        System.out.println("saveLog");
        user1Mapepr.save(new User1(null,"s1",new Date()));
        System.out.println("=======保存成功=======");
    }

}

执行后,即使后面保存用户报错,也不影响saveLog事务的执行,@Transactional能后正常执行

猜你喜欢

转载自blog.csdn.net/dndndnnffj/article/details/111028917