其他分享
首页 > 其他分享> > 【弄nèng - 化繁为简】@Transactional(propagation = Propagation.REQUIRES_NEW)失效

【弄nèng - 化繁为简】@Transactional(propagation = Propagation.REQUIRES_NEW)失效

作者:互联网

文章目录

参考
https://blog.csdn.net/hepei120/article/details/78058468
https://blog.csdn.net/yangquanwa/article/details/88578357

一. @Transactional失效

@Transactional失效的场景有很多种,感兴趣的研究下,文章很多,本文着重说明类内部调用Spring事务注解@Transactional失效的场景。

现象1

在一个事务中更新之后再查询能查询到最新的数据,毋庸置疑。
代码

    @Autowired
    private TestMapper testMapper;

    @Transactional
    public void testTransactional() {
        System.out.println("1.====:" + testMapper.selectById(1).toString());
        updateTestById("司马缸5");
        System.out.println("2.====:" + testMapper.selectById(1).toString());
    }
    
	public void updateTestById(String name) {
        TestEntity entity = new TestEntity();
        entity.setId(1);
        entity.setName(name);
        testMapper.updateById(entity);
    }

执行testTransactional()
输出
在这里插入图片描述

现象2

在一个事务中更新,在查询方法中添加事务传播行为Propagation.REQUIRES_NEW,意味着不管事务存不存在都新启用一个事务运行。

代码

    @Autowired
    private TestMapper testMapper;

    @Transactional
    public void testTransactional() {
        System.out.println("1.====:" + testMapper.selectById(1).toString());
        updateTestById("司马缸5");
        System.out.println("2.====:" + get().toString());
    }

    public void updateTestById(String name) {
        TestEntity entity = new TestEntity();
        entity.setId(1);
        entity.setName(name);
        testMapper.updateById(entity);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public TestEntity get() {
        return testMapper.selectById(1);
    }

执行testTransactional()
输出
在这里插入图片描述

分析

事务隔离级别

事务隔离级别由弱到强分别是:READ_UNCOMMITTED(未提交读)、READ_COMMITTED(提交读)、REPEATABLE_READ(重复读)和SERIALIZABLE(串行读)。

数据问题

不同的隔离级别会出现的问题

隔离界别脏读不可重复读幻读
READ_UNCOMMITTED允许允许允许
READ_COMMITTED不允允许允许
REPEATABLE_READ不允不允允许
SERIALIZABLE不允不允不允许

MySQL的默认事务隔离级别是REPEATABLE_READ,ORACLE、SQL Server、DB2和PostgreSQL的默认事务隔离级别是READ_COMMITED

按照MySQL的默认事务隔离级别REPEATABLE_READ按理来说不应该出现脏读,也就是不应该读取到其他事务没有提交的数据,但是现在读取到了,WHY???
继续看现象3

现象3

在一个事务中更新,在查询方法中添加事务传播行为Propagation.REQUIRES_NEW,意味着不管事务存不存在都新启用一个事务运行。

代码

@Service
public class TestServiceImpl extends ServiceImpl<TestMapper, TestEntity> implements ITestService {

    @Autowired
    private TestMapper testMapper;

    @Autowired
    private TestServiceImpl2 testServiceImpl2;

    @Transactional
    public void testTransactional() {
        System.out.println("1.====:" + testMapper.selectById(1).toString());
        updateTestById("司马缸5");
        System.out.println("2.====:" + testServiceImpl2.get().toString());
    }

    public void updateTestById(String name) {
        TestEntity entity = new TestEntity();
        entity.setId(1);
        entity.setName(name);
        testMapper.updateById(entity);
    }
}

@Service
public class TestServiceImpl2 extends ServiceImpl<TestMapper, TestEntity> implements ITestService {

    @Autowired
    private TestMapper testMapper;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public TestEntity get() {
        return testMapper.selectById(1);
    }
}

执行testTransactional()
输出
在这里插入图片描述

分析

看出现象2和现象3的代码有什么不同了吗?调用get()不同,2是this.get(),3是testServiceImpl2.get(),3把get()方法提取出来了。
都是查询数据库为什么2中@Transactional(propagation = Propagation.REQUIRES_NEW)失效了呢?

原因

Spring事务是基于AOP实现的,就是把@Transactional标识的类进行代理,在创建对象的时候创建代理类,在代理类中执行方法前后添加事务处理,相当于@Around。当我们执行需要事务的方法时是调用的代理类执行。但是在方法内部调用本类其他事务方法是通过this.get()的方式,得到的是目标类不是代理类,所以get()方法的Propagation.REQUIRES_NEW是失效的,并没有创建一个新的事务,还是在一个事务中执行。

结论

事务是基于代理类的

标签:事务,get,Transactional,entity,Propagation,public,testMapper,化繁为简
来源: https://blog.csdn.net/yy756127197/article/details/121105655