转载:https://cloud.tencent.com/developer/ask/78013
事务之间应如何相互关联
Required
:代码将始终在事务中运行。创建一个新事务,或者在可用的情况下重用一个事务。Requires_new
:代码将始终在新事务中运行。如果存在当前事务,则暂停当前事务。
定义事务之间的数据契约。
Read Uncommitted
*允许脏读Read Committed
*不允许脏读Repeatable Read
*如果一行在相同的传输中被读取两次,则结果总是相同的。Serializable
:按顺序执行所有事务
在多线程应用程序中,不同级别具有不同的性能特征,并且你还需要了解dirty reads
概念。
以下示例可能会发生脏读。
thread 1 thread 2
| |
write(x) |
| |
| read(x)
| |
rollback |
v v
value (x) is now dirty (incorrect)
因此,一个正常的默认值(如果可以声明的话)可以为Read Comitted
,它只允许你读取已经由其他运行事务处理的值,并且可以结合Required
的传播级别。如果你的应用程序有需求的话,在这里同样也能起作用。
当进入provideService
时将始终创建新事务,并在离开时完成。
public class FooService {
private Repository repo1;
private Repository repo2;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void provideService() {
repo1.retrieveFoo();
repo2.retrieveFoo();
}
}
如果我们使用了Required,那么当事务在进入程序时并且已经打开的时候,事务将保持打开状态。还要注意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
:我们希望所有的东西都回滚,并保持原样。