@Transactional annotation invalidation scenarios and solutions

@Transactional annotation does not take effect reasons and solutions

I encountered a problem in my work today: the operation record needs to be performed before inserting the data, so the method of saving the operation record called in the service layer, considering that the operation record should not be affected by the subsequent operation, so the transaction propagation type is Set to REQUIRES_NEW(If the current transaction exists, suspend the current transaction and restart the execution of the new transaction. The commit or rollback of the transaction is not affected by the previous transaction). During the test, it was found that the method of saving operation records was still returned even after REQUIRES_NEW was set. Affected by the following code, the following code reports an error, and the transaction recorded by the operation is also rolled back. The reason is that the method is not called through the proxy object, so the transaction is not processed by the proxy object and the @Transactional transaction is invalidated.

Simulate the scene at that time:

There is a user1 table in the database, the length of the name is 5, there are save and saveLog methods in the service, and then the saveLog method is called in the save method.

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("=======保存成功=======");
    }
}

After execution, it is found that although the transaction propagation behavior is REQIREES_NEW, no new transaction is created to execute, because the saveLog method is not called through the proxy object, so the @Transactional transaction fails

Solution:

Call the saveLog method after obtaining the proxy object of the current object through AopContext

@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("=======保存成功=======");
    }

}

After execution, even if you save the user's error later, it will not affect the execution of the saveLog transaction, and @Transactional can be executed normally.

Guess you like

Origin blog.csdn.net/dndndnnffj/article/details/111028917