2009-05-01 33 views
43

Trong cơ sở dữ liệu SQL Server 2000 của tôi, tôi có cột dấu thời gian (trong hàm không có trong kiểu dữ liệu) thuộc loại DATETIME có tên lastTouched đặt thành getdate() làm giá trị/ràng buộc mặc định của nó.Đặt cột dấu thời gian JPA được cơ sở dữ liệu tạo ra?

Tôi đang sử dụng Netbeans 6.5 tạo ra các lớp thực thể JPA, và có điều này trong mã của tôi

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

Tuy nhiên khi tôi cố gắng để đưa các đối tượng vào cơ sở dữ liệu tôi nhận được,

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

tôi đã cố gắng thiết lập thiết lập @Basic thành (optional = true), nhưng điều đó cho phép ngoại lệ nói rằng cơ sở dữ liệu không cho phép các giá trị null cho cột TIMESTAMP, mà nó không theo thiết kế.

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

trước đây tôi đã làm việc này trong Hibernate tinh khiết, nhưng tôi đã cảm giác chuyển sang JPA và không có ý tưởng làm thế nào để nói với nó rằng cột này là giả sử để được tạo ra về phía cơ sở dữ liệu. Lưu ý rằng tôi vẫn đang sử dụng Hibernate làm lớp kiên trì JPA của tôi.

Trả lời

42

Tôi cố định vấn đề này bằng cách thay đổi mã để

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

Vì vậy, các cột timestamp bị bỏ qua khi tạo chèn SQL. Không chắc chắn nếu đây là cách tốt nhất để đi về điều này. Phản hồi được hoan nghênh.

+5

Bạn cũng có thể muốn thêm @column (name = "LastTouched", insertable = false, có thể cập nhật = false) sử dụng cơ sở dữ liệu được tạo ra timestamps cũng với câu lệnh SQL UPDATE. –

+0

Cảm ơn Juha. Tôi chắc rằng điều đó sẽ làm tôi rối tung sau đó. –

+0

Trên thực tế, suy nghĩ về nó nhiều hơn, tôi nghĩ rằng tôi sẽ cần cột cập nhật, vì tôi sẽ cần phải cập nhật nó thông qua Java khi tôi thực hiện thay đổi cột. Trừ khi có một cách để thực hiện cập nhật cột ở phía cơ sở dữ liệu bằng cách nào đó. –

27

Tôi nhận ra điều này là hơi muộn, nhưng tôi đã thành công với chú thích một cột timestamp với

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

này cũng nên làm việc với CURRENT_DATECURRENT_TIME. Tôi đang sử dụng JPA/Hibernate với Oracle, vì vậy YMMV.

+5

Điều này phù hợp với chúng tôi! Chúng tôi kết hợp nó với 'insertable = false, updatable = false' –

+0

' ERROR 4371 --- [main] org.hibernate.tool.hbm2ddl.SchemaExport: Bạn có một lỗi trong cú pháp SQL của bạn; kiểm tra hướng dẫn tương ứng với phiên bản máy chủ MySQL của bạn cho cú pháp đúng để sử dụng gần ''TIMESTAMP DEFAULT CURRENT_TIMESTAMP' không null,' full_content' longtext không null' ở dòng 1'. Cột của tôi là: '@Column (nullable = false, name =" created_at ", updatable = false, columnDefinition =" TIMESTAMP DEFAULT CURRENT_TIMESTAMP ")' và 'dấu thời gian riêng được tạoAt;' –

3

Tôi đã làm việc này tốt bằng cách sử dụng JPA2.0 và MySQL 5.5.10, trong trường hợp tôi chỉ quan tâm đến lần cuối cùng hàng được sửa đổi. MySQL sẽ tạo một dấu thời gian khi chèn lần đầu tiên và mỗi lần UPDATE được gọi trên hàng. (LƯU Ý: điều này sẽ có vấn đề nếu tôi quan tâm hay không CẬP NHẬT thực sự đã thực hiện thay đổi).

Các "dấu thời gian" cột trong dụ này cũng giống như một "cuối cùng xúc động" column.x`

Đoạn code dưới đây sử dụng một cột "phiên bản" riêng cho khóa lạc quan.

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

(Chú ý:. @version không hoạt động trên một MySQL cột "DATETIME", nơi mà các loại thuộc tính là "Ngày" trong lớp Entity này là vì ngày đã tạo ra một giá trị xuống đến phần nghìn giây, Tuy nhiên MySQL đã không lưu trữ phần nghìn giây, vì vậy khi nó đã làm một so sánh giữa những gì là trong cơ sở dữ liệu, và "gắn" thực thể, nó nghĩ rằng họ có số phiên bản khác nhau)

From the MySQL manual regarding TIMESTAMP:

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

tôi làm việc này tốt bằng cách sử dụng JPA 2.0 và MyS QL 5.5.10.

tôi chèn một lĩnh vực Timesamp như thế này:

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

Tôi không nghĩ rằng tất cả các cơ sở dữ liệu có tính năng tự động cập nhật timestamps (ví dụ Postgres). Vì vậy, tôi đã quyết định cập nhật trường này theo cách thủ công ở mọi nơi trong mã của tôi. Điều này sẽ làm việc với mọi cơ sở dữ liệu:

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

Có nhiều lý do để sử dụng trình kích hoạt, nhưng đối với hầu hết các dự án, đây không phải là một trong số chúng. Trình kích hoạt sẽ đào sâu bạn sâu hơn vào một cơ sở dữ liệu cụ thể.

MySQL 5.6 .28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66) có vẻ là rất khoan dung, không đòi hỏi bất cứ điều gì ngoài

@Column(name="LastTouched") 

MySQL 5,7 .9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) chỉ làm việc với

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

không:

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

tôi thông tin khác hệ thống (giống hệt nhau trong cả hai môi trường)

  • hibernate-EntityManager 5.0.2
  • hibernate-validator 5.2.2
  • mysql-connector-java 5.1.38
+0

Thông tin rất hữu ích, cảm ơn - tôi tưởng tượng rất nhiều mọi người sẽ bị cắn bởi nâng cấp này lên MySQL 5.7.x – James

+0

@James - cảm ơn, nhưng tôi chỉ liệt kê những khác biệt mà tôi biết. Tôi không biết chắc chắn sự khác biệt quan trọng là gì. Nó có thể là một cái gì đó hoàn toàn khác. Hy vọng rằng người khác có thể xây dựng trên câu trả lời này. – GlenPeterson

+1

Có lỗi tôi nên có thêm rằng tôi gặp phải lỗi này sau khi nâng cấp từ MySQL 5.6 lên 5.7 trên Ubuntu 14.04.1 (OS và JDK không thay đổi AFAIK). Vì vậy, tôi đã giả định rằng phiên bản MySQL là yếu tố quan trọng ở đây. – James

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

làm việc này cho tôi. more info

Các vấn đề liên quan