I'm doing a Web application using Spring 3.1.0.RELEASE, JSF 2.x, JPA 2 with Hibernate Provider, MySql 5.1.x. The application runs on Tomcat 7.X.
In my entities I have some date like last update date:
@Column(name = "last_update_date", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdateDate;
For the moment I have a trigger that updates:
CREATE TRIGGER upd_site BEFORE UPDATE ON site
FOR EACH ROW SET NEW.last_update_date = CURRENT_TIMESTAMP();
It works fine, but I just notice that there is some callbacks methods in JPA http://www.objectdb.com/java/jpa/persistence/event
What is the best between JPA Events and the MySql's triggers ?
Thanks.
I have used it both ways with Triggers in the DB and with JPA listeners, I have settled on the JPA listeners because:
the only code talking to the database in JPA code so I don't have to worry about the time stamp fields falling out of date. (If this changes in the future I can add triggers and change my mapped super calss)
JPA listeners are less complex in the sense that I did not have to go creating lots of triggers in my database so I had less things to maintain. Since I am actively developing and changing the db structure as I go along its great not to have to go and update triggers as I rapidly iterate through the development.
I have complete control over the database and made a rule for the db that every table was going to have a integer pkey, and an integer version, and that the time stamped tables would have insert_ts
and update_ts
columns these are universal rules in my db design so life is easy I have these two mapped superclases that make all my enitites simple to code since I extend from them.
@MappedSuperclass
public abstract class PersistableObject {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="pkey")
private Integer pkey;
@Version
@Column(name="version")
private Integer version;
public Integer getPkey() {
return this.pkey;
}
public Integer getVersion() {
return this.version;
}
@Override
public String toString() {
return "Presistable Object: pkey=" + this.pkey + " Object: " + this.getClass().getName();
}
}
and
@MappedSuperclass
public class TimeStampedPersistableObject extends PersistableObject {
@Column(name = "insert_ts")
@Temporal(TemporalType.TIMESTAMP)
private Date insertTimestamp;
@Column(name = "update_ts")
@Temporal(TemporalType.TIMESTAMP)
private Date updateTimestamp;
@SuppressWarnings("unused")
@PrePersist
private void onInsert() {
this.insertTimestamp = new Date();
this.updateTimestamp = this.insertTimestamp;
}
@SuppressWarnings("unused")
@PreUpdate
private void onUpdate() {
this.updateTimestamp = new Date();
}
public Date getInsertTimestamp() {
return this.insertTimestamp;
}
public Date getUpdateTimestamp() {
return this.updateTimestamp;
}
}
There is no best thing. A database trigger will update the last update date at every update of a row, whatever the way used to update the row (Hibernate, a JDBC query, or an update from your database admin tool). A JPA callback will only be invoked when the row is updated using JPA. You might want one or the other.
Another difference is that JPA is unaware of the trigger executed by the database. So if you update some field in your entity, and JPA flushed the change, the update date will be modified by the trigger, but the JPA entity will keep the old value of the update date in memory. So if this update date is displayed in the GUI after the update, the update date will be incorrect. You'll have to refresh the entity to get the latest update date.