首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring :具有隔离READ_COMMITTED的事务不会看到在另一个事务中提交的数据

Spring :具有隔离READ_COMMITTED的事务不会看到在另一个事务中提交的数据
EN

Stack Overflow用户
提问于 2018-11-29 01:49:51
回答 2查看 2.3K关注 0票数 3

所以,我有一个非常简单的基于Spring的web应用程序.

数据库有一个表user,列为idusername,还有一个记录:(1, 'Joe')

我还有以下课程:

User -映射到表user的实体

UserRepository -它的Spring存储库

UserService + DefaultUserService --一个包含CRUD方法的服务层

UserController -有两种方法的控制器:getupdate

Application -主类(带有@EnableTransactionManagement注释)

因此,我要做的是测试事务隔离级别READ_COMMITTED。我同时发送两个请求:

  1. 对于更新用户的/update,将其名称设置为Jack,然后将当前线程休眠5s,然后提交事务。
  2. /get,它在每次尝试后重复读取同一个用户10次,进行1s的午睡。

问题是,即使提交了用于(1)的事务,(2)仍然会返回一个旧值-- Joe。如果我试图在此之后向/get发送另一个请求,它将像预期的那样返回Jack,因此只有在transaction (2)在transaction (1)向DB提交更改之前启动时,问题才会发生。

您可以在下面找到一些代码以供参考。

服务:

代码语言:javascript
复制
@Service
public class DefaultUserService implements UserService {

    ... //fields & constructor

    @Override
    @SneakyThrows
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public User read(Long id) {
        User user = userRepository.findById(id).get();
        Thread.sleep(1000);
        return user;
    }

    @Override
    @SneakyThrows
    @Transactional
    public User update(Long id, User update) {
        log.info("Entering update method for user {}", id);
        User user = read(id);

        user.setUsername("Jack");
        user = userRepository.save(user);

        log.info("User {} updated, falling asleep for 5s", id);
        Thread.sleep(5000);

        return user;
    }
}

主计长:

代码语言:javascript
复制
@RestController
public class UserController {

    ... //fields & constructor

    @RequestMapping("/update")
    public User update() {
        User user = userService.update(1L, new User("Jack"));
        log.info("UPDATED: {}", user);
        return user;
    }

    @RequestMapping("/get")
    public User get() {
        User user = userService.read(1L);
        for (int i = 0; i < 10; i++) {
            log.info("READ: {}", user);
            user = userService.read(1L);
        }
        return user;
    }
}    

日志输出:

代码语言:javascript
复制
04:37:52.915 [io-8781-exec-10] READ: ID: 1 :: Joe
04:37:53.151 [nio-8781-exec-1] Entering update method for user 1
04:37:53.919 [io-8781-exec-10] READ: ID: 1 :: Joe
04:37:54.152 [nio-8781-exec-1] User 1 updated, falling asleep for 5s
04:37:54.922 [io-8781-exec-10] READ: ID: 1 :: Joe
04:37:55.926 [io-8781-exec-10] READ: ID: 1 :: Joe
04:37:56.932 [io-8781-exec-10] READ: ID: 1 :: Joe
04:37:57.937 [io-8781-exec-10] READ: ID: 1 :: Joe
04:37:58.943 [io-8781-exec-10] READ: ID: 1 :: Joe
04:37:59.222 [nio-8781-exec-1] UPDATED: ID: 1 :: Jack
04:37:59.947 [io-8781-exec-10] READ: ID: 1 :: Joe
04:38:00.950 [io-8781-exec-10] READ: ID: 1 :: Joe
04:38:01.956 [io-8781-exec-10] READ: ID: 1 :: Joe

控制器返回的响应也不同。对于/update,它是:

代码语言:javascript
复制
{"id":1,"username":"Jack"}

时间为/get

代码语言:javascript
复制
{"id":1,"username":"Joe"}

我使用的是MySQL 5.7.18和SpringBoot2.1.0。

对我可能做错了什么/错过了什么有什么想法吗?提前谢谢。

EN

回答 2

Stack Overflow用户

发布于 2018-11-29 04:55:52

您的代码在Oracle中正确工作,但对于MySQL则有一点不同。在这里阅读有关MySql中的隔离级别的内容

https://blog.pythian.com/understanding-mysql-isolation-levels-repeatable-read/

我相信,如果您将方法的isolation level更改为Read committed,它应该会正常工作,因为默认情况下,MySql有Repeatable-read,处理方式略有不同。

代码语言:javascript
复制
   @Transactional(Isolation.READ_COMMITTED)
    public User update(Long id, User update) 
票数 1
EN

Stack Overflow用户

发布于 2020-06-19 07:00:27

集合:

代码语言:javascript
复制
@Override
@SneakyThrows
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
public User read(Long id) {
    User user = userRepository.findById(id).get();
    Thread.sleep(1000);
    return user;
}
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53530717

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档