vra*_*ojr 5 java spring hibernate jpa spring-data-jpa
注意:我不需要关于最佳锁定的说明.这个问题是关于使用乐观锁定时的特定Spring Data行为.
每当实体具有带注释的字段时,从jpa 规范中@Version,应该在实体上自动启用乐观锁定.
如果我在使用存储库的弹簧数据测试项目中执行此操作,则锁定似乎不会被激活.实际上,OptimisticLockException在执行不可重复读取测试时会抛出no (参见JPA规范第93页上的P2)
但是,从spring 文档中我看到,如果我们用一个方法注释,@Lock(LockModeType.OPTIMISTIC)那么底层系统会正确地抛出一个OptimisticLockException(然后由spring捕获并以稍微不同的形式向上传播).
这是正常的还是我错过了什么?我们是否有义务对所有方法进行注释(或者创建一个采用锁定的基本存储库实现)以使用spring数据启用乐观行为?
我在spring boot项目1.4.5版本的上下文中使用spring数据.
考试:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
测试服务:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
存储库:
@Repository
public interface UserRepository extends CrudRepository<User, Integer> {
}
Run Code Online (Sandbox Code Playgroud)
使用Spring Data进行乐观锁定JPA由使用的JPA实现实现.
您指的是JPA规范第93页上的P2.该部分以:
如果事务T1调用
lock(entity, LockModeType.OPTIMISTIC)版本化对象,则实体管理器必须确保不会发生以下任何现象:
但是你的测试并没有创造出这样的场景.该方法lock永远不会被调用.因此,不会发生相关锁定.特别是加载实体不会调用lock它.
当一个人修改一个对象(第二个但是规范的最后一个段落)时,事情会发生变化:
如果以其他方式更新或删除版本化对象,则实现必须确保满足要求
LockModeType.OPTIMISTIC_FORCE_INCREMENT,即使未进行显式调用EntityManager.lock.
注意:您使用相同的存储库生成两个线程,这反过来将使它们使用相同的存储库EntityManager.我怀疑这是否得到了支持,EntityManager而且我也不确定你是否真的以这种方式获得了两笔交易,但这是另一天的问题.
| 归档时间: |
|
| 查看次数: |
8540 次 |
| 最近记录: |