【问题标题】:Do Jpa& Hibernate load data which changes asynchronously in DB?Jpa& Hibernate 会加载数据库中异步更改的数据吗?
【发布时间】:2016-12-25 15:26:36
【问题描述】:

我有一个 oracle 视图,可以在其中查询我的数据库。

create or replace view my_view as
Select cc.CCID ccid
       sm.SMCODE smcode,
       NVL(sm.smname, cc.ccname) sname
  From CC cc
 Inner Join SM sm
    On cc.id = sm.id;

我使用jpa 2.1hibernate 4.3.7 将我的视图映射到我的实体。 我的实体类如下所示:

public class CCRequest implements Serializable {

    private static final long serialVersionUID = 1L;

    private String ccId;

    private String smCode;

    private String sName;
}

我的映射 xml 看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
                 version="2.1">
    <entity class="CCRequest" name="CCRequest001">
        <table name="my_view"/>
        <attributes>
            <id name="ccId">
                <column name="ccid"/>
            </id>
            <basic name="smCode">
                <column name="smcode"/>
            </basic>
            <basic name="sName">
                <column name="sname"/>
            </basic>
        </attributes>
    </entity>
</entity-mappings> 

所以我用 jpa 正确查询了我的实体,它返回了我的所有记录。 这是问题所在,当我异步更改数据库中的数据时,令人震惊的是,我的 jpa 查询返回了以前的记录。 我是不是做错了什么?

【问题讨论】:

  • 1.您是直接更改数据库中的数据还是通过 JPA/Hibernate 方法更改数据? - Hibernate 缓存以前的结果,因此如果您直接修改数据,则在清除缓存之前您不会看到更改。 2. 如果您使用 JPA/Hibernate 更改数据 - 您是否刷新/提交它们? 3.这也可能取决于你如何管理EntityManager或Session。
  • 我直接改数据。但是在我的应用程序中,除了我的 JPA/Hibernate 方法之外,还有可能以其他方式更改数据。这里的解决方案是什么。你说这取决于我如何管理 EntityManage 是什么意思?

标签: java spring hibernate jpa sql-view


【解决方案1】:

不那么令人震惊的是,JPA 对更新数据库的其他进程没有先见之明,这怎么可能呢? 你是唯一知道这一点的人,所以必须使用

em.refresh(obj)

如果您知道数据已(可能)更改,则更新对象。

【讨论】:

  • 但我认为当我执行查询时,它应该在 db 上运行并从 db 中获取结果。
  • 一个查询在DB上运行清晰,发出的SQL会在日志中。但它只会显示适合事务隔离的数据。只有您知道您的对象何时被外部更新/添加,以及 txn 隔离是否是一个因素。此外,JPA 的 L1/L2 缓存不了解外部进程,因此如果外部发生更改,它们将需要驱逐对象。
  • 在像2个带有db共享机制的应用程序jpa这样的情况下,jpa不是解决方案,因为每次需要执行查询时都可能发生外部更改,所以应该清楚chache。我说的对吗?
  • 如前所述,JPA 没有了解这些外部更改的机制,仅用于持久化和查询数据存储。提供检测外部变化的机制留给应用程序员,并根据需要使用 evict 等
【解决方案2】:

Hibernate 缓存以前的结果,因此您应该使用entityManager.clear() 来清理关联的缓存。它将强制再次执行查询。相关线程了解更多详情:

有关 Hibernate 缓存的更多信息:

另一种选择是使用entityManager.refresh(obj) 将数据库数据与会话数据同步。

【讨论】:

  • 你能给我一份关于这种行为的 jpa/hibernate 文档吗?这对我来说似乎有点奇怪。我认为,除非出现一些特殊情况,否则我们经常想要我们的数据库中的内容,不是吗?
  • 更新了更多链接。
  • 我不明白的是,如果它使用缓存数据,它如何理解新插入的数据?在我的情况下,正在加载直接在 db 中的新插入数据。但是没有加载直接更新的数据!!!
【解决方案3】:

我面临的问题是,在 4 年前的春天,我们有 JpaTemplate 用于处理 jpa 实体,我以编程方式将 EntityManagerEntityManagerFactory 的实例传递给 JpaTemplate 的实例@ 没有问题.

JpaTemplate 本身会为刷新EntityManager 和清除缓存做任何事情。 当我迁移到 spring 4 时,我面临 JpaTemplate 已被删除,因此我必须直接使用 EntityManager

我以编程方式从EntityManagerFactory 的实例中获取EntityManager 的实例。

我有一个EntityManagerProvider 类,它从EntityManagerFactory 的实例创建EntityManager 的实例。

public class EntityManagerProvider {

    public static EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.createEntityManager();
    }
}

我得到这样的 entityManager 实例:

<bean id="entityManager" class="com.tosan.novin.sipa.bo.da.jpa.EntityManagerFactoryProvider" factory-method="createEntityManager">
        <constructor-arg index="0" ref="entityManagerFactory"/>
</bean>

但我知道,如果我希望 EntityManager 管理事务并刷新,唯一的方法是使用 @PersistenceContextEntityManager 注入到我的 bean 中。

@PersistenceContext
protected EntityManager em;

我对这种方式有点困惑,但我的问题用这种方法解决了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 2019-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多