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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/811845/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:45:13  来源:igfitidea点击:

Setting a JPA timestamp column to be generated by the database?

javajpapersistenceannotationstimestamp

提问by James McMahon

In my SQL Server 2000 database, I have a timestamp (in function not in data type) column of type DATETIMEnamed lastTouchedset to getdate()as its default value/binding.

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

I am using the Netbeans 6.5 generated JPA entity classes, and have this in my code

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

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

However when I try to put the object into the database I get,

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

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

I've tried setting setting the @Basicto (optional = true), but that throws an exception saying the database doesn't allow nullvalues for the TIMESTAMPcolumn, which it doesn't by design.

我试过将设置设置@Basic(optional = true),但这会引发一个异常,指出数据库不允许列的nullTIMESTAMP,这不是设计的。

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

I previously got this to work in pure Hibernate, but I have sense switched over to JPA and have no idea how to tell it that this column is suppose to be generated on the database side. Note that I am still using Hibernate as my JPA persistence layer.

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

采纳答案by James McMahon

I fixed the issue by changing the code to

我通过将代码更改为

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

So the timestamp column is ignored when generating SQL inserts. Not sure if this is the best way to go about this. Feedback is welcome.

因此在生成 SQL 插入时忽略时间戳列。不确定这是否是解决此问题的最佳方法。欢迎反馈。

回答by Matt Luongo

I realize this is a bit late, but I've had success with annotating a timestamp column with

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

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

This should also work with CURRENT_DATEand CURRENT_TIME. I'm using JPA/Hibernate with Oracle, so YMMV.

这也应该适用于CURRENT_DATECURRENT_TIME。我在 Oracle 中使用 JPA/Hibernate,所以 YMMV。

回答by willtardy

I have this working well using JPA2.0 and MySQL 5.5.10, for cases where I only care about the last time the row was modified. MySQL will create a timestamp on first insertion, and every time UPDATE is called on the row. (NOTE: this will be problematic if I cared whether or not the UPDATE actually made a change).

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

The "timestamp" column in this example is like a "last-touched" column.x`

此示例中的“时间戳”列就像“最后触摸”列.x`

The code below uses a separate column "version" for optimistic 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;
}

(NOTE: @Version doesn't work on a MySQL "DATETIME" column, where the attribute type is "Date" in the Entity class. This was because Date was generating a value down to the millisecond, however MySQL was not storing the millisecond, so when it did a comparison between what was in the database, and the "attached" entity, it thought they had different version numbers)

(注意:@Version 不适用于 MySQL 的“DATETIME”列,其中实体类中的属性类型为“Date”。这是因为 Date 生成了一个精确到毫秒的值,但是 MySQL 没有存储毫秒,所以当它比较数据库中的内容和“附加”实体时,它认为它们有不同的版本号)

From the MySQL manual regarding TIMESTAMP:

从关于 TIMESTAMP 的 MySQL 手册

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

回答by GlenPeterson

I do not think that every database has auto-update timestamps (e.g. Postgres). So I've decided to update this field manually everywhere in my code. This will work with every database:

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

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

There are reasons to use triggers, but for most projects, this is not one of them. Triggers dig you even deeper into a specific database implementation.

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

MySQL 5.6.28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66) seems to be very forgiving, not requiring anything beyond

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-Bit 1.8.0_72) only works with

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

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

not:

不是:

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

My other system info (identical in both environments)

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

  • hibernate-entitymanager 5.0.2
  • hibernate-validator 5.2.2
  • mysql-connector-java 5.1.38
  • 休眠实体管理器 5.0.2
  • 休眠验证器 5.2.2
  • mysql-connector-java 5.1.38

回答by maximus

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

this worked for me. more info

这对我有用。 更多信息

回答by immanuelRocha

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

回答by Nithin Poosarla

This worked for me:

这对我有用:

@Column(name = "transactionCreatedDate", nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")

回答by Dhwanil Patel

@CreationTimestamp
@Column(name="timestamp", nullable = false, updatable = false, insertable = false)
private Timestamp timestamp;

回答by ponder275

If you mark your entity with @DynamicInserte.g.

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

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

Hibernate will generate SQL without nullvalues. Then the database will insert its own default value. This does have performance implications See [Dynamic Insert][1].

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

回答by Mandeep Singh Gill

This also works for me:-

这也适用于我:-

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