首页 文章

Hibernate读取功能显示旧数据

提问于
浏览
7

我在显示数据库中的数据时出现问题 . 如果我更新一个对象,有时我会得到旧数据,有时候是新数据 . 更新功能运行良好(我可以在DB中看到正确的更新),而read函数似乎获得缓存数据 . 我试图禁用两个缓存,尝试在更新/保存期间打开和关闭会话,但它仍然无法正常工作 . User和Store bean都有Lazy提取 . 谢谢!

阅读功能:

public static List<Store> getStoreByUser(User user)
        throws HibernateException {
    List<Store> result = null;
    Session session = sessionFactory.getCurrentSession();   
    Transaction transaction = null;
    try {
        transaction = session.getTransaction();
        Criteria criteria = session.createCriteria(Store.class);
        criteria.add(Restrictions.eq("userUserID", user));
        result = criteria.list();
    } catch (HibernateException he) {
        logger.error("No Store found for user: = " + user, he);
        throw he;
    }
    return result;
}

更新/保存功能:

public static Integer insertOrUpdateStore(Store store)
        throws HibernateException {
    Integer id = null;
    Session session = sessionFactory.getCurrentSession();   
    Transaction transaction = null;
    try {
                    transaction = session.getTransaction();
        if (store.getStoreID() != null && store.getStoreID() != 0) {

            session.merge(store);
            transaction.commit();

        } else {
                id = (Integer) session.save(store);
            transaction.commit();               
        }
    } catch (HibernateException he) {
        if (transaction != null) {
            transaction.rollback();
        }
    } finally {
    }       
    return id;
}

4 回答

  • 3

    通常,你有isolation level "read committed" . 这使您的事务可以查看其他事务已提交的更改 . 隔离级别由底层dbms实现,而不是由hibernate实现 .

    您无法禁用第一级缓存(可能通过使用无状态会话,不应将其用于一般用途) . 执行查询时,NH始终在缓存中返回值,以确保在内存中不再获取相同的db记录 .

    如果这对您来说是个问题,则应切换到更高的隔离级别 . 例如,可重复读取(这意味着它所说的:当多次读取相同的数据时,总会得到相同的结果) . 仍有机会看到其他交易的变化 . 使用可序列化的隔离级别,您不应再遇到此类问题 .

    注意:切换到另一个隔离级别是大多数系统的重大变化,应该仔细规划 .

  • 2

    您可以打开一个新会话,以便从会话缓存中获取没有旧实体的"fresh"(从数据库更新)数据 . 在下面的示例中,您可以看到实体正在从数据库查询 . 您也可以使用相同的机制返回实体而不是布尔值,或者调用 session.Refresh() (当然会从当前会话中)刷新数据库中的最新更改:

    /// <summary>
            ///  Gets an item exists on database.
            /// </summary>
            /// <param name="Id">Item ID to check if exists on database</param>
            /// <returns> True if the <paramref name="Id"/> to check exists on database, otherwise false. </returns>
            public bool Exists<T>(object Id)
            {
                using (var session = NHibernateSessionHelper.OpenSession())
                {
                    using (var transaction = session.BeginTransaction())
                    {
                        //get if the item is new. If is new, entity will be null and non exists
                        return session.Get<T>(Id) == null ? false : true;
                        //also you can return the entire table from database, or filter:
                        //session.CreateCriteria<T>().List<T>();
                    }
                }
            }
    
            public void Refresh(object entity)
            {
                //get latest changes from database (other users/sessions changes, manually, etc..) 
                NHibernateSessionHelper.CurrentSession.Refresh(entity);
            }
    

    我希望这可以帮助你 .

  • 5

    我有同样的问题,我的查询选择*返回旧数据 . 我在我的hibernate.cfg.xml文件中关闭了这样的二级缓存

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

    我会尝试在transaction.commit()之前/之后添加session.flush()或session.clear(),但它不会给出正面结果

  • 2

    您可以逐出旧数据,以确保从数据库中获取数据,而不是从L1和L2缓存中获取数据 .

    此外,您必须确保您不在 REPEATABLE_READ 隔离级别 . 在此隔离模式下,它保证同一事务中的两个读取始终返回相同的结果 . 由于隔离级别优先于缓存逐出,因此缓存逐出不会产生任何可见效果 .

    有一种方法可以解决此问题:将事务隔离级别声明为 READ_UNCOMMITTEDREAD_COMMITTED .

相关问题