小编典典

Spring @Transactional - 隔离、传播

all

有人可以通过实际示例解释注释中的 隔离传播 参数吗?@Transactional

基本上什么时候以及为什么我应该选择更改它们的默认值。


阅读 104

收藏
2022-03-11

共1个答案

小编典典

好问题,虽然不是一个微不足道的问题。

[传播](http://static.springsource.org/spring/docs/current/javadoc-

api/org/springframework/transaction/annotation/Propagation.html)

定义事务如何相互关联。常用选项:

  • REQUIRED:代码将始终在事务中运行。创建一个新事务或重用一个(如果有)。
  • REQUIRES_NEW:代码将始终在新事务中运行。如果存在,则暂停当前事务。

的默认值为,这通常是您想要的@TransactionalREQUIRED

[隔离](http://static.springsource.org/spring/docs/current/javadoc-

api/org/springframework/transaction/TransactionDefinition.html)

定义事务之间的数据契约。

  • ISOLATION_READ_UNCOMMITTED: 允许脏读。
  • ISOLATION_READ_COMMITTED: 不允许脏读。
  • ISOLATION_REPEATABLE_READ:如果在同一个事务中读取一行两次,结果总是相同的。
  • ISOLATION_SERIALIZABLE:按顺序执行所有事务。

不同级别在多线程应用程序中具有不同的性能特征。我认为,如果您了解 脏读 概念,您将能够选择一个不错的选择。

默认值可能因不同的数据库而异。例如,对于MariaDB,它是REPEATABLE READ.


可能发生脏读的示例:

  thread 1   thread 2      
      |         |
    write(x)    |
      |         |
      |        read(x)
      |         |
    rollback    |
      v         v 
           value (x) is now dirty (incorrect)

因此,合理的默认值(如果可以声明的话)可能是ISOLATION_READ_COMMITTED,它只允许您读取已经由其他正在运行的事务提交的值,并结合传播级别REQUIRED.
然后,如果您的应用程序有其他需求,您可以从那里开始工作。


一个在进入例程时总是创建新事务provideService并在离开时完成的实际示例:

public class FooService {
    private Repository repo1;
    private Repository repo2;

    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void provideService() {
        repo1.retrieveFoo();
        repo2.retrieveFoo();
    }
}

如果我们改为使用REQUIRED,如果在进入例程时事务已经打开,则该事务将保持打开状态。另请注意, a 的结果rollback可能不同,因为多个执行可能参与同一事务。


我们可以通过测试轻松验证行为,并查看结果与传播级别有何不同:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:/fooService.xml")
public class FooServiceTests {

    private @Autowired TransactionManager transactionManager;
    private @Autowired FooService fooService;

    @Test
    public void testProvideService() {
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        fooService.provideService();
        transactionManager.rollback(status);
        // assert repository values are unchanged ... 
}

传播水平为

  • REQUIRES_NEW:我们预计 不会 回滚,因为它创建了自己的子交易fooService.provideService()。 __

  • REQUIRED:我们希望一切都回滚并且后备存储没有改变。

2022-03-11