【问题标题】:Triggers versus JPA Event触发器与 JPA 事件
【发布时间】:2012-06-21 10:17:13
【问题描述】:

我正在使用 Spring 3.1.0.RELEASE、JSF 2.x、JPA 2 和 Hibernate Provider、MySql 5.1.x 做一个 Web 应用程序。该应用程序在 Tomcat 7.X 上运行。

在我的实体中,我有一些日期,例如上次更新日期:

@Column(name = "last_update_date", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdateDate;

目前我有一个更新的触发器:

CREATE TRIGGER upd_site BEFORE UPDATE ON site
FOR EACH ROW SET NEW.last_update_date = CURRENT_TIMESTAMP();

它工作正常,但我只是注意到JPA http://www.objectdb.com/java/jpa/persistence/event中有一些回调方法

JPA 事件和 MySql 的触发器之间最好的是什么?

谢谢。

【问题讨论】:

    标签: triggers jpa-2.0


    【解决方案1】:

    没有最好的东西。数据库触发器将在每次更新行时更新最后更新日期,无论使用何种方式更新行(Hibernate、JDBC 查询或数据库管理工具的更新)。仅当使用 JPA 更新行时才会调用 JPA 回调。你可能想要一个或另一个。

    另一个区别是 JPA 不知道数据库执行的触发器。因此,如果您更新实体中的某些字段,并且 JPA 刷新了更改,则触发器将修改更新日期,但 JPA 实体会将更新日期的旧值保留在内存中。所以如果更新后在GUI中显示这个更新日期,那么更新日期是不正确的。您必须刷新实体才能获得最新的更新日期。

    【讨论】:

    • 第2段的注释很有用。
    • 数据库触发器和 JPA 回调方法之间完美简洁的差异集。如果您的用例需要,cron 作业也是一个不错的选择。
    【解决方案2】:

    我在数据库中的触发器和 JPA 侦听器中都使用了它,我选择了 JPA 侦听器,因为:

    • JPA 代码中唯一与数据库通信的代码,因此我不必担心时间戳字段过期。 (如果将来发生变化,我可以添加触发器并更改映射的超级类)

    • JPA 侦听器不那么复杂,因为我不必在我的数据库中创建大量触发器,因此我需要维护的东西更少。由于我正在积极开发和更改数据库结构,因此在我快速迭代开发时不必去更新触发器。

    • 我完全控制了数据库,并为数据库制定了一个规则,即每个表都将有一个整数 pkey 和一个整数版本,并且时间戳表将具有 insert_ts 和 @987654322 @ 列这些是我的数据库设计中的通用规则,所以生活很容易我有这两个映射的超类,它们使我的所有实体都易于编码,因为我从它们扩展而来。

    @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();
        }
    }
    

    和

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

    【讨论】:

    • JPA 事件的唯一问题是如果你想用 SQL 更新数据库怎么办?这将绕过 JPA 事件。通常,数据库应该是自治的,因此 DBA 会告诉您使用触发器。开发人员会更喜欢 JPA 事件。
    • 嘿@MikeArgyriou,我希望你做得很好,你认为理想的情况是什么?与 JPA 回调一起创建触发器?
    猜你喜欢
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 2021-09-07
    • 1970-01-01
    相关资源
    最近更新 更多