我有一个非常强烈的并行更新操作,我试图避免重叠但没有成功。我想问一下是否有人知道为什么这可能会失败。
上下文:Spring Data,JPA实体,同一实体的2个字段通过不同的调用并行更新到同一操作。
以下是代码的一部分:
@Override @PreAuthorize("isAuthenticated()")
@Transactional(readOnly = true)
public void processTransaction(PurchaseTransaction newTransaction)
throws UnableToDetermineCompanyForPurchaseException {
try {
... one slow network i/o operation that takes time
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
...
// Forcing the locks
Company company = companyRepository.findOneAndLockForWrite(company.getId());
if (expirationDate.isAfter(company.getFeatureExpiration(transaction.getFeature()))) {
switch (transaction.getFeature()) {
case IMAGES: company.setImagesFeatureExpiration(expirationDate); break;
case EMPLOYEES: company.setEmployeesFeatureExpiration(expirationDate); break;
default:
throw new RuntimeException("Unexpected feature " + transaction.getFeature());
}
companyRepository.save(company);
...
}
...
}
}
} catch (...) {
...
}
}
具体问题是一个事务来到并更新一个字段(假设例如imagesFeatureExpiration)和紧接在(100ms之后)更新另一个字段的事务(假设例如employeesFeatureExpiration)但是也覆盖了所做的更改通过上一个事务(即覆盖imagesFeatureExpiration保留前一个值)。
目前我转而尝试避免此问题直接更新:
@Modifying
@Query("UPDATE Company c SET c.imagesFeatureExpiration = :expiration WHERE c.id = :id")
void setImagesFeatureExpirationById(@Param("id") long id, @Param("expiration") LocalDateTime expiration);
但仍在考虑为什么会在事务性的实体锁定上下文中发生这种情况,因为其中一个读取应该被另一个读取锁定,以防止这种情况发生。
答案 0 :(得分:0)
我的不好,我在ISOLATION_SERIALIZABLE时设置了ISOLATION_REPEATABLE_READ