事务隔离READ_COMMITTED丢失更新

时间:2015-11-15 19:10:58

标签: spring postgresql spring-data-jpa spring-transactions isolation-level

我使用Spring Boot制作了示例项目来测试事务的隔离级别。 PostgreSQL用作RDBMS,但我想这并不重要。

案例

第一个事务选择数据,更改数据并休眠。在它睡觉时,第二次交易开始。它选择相同的行,进行更改和提交。在第一次交易醒来后提交它的变化。

问题

第一笔交易的READ_COMMITTED隔离级别是否完全失去第二笔交易的更改?使用未发生的REPEATABLE_READSERIALIZABLE级别,以及第一个事务尝试提交时引发的异常。

我使用了最小的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);
    }

0 个答案:

没有答案