Hibernate / JPA @Version和@Generated导致StaleObjectStateException

时间:2012-03-20 15:45:19

标签: hibernate jpa jpa-2.0 optimistic-locking staleobjectstate

使用Hibernate 4.1.0提供的Spring 3.1 / JPA 2。

我的所有实体都有一个基类,它提供基本的审计功能(更新时间戳,版本号等)。因为其他应用程序访问我们的数据库,所以必须通过Trigger设置这些。

我的映射如下:

public abstract class AbstractBaseModel implements Serializable {

@Version
@Generated(GenerationTime.ALWAYS)
@Column(name = "VERSION", insertable = false, updatable = false)
protected Long version;

@Generated(GenerationTime.ALWAYS)
@Column(name = "UPDATE_TIMESTAMP", insertable = false, updatable = false)
protected Date updateDate;
...
}

提交事务时始终会调用org.hibernate.engine.internal.increment(...)方法 - 并产生StaleObjectStateException

如果我在版本列上设置GenerationTime.NEVER,奇怪的是,hibernate仍然会增加版本,但会保持正常。问题是,即使数据库中的版本没有得到更新(例如表中没有更改),从合并返回的版本将比数据库值高1,这显然会导致后续保存问题。

我的期望是GenerationTime.ALWAYS会告诉hibernate永远不会尝试增加版本并依赖数据库这样做,然后在插入/更新后选择更新的值。

有人能告诉我在理解和实施方面出了什么问题吗?

2 个答案:

答案 0 :(得分:0)

我对您的实际问题没有答案,但我确实为您的问题找到了解决方案。 :)

在Hibernate中,这样做完全有效:

@Version
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "UPDATE_TIMESTAMP"
private Date updateDate;

这也会使您的更新日期成为您的版本。这对于实体上的每次合并都更精简并自动更新。

顺便说一下:我建议将会员设为私人,并在课堂上添加get课程和set课程。

答案 1 :(得分:0)

您可以通过在SQL列定义和实体映射中指定以下内容来使用DB进行此操作。以下示例适用于MySQL:

didSelectItem

在代码中:

create table if not exists table_name (
    ...
    modified timestamp default current_timestamp on update current_timestamp not null,
    ...
);