首页 > 解决方案 > 单线程中的 JPA 乐观锁异常

问题描述

我正在尝试使用 JPA 持久性类更新基本删除时间戳。这是代码:

    public void delete(Document document, EntityManager em, SessionContext ctx)
                throws MyException {
            try {
                ctx.getUserTransaction().begin();
                DocumentDB documentDB = em.find(WDSDocument.class, document.getId());
                if (documentDB != null) {
                    em.lock(documentDB, LockModeType.WRITE);
                    documentDB.setDeletedAt(new Timestamp(System.currentTimeMillis()));
                    em.merge(documentDB);
                    em.flush(); // OptimisticLockException raised here
                }
                ctx.getUserTransaction().commit();
                if (log.isDebugEnabled()) log.debug("DELETED " + document.getId());
            } catch (Exception e) {
                ctx.getUserTransaction().rollback();
                throw new MyException(Utils.getError("ERR9", new String[] { "" + document.getId(), e.getMessage() }),
                        e);
            }
    }

Id与as相同的文档document已存储在数据库中,我想更新单个字段。

em.flush()行引发了异常,好像另一个用户(线程)试图更新同一个对象,但在我的应用程序中并非如此。

OptimisticLockException在 JPA 中阅读过,并且我知道当同一个用户尝试连续两次更新对象而不首先刷新/提交到数据库时,可以引发它。

显然,每当我尝试更新documentDB任何对象的删除时间戳时都会发生此错误,因此我想我的方法应该存在固有的错误,delete()即双重更新对象本身。到目前为止,我无法正确排除故障。

已编辑

这是我的DocumentDB

@Entity
@Table(name = "DOCUMENTS", schema = "WP")
public class DocumentDB extends AbstractEntity {
    private static final long serialVersionUID = -98765134L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID_DOCUMENT", nullable = false)
    private int id;

    @Column(name = "SOURCE")
    private String source = null;

    @Column(name = "CREATION_DATE")
    private Date creationDate;

    @Column(name = "TITLE")
    private String title = null;

    @Column(name = "AUTHOR")
    private String author = null;

    @Column(name = "URL")
    private String url = null;

    @Column(name = "DELETED_AT")
    private Timestamp deletedAt = null;

    @Override
    public Integer getId() {
        return id;
    }

    @Override
    public void setId(int id) {
        this.id = id;
    }


    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Timestamp getDeletedAt() {
        return deletedAt;
    }

    public void setDeletedAt(Timestamp deletedAt) {
        this.deletedAt = deletedAt;
    }
}

虽然它的抽象超类是:

@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
    private static final long serialVersionUID = -98765134L;

    public abstract Integer getId();
    public abstract void setId(int id);

    /**
     * Creator of the record
     */
    @Column(name = "USER_CREATION", nullable = false)
    protected String userCreation;

    /**
     * Timestamp of creation of the record
     */
    @Column(name = "DATE_CREATION", nullable = false)
    protected Timestamp dateCreation;

    /**
     * User of the last change of the record
     */
    @Column(name = "USER_LAST_CHANGE", nullable = false)
    protected String userLastChange;

    /**
     * Timestamp of the last change of the record
     */
    @Column(name = "DATE_LAST_CHANGE", nullable = false)
    protected Timestamp dateLastChange;

    /**
     * Progressive of the variation of the record: 
     * used in optimistic locking of entity manager 
     * to avoid conflicts in insert/update
     */
    @Version
    @Column(name = "PG_VER_REC", nullable = false)
    protected int progressiveVariationRecord;

    public String getUserCreation() {
        return userCreation;
    }
    public void setUserCreation(String userCreation) {
        this.userCreation = userCreation;
    }
    public Timestamp getDateCreation() {
        return dateCreation;
    }
    public void setDateCreation(Timestamp dateCreation) {
        this.dateCreation = dateCreation;
    }
    public String getUserLastChange() {
        return userLastChange;
    }
    public void setUserLastChange(String userLastChange) {
        this.userLastChange = userLastChange;
    }
    public Timestamp getDateLastChange() {
        return dateLastChange;
    }
    public void setDateLastChange(Timestamp dateLastChange) {
        this.dateLastChange = dateLastChange;
    }
    public int getProgressiveVariationRecord() {
        return progressiveVariationRecord;
    }
    public void setProgressiveVariationRecord(int progressiveVariationRecord) {
        this.progressiveVariationRecord = progressiveVariationRecord;
    }
}

为了更好地理解这个问题,您能否提供一些关于接下来要执行的步骤的指导?

更新

到目前为止,我还没有找到问题的根本原因。我怀疑我的 EclipseLink JPA 实现在更新 for 循环中的实体时会做一些奇怪的事情。

不幸的是,目前我没有时间和资源来深入挖掘,我正在使用悲观锁定作为解决方法。希望以后能找到真正的问题。

标签: javajpaoptimistic-locking

解决方案


推荐阅读