2009-05-01 6 views
43

In meiner SQL Server 2000-Datenbank habe ich eine Zeitmarke (in Funktion, nicht im Datentyp) Spalte des Typs mit dem Namen lastTouched als Standardwert/Bindung auf getdate() festgelegt.Einstellen einer JPA-Zeitstempelspalte, die von der Datenbank generiert werden soll?

Ich verwende die Netbeans 6.5 JPA Entitätsklassen erzeugt, und haben dies in meinem Code

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

Allerdings, wenn ich versuchen, das Objekt in die Datenbank habe ich bekommen,

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

I habe versucht Einstellung @Basic auf zu setzen, aber das wirft eine Ausnahme, die besagt, dass die Datenbank keine null Werte für die TIMESTAMP Spalte zulässt, die es nicht von Entwurf macht.

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

Ich habe vorher diese in reinen Hibernate zu arbeiten, aber ich habe zu JPA Sinn umgeschaltet und haben keine Ahnung, wie es zu sagen, dass diese Spalte auf der Seite Datenbank erzeugt werden annehmen wird. Beachten Sie, dass ich immer noch Hibernate als meine JPA-Persistenzschicht verwende.

Antwort

42

fixiert ich das Problem, indem Sie den Code zu

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

So ist die Timestamp-Spalte wird ignoriert, wenn SQL-Einsätze zu erzeugen. Ich bin mir nicht sicher, ob dies der beste Weg ist. Feedback ist willkommen.

+5

Sie können auch @Column (name = "LastTouched", einführbar = false, aktualisierbare = false) hinzufügen Datenbank Zeitstempel erzeugt auch Anweisungen mit SQL UPDATE zu verwenden. –

+0

Danke Juha. Ich bin sicher, das hätte mich später auf der Straße durcheinander gebracht. –

+0

Eigentlich denke ich darüber nach, ich werde die Spalte Update benötigen, da ich sie über Java aktualisieren muss, wenn ich Spaltenänderungen mache. Es sei denn, es gibt eine Möglichkeit, die Spaltenaktualisierung auf der Datenbankseite irgendwie durchzuführen. –

27

Ich weiß, das ein bisschen spät, aber ich habe Erfolg gehabt mit einer Timestamp-Spalte mit

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

Dies sollte auch mit CURRENT_DATE und CURRENT_TIME arbeitet. Ich verwende JPA/Hibernate mit Oracle, also YMMV.

+5

Das hat für uns funktioniert! Wir haben es mit 'insertable = false, updatable = false' kombiniert –

+0

' FEHLER 4371 --- [main] org.hibernate.tool.hbm2ddl.SchemaExport: Sie haben einen Fehler in Ihrer SQL-Syntax; Überprüfen Sie das Handbuch, das Ihrer MySQL-Server-Version entspricht, damit die richtige Syntax in der Nähe von "TIMESTAMP DEFAULT CURRENT_TIMESTAMP" nicht null ist, "full_content" longtext nicht null bei Zeile 1. Meine Spalte ist: '@Column (nullable = false, Name =" created_at ", aktualisierbar = false, columnDefinition =" TIMESTAMP DEFAULT CURRENT_TIMESTAMP ")' und 'private Timestamp createdAt;' –

3

Ich habe dies funktioniert gut mit JPA2.0 und MySQL 5.5.10, für Fälle, in denen ich nur das letzte Mal interessiert, die Zeile geändert wurde. MySQL erstellt einen Zeitstempel beim ersten Einfügen und jedes Mal, wenn UPDATE in der Zeile aufgerufen wird. (HINWEIS: Das wird problematisch, wenn es mich interessiert, ob das UPDATE tatsächlich eine Änderung vorgenommen hat oder nicht).

Der „Zeitstempel“ -Spalte in diesem Beispiel ist wie ein „letzter berührt“ column.x`

Der folgende Code verwendet eine separate Spalte „Version“ für die optimistische Sperren.

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

(HINWEIS:. @Version funktioniert nicht auf einer MySQL „DATETIME-“ Spalte, wo der Attributtyp „Date“ in der Entity-Klasse ist dafür war, dass Datum wurde einen Wert bis auf die Millisekunde zu erzeugen, aber MySQL nicht die Millisekunde zu speichern, so dass, wenn es einen Vergleich zwischen tat, was in der Datenbank war, und die „angehängt“ Einheit, sie dachten, dass sie unterschiedliche Versionsnummern)

From the MySQL manual regarding TIMESTAMP hatten:

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

I funktioniert das gut mit JPA 2.0 und MyS QL 5.5.10.

eingefügt ich ein Timesamp Feld wie folgt aus:

@Column(name = "LastTouched") 
private Timestamp lastTouched; 
2

Ich glaube nicht, dass jede Datenbank Auto-Update-Zeitstempel (z Postgres) hat. Also habe ich beschlossen, dieses Feld überall in meinem Code manuell zu aktualisieren. Dies wird mit jeder Datenbank arbeiten:

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

Es gibt Gründe, Auslöser zu verwenden, aber für die meisten Projekte, das ist nicht einer von ihnen. Auslöser greifen Sie noch tiefer in eine bestimmte Datenbankimplementierung ein.

MySQL 5.6 .28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66) scheint sehr nachsichtig zu sein, nicht erfordert etwas über

@Column(name="LastTouched") 

MySQL 5.7 0,9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) funktioniert nur mit

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

nicht:

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

Mein anderes System info (identisch in beiden Umgebungen)

  • Hibernate-EntityManager 5.0.2
  • Hibernate-Validator 5.2.2
  • mysql-connector-java 5.1.38
+0

Sehr hilfreiche Informationen, danke - ich stelle mir eine Menge vor Leute werden von diesem Upgrade auf MySQL 5.7.x – James

+0

@James gebissen werden - danke, aber ich habe nur die Unterschiede aufgelistet, die ich kannte. Ich weiß nicht genau, was der entscheidende Unterschied ist. Es könnte etwas ganz anderes sein. Hoffentlich kann jemand anderes auf diese Antwort aufbauen. – GlenPeterson

+1

Ja Entschuldigung, ich hätte hinzufügen sollen, dass ich diesen Fehler nach dem Upgrade von MySQL 5.6 auf 5.7 unter Ubuntu 14.04.1 (OS und JDK wurden nicht AFAIK geändert). Daher ging ich davon aus, dass die MySQL-Version hier der entscheidende Faktor war. – James

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

das funktionierte für mich. more info