注册
登录
数据隔离
Spring @Transactional - 隔离、传播
返回
Spring @Transactional - 隔离、传播
作者:
糖果
发布时间:
2024-04-19 12:03:41 (7天前)
有人可以通过实际示例解释注释中的隔离和传播参数是@Transactional什么吗?
基本上什么时候以及为什么我应该选择更改它们的默认值。
收藏
举报
2 条回复
1#
回复此人
糖果
|
2021-07-27 10-57
好问题,虽然不是一个微不足道的回答。 ##### 传播 定义事务如何相互关联。常用选项: - REQUIRED:代码将始终在事务中运行。创建一个新事务或重用一个(如果可用)。 - REQUIRES_NEW:代码将始终在新事务中运行。如果存在,则暂停当前事务。 为默认值@Transactional是REQUIRED,这往往是你想要的。 ##### 隔离 定义事务之间的数据契约。 - 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:我们希望一切都回滚并且后备存储不变。
编辑
登录
后才能参与评论