【发布时间】:2018-04-27 03:36:15
【问题描述】:
注意: 我不需要关于乐观锁定的解释。 这个问题是关于使用乐观锁定时似乎特定的 Spring Data 行为。
从 jpa specs 开始,只要实体具有 @Version 注释字段,就应该在实体上自动启用乐观锁定。
如果我在使用 Repositories 的 spring 数据测试项目中执行此操作,锁定似乎没有被激活。事实上,在进行不可重复读取测试时不会抛出 OptimisticLockException(请参阅 JPA 规范第 93 页上的 P2)
但是,从 spring docs 开始,我看到如果我们用 @Lock(LockModeType.OPTIMISTIC) 注释单个方法,那么底层系统会正确抛出 OptimisticLockException(然后被 spring 捕获并以稍微不同的形式向上传播)。
这是正常的还是我错过了什么?我们是否有义务注释我们所有的方法(或创建一个获取锁的基本存储库实现)以启用 Spring 数据的乐观行为?
我在 spring boot 项目的上下文中使用 spring 数据,版本 1.4.5。
测试:
public class OptimisticLockExceptionTest {
static class ReadWithSleepRunnable extends Thread {
private OptimisticLockExceptionService service;
private int id;
UserRepository userRepository;
public ReadWithSleepRunnable(OptimisticLockExceptionService service, int id, UserRepository userRepository) {
this.service = service;
this.id = id;
this.userRepository = userRepository;
}
@Override
public void run() {
this.service.readWithSleep(this.userRepository, this.id);
}
}
static class ModifyRunnable extends Thread {
private OptimisticLockExceptionService service;
private int id;
UserRepository userRepository;
public ModifyRunnable(OptimisticLockExceptionService service, int id, UserRepository userRepository) {
this.service = service;
this.id = id;
this.userRepository = userRepository;
}
@Override
public void run() {
this.service.modifyUser(this.userRepository, this.id);
}
}
@Inject
private OptimisticLockExceptionService service;
@Inject
private UserRepository userRepository;
private User u;
@Test(expected = ObjectOptimisticLockingFailureException.class)
public void thatOptimisticLockExceptionIsThrown() throws Exception {
this.u = new User("email", "p");
this.u = this.userRepository.save(this.u);
try {
Thread t1 = new ReadWithSleepRunnable(this.service, this.u.getId(), this.userRepository);
t1.start();
Thread.sleep(50);// To be sure the submitted thread starts
assertTrue(t1.isAlive());
Thread t2 = new ModifyRunnable(this.service, this.u.getId(), this.userRepository);
t2.start();
t2.join();
assertTrue(t1.isAlive());
t1.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试服务:
@Component
public class OptimisticLockExceptionService {
@Transactional
public User readWithSleep(UserRepository userRepo, int id) {
System.err.println("started read");
User op = userRepo.findOne(id);
Thread.currentThread();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println("read end");
return op;
}
@Transactional
public User modifyUser(UserRepository userRepo, int id) {
System.err.println("started modify");
User op = userRepo.findOne(id);
op.setPassword("p2");
System.err.println("modify end");
return userRepo.save(op);
}
}
存储库:
@Repository
public interface UserRepository extends CrudRepository<User, Integer> {
}
【问题讨论】:
标签: java spring hibernate jpa spring-data-jpa