spring-boot-starter-data-jpa
依赖和H2
内存数据库。我定义了一个包含两个字段(id
和firstName
)的User
实体,并通过扩展CrudRepository
接口声明了一个UsersRepository
。现在,考虑一个简单的控制器,它提供了两个端点:
/print-user
读取同一个用户两次,并打印出其名字,有一定的时间间隔;/update-user
用于在这两次读取之间更改用户的名字。请注意,我故意设置了隔离级别为Isolation.READ_COMMITTED
,并期望在第一次事务过程中,通过相同id检索两次的用户将具有不同的名字。但是,第一次事务打印相同的值两次。为了使问题更加清晰,这是完整的操作序列:1.最初,jeremy的名字设置为Jeremy。 2.然后,我调用
/print-user
,它打印出Jeremy并进入睡眠状态。
3.接下来,我从另一个会话中调用/update-user
,它将jeremy的名字更改为Bob。
4.最后,在第一次事务在休眠后被唤醒并重新读取jeremy用户时,它再次打印出Jeremy作为他的名字,即使第一个名字已经被更改为Bob(如果我们打开数据库控制台,它现在确实存储为Bob,而不是Jeremy)。看起来设置隔离级别在这里没有效果,我想知道为什么。
@RestController
@RequestMapping
public class UsersController {
private final UsersRepository usersRepository;
@Autowired
public UsersController(UsersRepository usersRepository) {
this.usersRepository = usersRepository;
}
@GetMapping("/print-user")
@ResponseStatus(HttpStatus.OK)
@Transactional (isolation = Isolation.READ_COMMITTED)
public void printName() throws InterruptedException {
User user1 = usersRepository.findById("jeremy");
System.out.println(user1.getFirstName());
// allow changing user's name from another
// session by calling /update-user endpoint
Thread.sleep(5000);
User user2 = usersRepository.findById("jeremy");
System.out.println(user2.getFirstName());
}
@GetMapping("/update-user")
@ResponseStatus(HttpStatus.OK)
@Transactional(isolation = Isolation.READ_COMMITTED)
public User changeName() {
User user = usersRepository.findById("jeremy");
user.setFirstName("Bob");
return user;
}
}
findById(....)
应该返回一个Optional<User>
吗? - Andrew SusersRepository.save(user)
。 - Shababb Karimsave()
调用是多余的。 - escudero380