gpt4 book ai didi

java - Spring data - 启用乐观锁定

转载 作者:搜寻专家 更新时间:2023-11-01 03:32:13 26 4
gpt4 key购买 nike

注意:我不需要关于乐观锁定的解释。这个问题是关于什么似乎是使用乐观锁定时特定的 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> {
}

最佳答案

使用 Spring Data JPA 的乐观锁定由所使用的 JPA 实现实现。

您指的是 JPA 规范第 93 页上的 P2。该部分开始于:

If transaction T1 calls lock(entity, LockModeType.OPTIMISTIC) on a versioned object, the entity manager must ensure that neither of the following phenomena can occur:

但是您的测试不会创建这样的场景。 lock 方法永远不会被调用。因此不会发生相关的锁定。特别是仅仅加载一个实体不会对其调用 lock

当一个人修改一个对象时,事情会发生变化(第 93 页,规范的最后一段):

If a versioned object is otherwise updated or removed, then the implementation must ensure that the requirements of LockModeType.OPTIMISTIC_FORCE_INCREMENT are met, even if no explicit call to EntityManager.lock was made.

注意:您正在使用同一个存储库生成两个线程,这反过来会使它们使用相同的 EntityManager。我怀疑 EntityManager 是否支持这一点,而且我不确定您是否真的通过这种方式获得了两笔交易,但这是改天的问题。

关于java - Spring data - 启用乐观锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47281523/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com