Triggers versus JPA Event

2019-01-22 07:41发布

问题:

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.

回答1:

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


回答2:

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.