如何在JPA中为相关实体正确实现乐观锁定

时间:2014-08-15 16:06:09

标签: java database hibernate jpa locking

以下是我的数据模型的简化版本:

@Entity
@Table(name = "DATA_TABLE")
public class DataTable implements Serializable {
    @Id
    @Column(name = "DATA_TABLE_ID")
    private int dataTableId;

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

    @OneToMany(mappedBy = "dataTableId", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Row> rows;

    @Version
    @Column(name = "VERSION")
    private long version;
}

@Entity
@Table(name = "ROW")
public class Row implements Serializable {
    @Id
    @Column(name = "ROW_ID")
    private int rowId;

    @ManyToOne
    @JoinColumn(name = "DATA_TABLE_ID")
    private DataTable dataTable;

    @OneToMany(mappedBy = "dataTableId", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Row> rows;
}

@Entity
@Table(name = "CELL")
public class Cell implements Serializable {
    @Id
    @Column(name = "CELL_ID")
    private int cellId;

    @ManyToOne
    @JoinColumn(name = "ROW_ID")
    private Row row;

    @Column(name = "TEXT")
    private String text;
}

我需要为与现有系统兼容的模型实现乐观锁定。 在其中,DataTable的版本被发送给服务的用户,他们必须将它与他们执行的acion一起发回,这用于验证同时没有变化。只要属于该特定DataTable的Row或Cell发生更改,就会更新版本字段。

不幸的是,这似乎不适用于JPA @Version注释(Hibernate 4.1.9)。当version表中保留的属性发生更改时,DATA_TABLE字段会更新,例如title,但更改/添加行和单元格不会增加version值。

有没有办法在JPA中通过@Version或其他一些机制(expicit locking?)来实现这个功能,以防止Time of check to time of use之类的并发错误?

2 个答案:

答案 0 :(得分:1)

我认为这是因为您要映射的字段是原始类型(long)。您应该使用包装类型Long代替。

答案 1 :(得分:1)

JPA维护每个实体对象的版本号。新实体对象的初始版本(当它第一次存储在数据库中时)是1.在每个修改实体对象的事务中,其版本号自动增加1。版本号在内部进行管理,但可以通过定义版本字段来公开。

在提交(和刷新)期间,JPA会检查每个必须更新或删除的数据库对象,并将数据库中该对象的版本号与正在更新的内存中对象的版本号进行比较。如果版本号不匹配,则事务失败并抛出OptimisticLockException,表示该对象已被另一个用户(使用另一个EntityManager)修改,因为它是由当前更新程序检索的。

仅当行被更改时才会发生此行为..外键无关紧要因此版本号不会增加。