首页 文章

MySQL或Hibernate缓存问题接收旧数据

提问于
浏览
2

当我更新表时,我面临一个奇怪的问题,当我尝试获取时,几秒钟后我仍然收到旧数据 . 当我再次使用相同的查询获取几秒后,我会收到刷新的数据 . 基本上我所看到的是返回新数据需要一些时间 .

我已经禁用了所有来自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();
    }   
}

所以我正在清理会话,同样在我的配置中我已将所有缓存设置为禁用 . 当我更新记录时,如果我使用上述方法获取记录,那么我会在几秒钟内收到旧数据一次 . 之后,它给了我最新的数据 .

1 回答

  • 0

    如果在当前会话中加载了某些实体并且您运行了native query,则会话可能不会自动刷新 .

    Hibernate Session提供application-level repeatable reads,因此如果其他数据库事务更改实体,Hibernate将不会刷新当前实体状态 .

    现在,由于您没有发布UPDATE部分,因此很难说出您在那里做了什么 . 解决此问题的最佳方法是将所有JDBC语句记录为explained in this article . 然后,您将确定是否已执行更新 .

    此外,您进行交易和会话管理的方式也存在缺陷 . 您甚至不在 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 User Guide并跳转到编码Hibernate .

    • aluminiList 永远不能为空 . 它只能是空的 .

    • 通过 System.out 记录是错误的 . 使用Logging框架 .

    • 为什么要在执行查询后提交?可能根本没有刷新更改并且查询没有触发刷新因为您设置了 FlushMode.MANUAL 或查询是本机SQL,而不是JPQL . 看看this article for more details about the difference .

    • 你在其他地方拨打 rollback ?什么's the point? You don't信任它正确发出UPDATE的数据库,现在你要回滚该更改 . 或者,你怀疑Hibernate没有刷新,但是,如果改变没有ACID isolation levels work,你为什么还要回滚呢?

    总而言之,您发布的代码中存在许多问题 . 因此,请阅读Hibernate用户指南和these tutorials,您将解决所有问题 . 别无他法 .

相关问题