MySQL 或 Hibernate 缓存问题导致收到旧数据

3

我在更新表格后,过几秒钟再试图获取数据时,仍然会收到旧数据的奇怪问题。当我再次使用相同的查询获取数据时,几秒钟后我会收到刷新后的数据。基本上,我发现它需要一些时间才能返回新鲜的数据。

我已经从Hibernate中禁用了所有缓存,同时在获取数据时,我使用session.clear()并将查询标记为不可缓存。

我还查看了mysql查询日志,并发现Hibernate正在查询mysql,但我收到的是旧数据。

如何确保在任何给定时间点上,我只接收到刷新后的数据?

以下是我的Hibernate配置文件:

<hibernate-configuration>
<session-factory>
    <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>  
    <property name="show_sql">true</property> 

    <property name="connection.url">jdbc:mysql://127.0.0.1:4804/aluminidb?autoReconnect=true</property>  
    <property name="connection.username">root</property>  
    <property name="connection.password">root</property>  
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <!-- Example mapping file inclusion -->

    <property name="hibernate.cache.use_second_level_cache">false</property>
    <property name="hibernate.cache.use_query_cache">false</property>

    <!-- Disable the second-level cache  -->
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> 
    <mapping resource="com/alumini/spring/model/Alumini.hbm.xml"/>
    <mapping resource="com/alumini/spring/model/Question.hbm.xml"/>
    <mapping resource="com/alumini/spring/model/Events.hbm.xml"/>
</session-factory>

以下是获取对象的代码。
@Override
public Alumini login(String email, String password) {
    Session session=sessionFactory.openSession();
    session.clear();
    Transaction t;
    try{
        t=session.beginTransaction(); 
        Query query = session.getNamedQuery("chkLogIn");
        query.setParameter("email",email);
        query.setParameter("password",password);
        query.setCacheMode(CacheMode.REFRESH);
        query.setCacheable(false);
        List<Alumini> aluminiList=query.list();
        if(aluminiList!=null && aluminiList.size()>0){
            System.out.println(aluminiList.get(0).getLastUpdated());
            t.commit();
            return aluminiList.get(0);
        }else{
            t.rollback();
            return null;
        }
    }finally{
        session.close();
    }   
}

所以我清除了会话,同时在我的配置中禁用了所有缓存。但是,当我更新记录并在几秒钟内使用上述方法获取记录时,我仍然会收到旧数据一次。之后,它会给我最新的数据。


当你使用数据库开发工具在代码之外进行查询时,你是否会获得旧的数据? - 6ton
不,我没有拿到旧数据。我相信缓存更新有几秒钟的延迟。 - mahesh
请分享您的Hibernate配置,包括SessionFactory Bean和事务管理器(如果有的话)。 - Amogh
1个回答

0

如果在当前会话中加载了某些实体并运行本地查询,则会话可能不会自动刷新。

Hibernate会话提供应用程序级可重复读取,因此如果其他数据库事务更改实体,则Hibernate不会刷新当前实体状态。

现在,由于您没有发布UPDATE部分,很难确定您在那里做什么。解决这些问题的最佳方法是将所有JDBC语句记录为在本文中解释。然后,您就可以确定是否执行了更新。

此外,您处理事务和会话管理的方式也存在缺陷。您甚至没有在finally块中回滚,并且由于您正在使用MySQL,这可能会导致锁定被保持并导致死锁。

只需使用像Spring或Java EE这样的框架来处理持久性上下文和事务管理。

在您的示例中:

Session session=sessionFactory.openSession();
session.clear();

如何判断这是一个新的Session,并且调用clear没有任何意义,还是你用于更新的相同Session

从这段代码中,我会假设这是相同的情况:

if(aluminiList!=null && aluminiList.size()>0){
    System.out.println(aluminiList.get(0).getLastUpdated());
    t.commit();
    return aluminiList.get(0);
}else{
    t.rollback();
    return null;
}

但它指出您可能已经跳过了Hibernate用户指南并直接开始编写Hibernate代码。

  1. aluminiList 不能为 null,只能为空。
  2. 通过 System.out 进行日志记录是错误的。应该使用日志框架。
  3. 为什么要在查询执行后提交?也许更改根本没有被刷新,查询也没有触发刷新,因为你设置了 FlushMode.MANUAL 或者查询是原生 SQL,而不是 JPQL。请查看 这篇文章以获取更多关于两者之间的区别的细节
  4. 你在 else 上调用 rollback?这有什么意义吗?你不相信数据库已经正确地发出了 UPDATE,现在你想回滚那个更改。或者,你怀疑 Hibernate 没有刷新,但是如果更改没有发生,为什么要回滚呢?但是如果它发生了,那么你应该读取你的写入,因为这就是 ACID 隔离级别的工作方式
总的来说,你发布的代码存在许多问题。因此,请阅读Hibernate用户指南和这些教程,你就能解决所有问题。没有其他办法。

我在使用之前清除了会话。请检查我的更新答案,我有遗漏吗? - mahesh
不,问题还没有解决。更新后,如果在几秒钟内尝试获取数据,则会收到旧数据。仍然面临此问题。 - mahesh
你的代码存在太多问题,仅仅获取到陈旧数据这一点就提示你需要对其进行大量更改:适当的日志记录、语句记录、正确的Session/Tx管理。 - Vlad Mihalcea

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接