跨 2 个不同 Hibernate 会话的乐观锁定
Optimistic locking across 2 different Hibernate Sessions
我在服务层中写了一个这样的更新方法,我正在使用 Spring-data JpaRepository 进行所有 CRUD 操作。
public Note updateNote(Note note, Long id) {
Note current = repository.getOne(id);
current.setTitle(note.getTitle());
current.setDetail(note.getDetail());
return repository.save(current);
}
我想对该操作进行乐观锁定,所以我在 Note
实体中添加了一个版本字段。
- 休眠会话对版本信息有何影响?版本比较实际上是如何进行的?
- 我尝试通过使用多线程的一些测试来模拟这种情况,但无法这样做,也无法验证这是否有效。这种方法是正确的还是错误的?如果对象处于分离状态,乐观锁定是否会起作用
状态?或者是否有一些规则规定何时休眠
检查新旧实体之间的版本匹配?
- 另外,是否需要显式注解@Lock注解?或者它会默认选择 OPTIMISTIC_READ?
2: 不,你不需要任何 @Lock 来进行乐观锁定,
使用@Version 我们实现了乐观锁定。
1:现在你可以使用线程测试乐观锁场景了,下面我写了一些示例测试代码,你可以根据你的需要更新。
假设我有注释实体:
@Entity
@Data
@ToString
public class Note {
@Id
@GeneratedValue
private Long id;
@Version
private int version;
private String name;
}
我还有用于执行数据库操作的 Note Reposotory
@存储库
public interface NoteRepo extends JpaRepository<Note, Long> {
}
现在我有笔记服务了
@Service
@AllArgsConstructor
public class NoteService {
private final NoteRepo noteRepo;
@Transactional
public Note create() {
Note note = new Note();
note.setName("Test Sample");
note = noteRepo.save(note);
System.out.println(note);
return note;
}
@Transactional
public void update(Long id, String name) {
Note note = noteRepo.getById(id);
note.setName(name );
note = noteRepo.save(note);
}
}
现在是时候使用集成测试来测试乐观锁定了。
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes =Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TestServiceTest {
@Autowired
private NoteService noteService;
@Test
void assertObjectOptimisticLockingFailure() throws InterruptedException {
// Create a note, so after this we can perform updation
Note note = noteService.create();
//CountDownLatch required for wait test to complete
CountDownLatch countDownLatch = new CountDownLatch(2);
// Create 2 NoteThread to perform updation for exising note entity
NoteThread xNote = new NoteThread("X", note.getId(), countDownLatch);
NoteThread yNote = new NoteThread("Y", note.getId(), countDownLatch);
xNote.start();
yNote.start();
countDownLatch.await();
// Validate one of thread have ObjectOptimisticLockingFailureException
assertTrue(xNote.hasObjectOptimisticLockingFailure() || yNote.hasObjectOptimisticLockingFailure());
}
class NoteThread extends Thread {
private final String name;
private final Long id;
private final CountDownLatch countDownLatch;
private Class exceptionClass;
// verify exception
boolean hasObjectOptimisticLockingFailure() {
return this.exceptionClass == ObjectOptimisticLockingFailureException.class;
}
// Custome Thread class for performing note update and verify lock exception
public NoteThread(String name, Long id, CountDownLatch countDownLatch) {
this.name = name;
this.id = id;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
noteService.update(id, name);
} catch (Exception e) {
exceptionClass = e.getClass();
}finally {
countDownLatch.countDown();
}
}
}
}
我在服务层中写了一个这样的更新方法,我正在使用 Spring-data JpaRepository 进行所有 CRUD 操作。
public Note updateNote(Note note, Long id) {
Note current = repository.getOne(id);
current.setTitle(note.getTitle());
current.setDetail(note.getDetail());
return repository.save(current);
}
我想对该操作进行乐观锁定,所以我在 Note
实体中添加了一个版本字段。
- 休眠会话对版本信息有何影响?版本比较实际上是如何进行的?
- 我尝试通过使用多线程的一些测试来模拟这种情况,但无法这样做,也无法验证这是否有效。这种方法是正确的还是错误的?如果对象处于分离状态,乐观锁定是否会起作用 状态?或者是否有一些规则规定何时休眠 检查新旧实体之间的版本匹配?
- 另外,是否需要显式注解@Lock注解?或者它会默认选择 OPTIMISTIC_READ?
2: 不,你不需要任何 @Lock 来进行乐观锁定, 使用@Version 我们实现了乐观锁定。
1:现在你可以使用线程测试乐观锁场景了,下面我写了一些示例测试代码,你可以根据你的需要更新。
假设我有注释实体:
@Entity
@Data
@ToString
public class Note {
@Id
@GeneratedValue
private Long id;
@Version
private int version;
private String name;
}
我还有用于执行数据库操作的 Note Reposotory
@存储库
public interface NoteRepo extends JpaRepository<Note, Long> {
}
现在我有笔记服务了
@Service
@AllArgsConstructor
public class NoteService {
private final NoteRepo noteRepo;
@Transactional
public Note create() {
Note note = new Note();
note.setName("Test Sample");
note = noteRepo.save(note);
System.out.println(note);
return note;
}
@Transactional
public void update(Long id, String name) {
Note note = noteRepo.getById(id);
note.setName(name );
note = noteRepo.save(note);
}
}
现在是时候使用集成测试来测试乐观锁定了。
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes =Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TestServiceTest {
@Autowired
private NoteService noteService;
@Test
void assertObjectOptimisticLockingFailure() throws InterruptedException {
// Create a note, so after this we can perform updation
Note note = noteService.create();
//CountDownLatch required for wait test to complete
CountDownLatch countDownLatch = new CountDownLatch(2);
// Create 2 NoteThread to perform updation for exising note entity
NoteThread xNote = new NoteThread("X", note.getId(), countDownLatch);
NoteThread yNote = new NoteThread("Y", note.getId(), countDownLatch);
xNote.start();
yNote.start();
countDownLatch.await();
// Validate one of thread have ObjectOptimisticLockingFailureException
assertTrue(xNote.hasObjectOptimisticLockingFailure() || yNote.hasObjectOptimisticLockingFailure());
}
class NoteThread extends Thread {
private final String name;
private final Long id;
private final CountDownLatch countDownLatch;
private Class exceptionClass;
// verify exception
boolean hasObjectOptimisticLockingFailure() {
return this.exceptionClass == ObjectOptimisticLockingFailureException.class;
}
// Custome Thread class for performing note update and verify lock exception
public NoteThread(String name, Long id, CountDownLatch countDownLatch) {
this.name = name;
this.id = id;
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
noteService.update(id, name);
} catch (Exception e) {
exceptionClass = e.getClass();
}finally {
countDownLatch.countDown();
}
}
}
}