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


70

在我的SQL Server 2000数据库中,我有一个DATETIME名称类型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

我尝试过将@Basicto设置为(optional = true),但这引发了一个异常,说数据库不允许nullTIMESTAMP列的值,而这是设计不允许的。

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持久层。

Answers:


58

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

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

因此,在生成SQL插入时,将忽略timestamp列。不知道这是否是解决此问题的最佳方法。欢迎反馈。


实际上,考虑得更多,我认为我将需要有关更新的专栏,因为当我进行列更改时,我将需要通过Java更新它。除非有办法以某种方式在数据库端进行列更新。
詹姆斯·麦克马洪

1
根据stackoverflow.com/questions/36001/…的说明,触发器是我在此处应使用的触发器。
詹姆斯·麦克马洪

对于LocalDateTime等其他类型呢?通过这种解决方案,我得到了Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: @Temporal should only be set on a java.util.Date or java.util.Calendar
emecas '20

46

我意识到这有点晚了,但是我已经成功地用

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

这也应与CURRENT_DATE和一起使用CURRENT_TIME。我在Oracle中使用JPA / Hibernate,所以是YMMV。


7
这对我们有用!我们将其与insertable=false, updatable=false
Shervin Asgari

ERROR 4371 --- [ main] org.hibernate.tool.hbm2ddl.SchemaExport : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'full_content第1行. My column is: @Column的TIMESTAMP DEFAULT CURRENT_TIMESTAMP`不为空,长文本不为null' @Column(nullable = false,name =“ created_at”,可更新= false,columnDefinition =“ TIMESTAMP DEFAULT CURRENT_TIMESTAMP”)`private Timestamp createdAt;
e-info128

1
这是一个简短而甜蜜的解决方案。谢谢
Vimukthi Sineth '20

15
@Column(nullable = false, updatable = false)
@CreationTimestamp
private Date created_at;

这对我有用。 更多信息



4

对于只关心最后一次修改该行的情况,我可以使用JPA2.0和MySQL 5.5.10很好地工作。MySQL将在首次插入时创建时间戳,并且每次在该行上调用UPDATE时都会创建一个时间戳。(注意:如果我关心UPDATE是否确实进行了更改,这将是有问题的)。

在此示例中,“时间戳”列类似于“最后接触”列。

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

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;
}

(注意:@Version在Entity类的属性类型为“ 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.

4

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

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

有使用触发器的原因,但是对于大多数项目来说,这不是其中之一。触发器将使您更深入地了解特定的数据库实现。

MySQL 5.6 .28(Ubuntu 15.10,OpenJDK 64-Bit 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")

我的其他系统信息(在两种环境中均相同)

  • 休眠实体管理员5.0.2
  • 休眠验证器5.2.2
  • MySQL的连接器的Java 5.1.38

非常有用的信息,谢谢-我想很多人会因为这次升级到MySQL 5.7.x而被咬
James

@James-谢谢,但是我只列出了我所知道的区别。我不确定关键的区别是什么。可能完全是另外一回事。希望其他人可以基于此答案。
GlenPeterson '16

1
是的,对不起,我应该补充说,在Ubuntu 14.04.1上从MySQL 5.6升级到5.7后,我遇到了此错误(OS和JDK的AFAIK均未更改)。所以我以为MySQL版本是这里的关键因素。
詹姆斯,

1
@James-哇,这真的很有用。谢谢!我已经更新了我的答案以反映这一点。
GlenPeterson

3

如果您用@DynamicInsert例如标记您的实体

@Entity
@DynamicInsert
@Table(name = "TABLE_NAME")
public class ClassName implements Serializable  {

Hibernate将生成没有null值的SQL 。然后数据库将插入其自己的默认值。这确实会对性能产生影响,请参见[动态插入] [1]。


3

我将其发布给那些在使用MySQL和Java Spring Boot JPA时寻找答案的人,就像@immanuelRocha所说,在Spring中也只有@CreationTimeStamp到@Column,并且在MySQL中将默认值设置为“ CURRENT_TIMESTAMP”。

在Spring中,仅添加以下行:

@Column(name = "insert_date")
@CreationTimestamp
private Timestamp insert_date;


2

这也对我有用:

@Temporal(TemporalType.TIMESTAMP)   
@Column(name = "CREATE_DATE_TIME", nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
public Date getCreateDateTime() {
    return createDateTime;
}

public void setCreateDateTime(Date createDateTime) {
    this.createDateTime = createDateTime;
}

1

如果您正在使用Java 8和Hibernate 5或Spring Boot JPA进行开发,请直接在Entity类中使用以下注释。Hibernate从VM获取当前时间戳,并将日期和时间插入数据库。

public class YourEntity {
 
    @Id
    @GeneratedValue
    private Long id;
 
    private String name;
 
    @CreationTimestamp
    private LocalDateTime createdDateTime;
 
    @UpdateTimestamp
    private LocalDateTime updatedDateTime;
 
    …
}

0
@Column(name = "LastTouched", insertable = false, updatable = false, columnDefinition = "TIMESTAMP default getdate()")
@Temporal(TemporalType.TIMESTAMP)
private Date LastTouched;`enter code here`

-1

这对我有用:

@Column(name = "transactionCreatedDate", nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.