我正在构建一个新的Web应用程序,我正在使用Spring,JPA / Hibernate和Postgres。我的一些表有creation_ts和lastupdate_ts列,这些列是时间戳列,用于跟踪插入发生的时间以及最后一次更新发生在行上的时间。
我也在我的表中使用列的命名约定,因此在设计策略方面,每个表都保证有两列pkey,它是一个整数代理键,以及用于乐观锁定的版本。
我有两种方法可以保持这些字段的最新状态。
选项A:使用触发器
这是我现在已有的解决方案,我有两个Postgres触发器,可以触发插入和更新,并使这些字段保持最新状态。我有两节课。
@MappedSuperclass
public abstract class PersistableObject
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="pkey")
private Integer pkey;
@Version
@Column(name="version")
private Integer version;
public Integer getPkey()
{
return this.pkey;
}
public Integer getVersion()
{
return this.version;
}
}
我有
@MappedSuperclass
public class TimeStampedPersistableObject extends PersistableObject {
@Column(name = "creation_ts")
@Temporal(TemporalType.DATE)
@org.hibernate.annotations.Generated(value = GenerationTime.INSERT)
private Date creationTimestamp;
@Column(name = "update_ts")
@Temporal(TemporalType.DATE)
@org.hibernate.annotations.Generated(value = GenerationTime.ALWAYS)
private Date updateTimestamp;
public Date getCreationTimestamp()
{
return this.creationTimestamp;
}
public Date getUpdateTimestamp()
{
return this.updateTimestamp;
}
}
选项B:使用JPA听众
在这个选项中,我会使用JPA监听器来使时间戳列保持最新。
我的问题:
这两种方法中的哪一种更好?我在这里看到的是我个人的每个选项的优缺点列表,我非常有兴趣听取其他人选择这两种选择的经验。
选项A专业人士:
选项A缺点:
选项B专业人士:
选项B缺点:
如何为新应用程序解决此问题,您可以完全控制数据库和java代码。
答案 0 :(得分:6)
在插入和更新后必须执行选择以读取触发器所在的值。
您可以使用INSERT ... RETURNING
或UPDATE ... RETURNING
来检索触发器更改的值,因此无需再执行其他SELECT。
除此之外,我会说这取决于你的环境。如果应用程序是关键任务的,并且如果这些列没有正确维护将会失败,那么我会坚持使用触发器。
如果这只是为了方便前端(并且它可以优雅地处理因错误值而导致的冲突),那么JPA方法可能更容易维护。
答案 1 :(得分:2)
我目前正在以下列方式使用选项A(包括所有框架和PostgreSQL):
@Column(insertable = false, updatable = false, nullable = false, columnDefinition = "timestamp without time zone default CURRENT_TIMESTAMP")
@Generated(GenerationTime.INSERT)
public Date getCreatedIn() {
return createdIn;
}
如果使用代码中编写的columnDefinition,则不必再次选择对象,也不必编写任何代码来设置对象上的日期。除了连接Envers框架之外,我从未使用过JPA回调,但我可以说它只是为了在特定对象上设置日期而付出太多努力。
答案 2 :(得分:1)
群集中时钟偏差的危险
我说不要担心。它可能在集群中失败,就像在数据库中失败一样。在适当的生产环境中,您将拥有自己的NTP服务器,并且您的群集将与之同步。
我通常更愿意将所有内容保存在Java中,因为“逻辑”的集中位置是可取的(对我而言)。如果您使用非Java应用程序,则可以在触发器中放置逻辑。