【问题标题】:How to Sync Entity Bean with Database After Trigger Update如何在触发器更新后将实体 Bean 与数据库同步
【发布时间】:2012-11-03 13:35:31
【问题描述】:

PostgreSQL 9.1
Glassfish 3.1.2.2
火狐 10.0.0.7
Linux

我正在使用 JPA 在 PostgreSQL 中持久化实体。但是,有一个由触发器填充的表(名为 Position),我使用该表的一个实体作为只读的。实体从不将数据持久保存到此表中,因为它是从触发器加载和操作的。我可以将数据加载到我的托管 bean 并查看 Position 表数据。

我的问题是一旦数据库(位置表)被触发器修改了,当再次查询位置表时,值仍然是一样的。 Position 实体仍然包含旧值并且没有重新加载。

这是处理 Position 实体的 bean。我添加了 em.flush() 没有帮助,并且不确定如何以这种方式使用 em.refresh() 。实际上,无论如何,同步将如何提供帮助,因为它不知道我想在没有查询的情况下同步到什么。

非常感谢任何帮助。

EJB ...

@Stateless
public class PositionBean implements IPosition {
    @PersistenceContext(unitName="positionbean-pu")
    private EntityManager em;

    public Position getPositionById(Integer posId) {
        Position pos = null;

        try {
            pos = (Position) em.createNamedQuery("findPosition")
                .setParameter("posId", posId).getSingleResult();
        }
        catch (Exception e) {
            throw new EJBException(e.getMessage());
        }

        return pos;
   }

实体 bean ...

@Entity
@SequenceGenerator(name="posIdGen", initialValue=10000,
    sequenceName="pos_seq", allocationSize=1)
@NamedQuery(name="findPosition",
    query="SELECT p FROM Position p WHERE p.posId = :posId")
@Table(name="Position")
public class Position implements Serializable {
    // ...

persistence.xml

<persistence-unit name="positionbean-pu" transaction-type="JTA">
    <jta-data-source>jdbc/postgreSQLPool</jta-data-source>
</persistence-unit>

【问题讨论】:

    标签: jpa ejb glassfish-3 ejb-3.1 jta


    【解决方案1】:

    如果有人遇到这种情况,我学习了如何使用 refresh() 并解决了我的问题。

            pos = (Position) em.createNamedQuery("findPosition")
                .setParameter("posId", posId).getSingleResult();
    
            em.refresh(pos);
    

    【讨论】:

    • 我假设您使用的是资源本地事务类型。如果您使用 JTA 事务类型,则不需要调用 refresh()。在 JTA 事务中,容器负责刷新持久性上下文。在容器管理的 JTA 事务中,refresh() 将用于丢弃您当前的事务更新并用数据库的新副本覆盖持久性上下文,这是一种完全不同的用法。
    • 这让我很困惑,因为我正在使用 JTA 并且必须添加刷新才能使其正常工作。我在 OP 中添加了我的 persistence.xml 的 sn-p 以显示它的外观。
    • refresh 方法会丢弃当前未完成事务的持久/合并/删除操作的效果,并诉诸数据库最新状态。换句话说,refresh() 将数据库重新复制到 EntityManager 持久性上下文中,并丢弃在当前事务中完成的任何更新,直到调用点。这种情况发生在需要很长时间的事务中,并且您希望优先考虑由其他应用程序更新的数据库的最新状态。
    • 你能发布你需要 refresh() 的整个方法吗?
    • 除了在 try/catch 中并返回位置之外,这实际上就是整个方法。如 OP 中所述,此处没有持久化/合并或删除,该表及其条目是由数据库触发器函数添加的,我唯一要做的就是使用该命名查询读取该表。
    【解决方案2】:

    在我看来,创建“外部”更新的只读实体的正确方法如下:

    1. 通过将注释@Access 设置为AccessType.FIELD(或删除注释,因为它是默认访问类型),对实体类使用基于字段的注释,如this answer 中所述。还建议仅按照this answer 中的说明提出公共吸气剂。这可以防止实体在应用程序中被修改。
    2. persistence.xml 文件中启用选择性共享缓存模式,并将注释@Cacheable(false) 添加到实体类,如this answer 中所述。这会强制 JPA 在您调用 EntityManager#find(...) 时始终从持久层加载实体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-26
      • 1970-01-01
      • 1970-01-01
      • 2017-11-05
      • 2023-02-07
      • 1970-01-01
      相关资源
      最近更新 更多