悲观锁中的乐观锁异常

9

我正在使用Spring和Hibernate。我正在这样运行jUnit测试:

String number = invoiceNumberService.nextInvoiceNumber();

并且invoiceNumberService方法是:

InvoiceNumber invoiceNumber = invoiceNumberRepository.findOne(1L);

使用简单的Spring Data Repository方法,它正常运作。但当我重写这个方法来使用锁定时:

@Lock(LockModeType.PESSIMISTIC_READ)
@Override
InvoiceNumber findOne(Long id);

我遇到了"javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction"错误。

我无法理解为什么会出现乐观锁异常,因为我正在使用悲观锁定?还有,在哪里发生了另一个事务更改此实体的情况?我已经查找了很多类似的问题,但仍然感到绝望。谢谢任何帮助。

解决方案:
问题出在我的测试类的init函数中:

@Before
public void init() {
    InvoiceNumber invoiceNumber = new InvoiceNumber(1);
    em.persist(invoiceNumber);
    em.flush();
}

缺乏了

em.flush();

将数据保存到数据库中,这样findOne()函数现在就可以检索到它了。


我遇到了相同的问题和解决方案。对我来说,这似乎是一个Hibernate没有自动刷新的错误。 - gnomie
2个回答

0
仅为了这个目的,我将发布以下内容,如果有人不同意,请纠正我。通常在Java中,建议使用Spring/hibernate和JPA。Hibernate实现了JPA,因此您需要Spring和Hibernate的依赖项。
接下来让Spring/hibernate管理您的事务和提交部分。自己刷新/提交数据是不好的做法。
例如,假设以下方法:
public void changeName(long id, String newName) {
   CustomEntity entity = dao.find(id);
   entity.setName(newName);
}

在调用这个方法后什么都不会发生(你可以调用merge和commit)。但是如果你使用@Transactional进行注解,你的实体将被管理,并且在@Transactional方法结束时,Spring/hibernate将提交你的更改。所以这就足够了:

@Transactional
public void changeName(long id, String newName) {
   CustomEntity entity = dao.find(id);
   entity.setName(newName);
}

不需要调用flush,Spring/Hibernate会为您处理所有的混乱。只是不要忘记您的测试必须调用@Transactional方法,或者本身就应该是@Transactional。


0
问题:您是否在DAO或服务层中使用了@transcational注释? 这是因为两个事务同时尝试更改同一张表的数据而发生的。因此,如果您从DAO层中删除所有注释并将其放入服务层,则应该可以解决此问题,因为我曾经遇到过类似的问题。 希望能有所帮助。

你从头到尾读了这个问题吗?楼主错误地在问题本身中发布了答案,而不是作为答案。 - BalusC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接