データベースによって生成される JPA タイムスタンプ列を設定しますか?
-
03-07-2019 - |
質問
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 に伝える方法がわかりません。JPA 永続層として Hibernate をまだ使用していることに注意してください。
解決
コードを次のように変更して問題を修正しました
@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_DATE
および CURRENT_TIME
でも機能するはずです。 OracleでJPA / Hibernateを使用しているため、YMMVです。
@Column(nullable = false, updatable = false)
@CreationTimestamp
private Date created_at;
これは私にとってはうまくいきました。より詳しい情報
最後に行が変更されたときだけを気にする場合のために、JPA2.0とMySQL 5.5.10を使用してこれがうまく機能しています。 MySQLは最初の挿入でタイムスタンプを作成し、UPDATEが行で呼び出されるたびに作成します。 (注:UPDATEが実際に変更を行ったかどうかを気にする場合、これは問題になります。)
"タイムスタンプ"この例の列は、「ラストタッチ」のようなものです。 column.x`
以下のコードでは、別の列" version"を使用しています。楽観的ロックのため。
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がミリ秒までの値を生成していたためですミリ秒を保存していなかったため、データベースにあるものと「付加された」エンティティとを比較したときに、バージョン番号が異なると考えていました)
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);
トリガーを使用する理由はありますが、ほとんどのプロジェクトでは、これはトリガーの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)
not:
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
@Column(name = "LastTouched", insertable = false, updatable = false, columnDefinition = "TIMESTAMP default getdate()")
@Temporal(TemporalType.TIMESTAMP)
private Date LastTouched;`enter code here`