java - org.springframework.orm.ObjectOptimisticLockingFailureException 乐观锁定失败...行被另一个事务更新或删除
问题描述
此代码返回错误
org.springframework.orm.ObjectOptimisticLockingFailureException:具有标识符 [03555b54-9d67-4990-871f-551f9e7788jj] 的类 [...CRPS] 的对象:乐观锁定失败;嵌套异常是 org.hibernate.StaleObjectStateException:行已被另一个事务更新或删除(或未保存的值映射不正确):[...CRPS#03555b54-9d67-4990-871f-551f9e7788jj]
@Override
@Transactional
public Boolean updatePS(User user, List<PSResponse> request) throws Exception {
log.trace("Entering updatePS!");
try {
CR r = carRRepository.findByUserId(user.getId());
if (r == null) {
throw new HttpException("R not found", HttpStatus.NOT_FOUND);
}
List<CRPS> carRPSs = r.getRPSs();
List<String> toDelete = new LinkedList<>();
for(CRPS carRPS: carRPSs) {
toDelete.add(carRPS.getId());
}
for (PSResponse requestPS: request) {
CRPS existingElement = null;
for(CRPS search: carRPSs) {
if (requestPS.getId()!=null && requestPS.getId().equals(search.getId())) {
existingElement = search;
break;
}
}
CRPS savingPSs = null;
if (existingElement!=null) {
log.trace(String.format("Setting entity attributes for old element: %s !", existingElement.getId()));
toDelete.remove(existingElement.getId());
savingPSs = existingElement;
} else {
log.trace(String.format("Setting entity attributes for new element!"));
savingPSs = new CRPS();
savingPSs.setCR(r);
}
savingPSs.setPrice(requestPS.getPrice());
Re city = null;
if (requestPS.getCityId()!=null) {
city = regencyRepository.getOne(requestPS.getCityId());
}
savingPSs.setCity(city);
savingPSs.setIsAllCity(requestPS.getAllCity());
savingPSs.setIsAllC(requestPS.getAllC());
savingPSs.setStartDate(requestPS.getStartDate());
savingPSs.setEndDate(requestPS.getEndDate());
log.trace(String.format("Setting entity attributes done: %s", savingPSs.getId()));
if (savingPSs.getId() == null) {
savingPSs = this.rPSRepository.save(savingPSs);
log.trace(String.format("Saving new id: %s", savingPSs.getId()));
if (savingPSs == null || savingPSs.getId() == null) {
throw new HttpException("Unable to save entity data!!",
HttpStatus.INTERNAL_SERVER_ERROR);
}
log.trace(String.format("Saved id: %s", savingPSs.getId()));
}
}
for(String toDeleteElementId: toDelete) {
CRPS toDeleteElement = null;
for(CRPS carRPS: r.getRPSs()) {
if(carRPS.getId().equals(toDeleteElementId)) {
toDeleteElement = carRPS;
}
}
log.trace(String.format("Deleting id: %s", toDeleteElementId));
if (toDeleteElement!=null) {
toDeleteElement.setIsDeleted(true);//IF I COMMENT THIS LINE IT WOULD NOT THROW ERROR, WHY AND HOW TO SOLVE IT?
toDeleteElement.getCR().getRPSs().remove(toDeleteElement);
log.trace(String.format("Set isDeleted flag true for id: %s", toDeleteElement.getId()));
}
}
} catch (Exception e) {
log.debug(new StringBuilder().append("Error occurred while updating entity data:").append(
e.getMessage()).toString());
log.debug(e.getMessage(), e);
throw e;
}
log.trace("Leaving updatePS!");
return true;
}
罪魁祸首是,如果我将其注释掉,它将毫无错误地运行,但不会完成应有的工作。
我该如何处理这个问题?
涉及的实体有:
CRPS:
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "rps")
public class CRPS extends BaseEntity {
...
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
public CR carR;
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
public CRC carRC;
@JsonProperty("start_date")
@Column(name = "start_date")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
private Date startDate;
@JsonProperty("end_date")
@Column(name = "end_date")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
private Date endDate;
@Column(name = "price")
private Double price = 0D;
@Column(name = "is_all_car")
private Boolean isAllC;
@Column(name = "is_all_city")
private Boolean isAllCity;
@JsonProperty("city_id")
@ManyToOne(fetch = FetchType.LAZY)
@JsonBackReference
private Re City;
}
关于:
@Getter
@Setter
@Entity
@Table(name = "re")
public class Re extends BaseEntity {
...
}
铬:
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "r")
public class CR extends BaseEntity {
...
@OneToMany(mappedBy = "carR", fetch = FetchType.EAGER)
@OrderBy("startRange")
@Where(clause = "is_deleted=0")
private List<RRF> rF;
@OneToMany(mappedBy = "carR")
@Where(clause = "is_deleted=0")
private List<CRPS> rPS;
...
}
解决方案
The reason behind my getting this error is due to hibernate not checking correctly for null in the version column, in my case the updated_at with type datetime.
Looking at the hibernate trace logs rather than checking with the operator is null it uses the = operator to check for null value, which would return the undesired value that causes the exception to be thrown.
Workaround or maybe rather it's a constraint that must be defined to begin with is to add a not null or a default value.