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を使用していることに注意してください。
コードを次のように変更して問題を修正しました
@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が実際に変更を行ったかどうかを気にする場合、これは問題になります)。
この例の「タイムスタンプ」列は、「最後に触れた」列のようなものです。
以下のコードは、楽観的ロックに別の列「バージョン」を使用しています。
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がミリ秒までの値を生成していたためです。 、したがって、データベースにあるものと「アタッチされた」エンティティを比較したとき、バージョン番号が異なると考えられていました)
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)
ではない:
FAILED: removing @Temporal
FAILED: @Column(name="LastTouched", nullable=true)
FAILED: @Column(name="LastTouched", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
私の他のシステム情報(両方の環境で同一)
@Column(name = "LastTouched", insertable = false, updatable = false, columnDefinition = "TIMESTAMP default getdate()")
@Temporal(TemporalType.TIMESTAMP)
private Date LastTouched;`enter code here`