Jpa 如何在触发器更新后将实体Bean与数据库同步

Jpa 如何在触发器更新后将实体Bean与数据库同步,jpa,ejb,glassfish-3,ejb-3.1,jta,Jpa,Ejb,Glassfish 3,Ejb 3.1,Jta,PostgreSQL 9.1 玻璃鱼3.1.2.2 Firefox 10.0.0.7 Linux 我正在使用JPA在PostgreSQL中持久化实体。但是,有一个表(命名位置)由触发器填充,我使用该表的一个实体作为只读。实体从不将数据持久化到此表中,因为它是从触发器加载和操作的。我可以将数据加载到我的托管bean中,并可以很好地查看位置表数据 我遇到的问题是,一旦触发器修改了数据库(位置表),当再次查询位置表时,值仍然相同。Position实体仍然包含旧值,并且没有重新加载 下面是处理Posit

PostgreSQL 9.1
玻璃鱼3.1.2.2
Firefox 10.0.0.7
Linux

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

我遇到的问题是,一旦触发器修改了数据库(位置表),当再次查询位置表时,值仍然相同。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>

jdbc/postgreSQLPool

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

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

        em.refresh(pos);

我认为创建“外部”更新的只读实体的正确方法如下:

  • 请通过将注释
    @Access
    设置为
    AccessType.field
    (或删除注释,因为它是默认的访问类型)为实体类使用基于字段的注释,如中所述。此外,还应仅按照中的说明,提出公共获取者。这可以防止实体在应用程序中被修改
  • persistence.xml
    文件中启用选择性共享缓存模式,并向实体类添加注释
    @Cacheable(false)
    ,如中所述。这迫使JPA在调用
    EntityManager\find(…)
    时总是从持久层加载实体

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