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

标签 java mysql hibernate jpa caching

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

我在获取 session.clear() 并将查询标记为不可缓存时也禁用了 hibernate 中的所有缓存。

我还查看了 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();
    }   
}

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

最佳答案

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

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

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

此外,您进行事务和 session 管理的方式也存在缺陷。您甚至不会在 finally block 中回滚,并且由于您使用的是 MySQL,这可能会导致锁定并导致死锁。

只需使用像 Spring 或 Java EE 这样的框架来为您处理 Persistence Context 和事务管理。

在你的例子中:

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。

  1. aluminiList 永远不能为空。它只能是空的。
  2. 通过 System.out 记录是错误的。为此使用日志记录框架。
  3. 为什么要在查询执行后提交?也许更改根本没有刷新并且查询没有触发刷新,因为您设置了 FlushMode.MANUAL 或者查询是 native SQL,而不是 JPQL。查看this article for more details about the difference .
  4. 您在 else 上调用了 rollback?重点是什么?您不信任它正确发出 UPDATE 的数据库,现在您想回滚该更改。或者,您怀疑 Hibernate 没有刷新,但是,如果没有发生更改,您为什么要回滚它,对吗?但如果它发生了,那么你应该读你写的,因为这就是ACID isolation levels work的方式。 .

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

关于java - MySQL 或 Hibernate 缓存问题接收旧数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30918154/

相关文章:

java - Repaint() 保留原始图像

c# - 在调用 Read() 之前访问字段的尝试无效

mysql - 为什么在我刚刚锁定表时给 mysql 错误 ER_TABLE_NOT_LOCKED?

java - 如何使用 JPA/Hibernate 将自定义数据结构映射到 bean 实体?

java - 我应该将托管实体传递给需要新事务的方法吗?

java - 是否可以使用 Hibernate Validation 运行一项具体验证

java - 为什么 sbt 程序集在更新依赖项时会抛出错误?

java - 如何反转字符串中特定字母字符的大写(不区分大小写),而不影响字符串中的所有其他字符?

java - 注释android后的MuPdf保存文件

php - 动态 PHP PDO MYSQL 查询不更新 [未返回错误]