我使用Spring Boot制作了示例项目来测试事务的隔离级别。 PostgreSQL用作RDBMS,但我想这并不重要。
第一个事务选择数据,更改数据并休眠。在它睡觉时,第二次交易开始。它选择相同的行,进行更改和提交。在第一次交易醒来后提交它的变化。
第一笔交易的READ_COMMITTED
隔离级别是否完全失去第二笔交易的更改?使用未发生的REPEATABLE_READ
或SERIALIZABLE
级别,以及第一个事务尝试提交时引发的异常。
我使用了最小的Spring Boot项目(spring-boot-starter-data-jpa)。
一些代码:
@Transactional(isolation = Isolation.READ_COMMITTED)
public Product firstTransaction(Integer id) {
Product p = repository.findOne(id);
p.setName(p.getName() + "+first");
// Waiting secondTransaction to finish
try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}
return p;
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public Product secondTransaction(Integer id) {
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
Product p = repository.findOne(id);
p.setName(p.getName() + "+second");
return p;
}
测试
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Product> firstFuture = pool.submit(() -> service.firstTransaction(productId));
Future<Product> secondFuture = pool.submit(() -> service.secondTransaction(productId));
try {
Product firstProduct = firstFuture.get();
Product secondProduct = secondFuture.get();
Product productFromRepo = repository.findOne(productId);
assertEquals("base+first", firstProduct.getName());
assertEquals("base+second", secondProduct.getName());
assertEquals(productFromRepo.getName(), firstProduct.getName());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}