首页 > 解决方案 > 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;

    ...
}

标签: javaspringspring-data-jpa

解决方案


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.


推荐阅读