设置由数据库生成的JPA时间戳列?

在我的SQL Server 2000数据库中,我有一个名为lastTouched DATETIMEtypes的时间戳(在函数中不是数据types),其列表名为lastTouched设置为getdate()作为其默认值/绑定。

我正在使用Netbeans 6.5生成的JPA实体类,并在我的代码中

 @Basic(optional = false) @Column(name = "LastTouched") @Temporal(TemporalType.TIMESTAMP) private Date lastTouched; 

但是,当我尝试将对象放入数据库时​​,

 javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.generic.Stuff.lastTouched 

我已经尝试设置@Basic设置为(optional = true) ,但是会引发一个exception,说数据库不允许TIMESTAMP列的null值,而不是按devise。

 ERROR JDBCExceptionReporter - Cannot insert the value NULL into column 'LastTouched', table 'DatabaseName.dbo.Stuff'; column does not allow nulls. INSERT fails. 

我以前得到这个纯Hibernate的工作,但我有感觉切换到JPA,并不知道如何告诉它,这列是假设在数据库端生成。 请注意,我仍然使用Hibernate作为我的JPA持久层。

我通过更改代码来解决问题

 @Basic(optional = false) @Column(name = "LastTouched", insertable = false, updatable = false) @Temporal(TemporalType.TIMESTAMP) private Date lastTouched; 

所以当生成SQL插入时,时间戳列被忽略。 不知道这是否是最好的方式去做这件事。 欢迎反馈。

我意识到这有点迟了,但我已经成功用注释时间戳列

 @Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP") 

这也应该与CURRENT_DATECURRENT_TIME 。 我使用Oracle的JPA / Hibernate,所以YMMV。

我已经使用JPA2.0和MySQL 5.5.10,在我只关心最后一次修改行的情况下工作得很好。 MySQL将在第一次插入时创build一个时间戳,并且每次在该行上调用UPDATE。 (注意:如果我关心UPDATE是否实际发生了变化,这将是有问题的)。

这个例子中的“timestamp”列就像一个“最后一次触摸”的列

下面的代码使用单独的列“版本”进行乐观locking。

 private long version; private Date timeStamp @Version public long getVersion() { return version; } public void setVersion(long version) { this.version = version; } // columnDefinition could simply be = "TIMESTAMP", as the other settings are the MySQL default @Column(name="timeStamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") @Temporal(TemporalType.TIMESTAMP) public Date getTimeStamp() { return timeStamp; } public void setTimeStamp(Date timeStamp) { this.timeStamp = timeStamp; } 

(注意:@版本不适用于实体类中属性types为“Date”的MySQL“DATETIME”列,这是因为Date生成的值是毫秒,但是MySQL不存储毫秒,所以当它在数据库和“附加”实体之间进行比较时,它认为它们具有不同的版本号)

从关于TIMESTAMP的MySQL手册 :

 With neither DEFAULT nor ON UPDATE clauses, it is the same as DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP. 

我不认为每个数据库都有自动更新时间戳(例如Postgres)。 所以我决定在我的代码中手动更新这个字段。 这将适用于每个数据库:

 thingy.setLastTouched(new Date()); HibernateUtil.save(thingy); 

有理由使用触发器,但对于大多数项目,这不是其中之一。 触发器会深入挖掘特定的数据库实现。

MySQL 5.6.28(Ubuntu 15.10,OpenJDK 64位1.8.0_66)似乎是非常宽容的,不需要任何东西

 @Column(name="LastTouched") 

MySQL 5.7.9(CentOS 6,OpenJDK 64位1.8.0_72)只适用于

 @Column(name="LastTouched", insertable=false, updatable=false) 

不:

 FAILED: removing @Temporal FAILED: @Column(name="LastTouched", nullable=true) FAILED: @Column(name="LastTouched", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") 

我的其他系统信息(两个环境相同)

  • hibernate-entitymanager 5.0.2
  • hibernate-validator 5.2.2
  • mysql-connector-java 5.1.38

我有这个使用JPA 2.0和MySQL 5.5.10很好。

我插入了一个Timesamp字段,如下所示:

 @Column(name = "LastTouched") private Timestamp lastTouched;