web-dev-qa-db-ja.com

データベースによって生成されるJPAタイムスタンプ列を設定しますか?

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

私は@Basicから(optional = true)が、データベースがnull列のTIMESTAMP値を許可しないという例外をスローしますが、これは仕様ではありません。

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

以前はこれを純粋なHibernateで動作するようにしましたが、JPAに切り替えた感覚があり、この列がデータベース側で生成されることを想定する方法がわかりません。 JPAの永続化レイヤーとしてまだHibernateを使用していることに注意してください。

54
James McMahon

コードを次のように変更して問題を修正しました

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

そのため、SQL挿入の生成時にタイムスタンプ列は無視されます。これが最善の方法であるかどうかはわかりません。フィードバックは大歓迎です。

51
James McMahon

私はこれが少し遅いことを理解していますが、タイムスタンプ列に注釈を付けることで成功しました

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

これは、CURRENT_DATEおよびCURRENT_TIMEでも機能するはずです。 OracleでJPA/Hibernateを使用しているため、YMMVです。

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

これは私のために働いた。 詳細

6
maximus

最後に行が変更されたときだけを気にする場合のために、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は、MySQLの「DATETIME」列では機能しません。属性タイプはEntityクラスの「Date」です。これは、Dateがミリ秒までの値を生成していたためです。 、したがって、データベースにあるものと「アタッチされた」エンティティを比較したとき、バージョン番号が異なると考えられていました)

TIMESTAMPに関するMySQLマニュアルから

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

すべてのデータベースに自動更新タイムスタンプがあるとは思いません(例:Postgres)。そのため、このフィールドはコードのどこでも手動で更新することにしました。これはすべてのデータベースで動作します:

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

トリガーを使用する理由はありますが、ほとんどのプロジェクトでは、これはそれらの1つではありません。トリガー特定のデータベース実装をさらに深く掘り下げます。

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)は、

@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
4
GlenPeterson
@Column(name = "LastTouched", insertable = false, updatable = false, columnDefinition = "TIMESTAMP default getdate()")
@Temporal(TemporalType.TIMESTAMP)
private Date LastTouched;`enter code here`
0
immanuelRocha