【问题标题】:Hibernate PersistenceContext session FlushHibernate PersistenceContext 会话刷新
【发布时间】:2013-10-08 06:32:54
【问题描述】:

我想知道当我调用 session= session.getCurrentSession() 时休眠何时完成上下文会话

问题是我的 dao 中有 2 个方法调用 getCurrentSession(),当我处理调用 getCurrentSession() 的更新时,实体为空:

SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];...)

如何让这些实体从 select 方法持续到 update 方法?

这是我的方法:

public List<SystemConfiguration> getListConfigurations() {
    List<SystemConfiguration> lista = new ArrayList<SystemConfiguration>();
    Session session = null;
    Query query = null;

    String sql = "from SystemConfiguration where description = :desc";
    try {
        /* BEFORE
            session = SessionFactoryUtil.getInstance().getCurrentSession(); 
        @SuppressWarnings("unused")
        Transaction ta = session.beginTransaction(); */
            //FOLLOWING LINE SOLVED THE PROBLEM
            session = SessionFactoryUtil.getInstance().openSession();
        query = session.createQuery(sql);

        query.setString("desc", "configuracion");
        lista = query.list();

        return lista;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}


public void updateConfigurations(List<SystemConfiguration> configs) throws Exception{
        Session sess = null;
        Transaction tx = null;
        try {
                    //BEFORE
            //sess = SessionFactoryUtil.getInstance().getCurrentSession();
                    //FOLLOWING LINE SOLVED THE PROBLEM
                 sess = SessionFactoryUtil.getInstance().openSession(new SystemConfigurationInterceptor());
            tx = sess.beginTransaction();
            for (SystemConfiguration sys : configs) {
                    sess.update(sys);   
            }
            tx.commit();
        } // try
        catch (Exception e) {
            e.printStackTrace();
            if (tx != null && tx.isActive()) {
                tx.rollback();
            } // if
            throw e;
        } 
    }

这是我的拦截器:

public class SystemConfigurationInterceptor extends EmptyInterceptor {
            private int updates;
        private int creates;
        private int loads;
        public void onDelete(Object entity,
                             Serializable id,
                             Object[] state,
                             String[] propertyNames,
                             Type[] types) {
            // do nothing
        }

        // This method is called when Entity object gets updated.
        public boolean onFlushDirty(Object entity,
                                    Serializable id,
                                    Object[] currentState,
                                    Object[] previousState,
                                    String[] propertyNames,
                                    Type[] types) {

            if ( entity instanceof SystemConfiguration ) {
                updates++;
                for ( int i=0; i < propertyNames.length; i++ ) {
                    if ( "updated_at".equals( propertyNames[i] ) ) {
                        currentState[i] =  new Timestamp(Calendar.getInstance().getTime().getTime());
                        return true;
                    }
                }
            }
            return false;
        }

        public boolean onLoad(Object entity,
                              Serializable id,
                              Object[] state,
                              String[] propertyNames,
                              Type[] types) {
            if ( entity instanceof SystemConfiguration ) {
                loads++;
            }
            return false;
        }

     // This method is called when Entity object gets created.
        public boolean onSave(Object entity,
                              Serializable id,
                              Object[] state,
                              String[] propertyNames,
                              Type[] types) {

            if ( entity instanceof SystemConfiguration ) {
                creates++;
                for ( int i=0; i<propertyNames.length; i++ ) {
                    if ( "updated_at".equals( propertyNames[i] ) ) {
                        state[i] = new Timestamp(Calendar.getInstance().getTime().getTime());
                        return true;
                    }
                }
            }
            return false;
        }

        public void afterTransactionCompletion(Transaction tx) {
            if ( tx.wasCommitted() ) {
                System.out.println("Creations: " + creates + ", Updates: " + updates +", Loads: " + loads);
            }
            updates=0;
            creates=0;
            loads=0;
        }

【问题讨论】:

  • 不太明白你的问题,但是使用会话的默认刷新模式 (AUTO),会话在以下情况下被刷新:1) 调用 transaction.commit 2) 正在执行查询跨度>
  • 有没有办法让实体持久化?我的意思是在执行查询后不被刷新?
  • 我的意思是我做了一个选择,它返回一个列表,然后我处理它,然后我将它更新到数据库,我的问题是休眠将所有实体标记为脏,因为有会话的持久上下文中没有任何内容
  • 我解决了!我不知道它为什么起作用,但我将这两种方法都更改为 .openSession() 现在一切正常(实体现在仍在会话中,它不会自动刷新),我将使用解决方案更新帖子。但是现在,有人能告诉我为什么打开 2 个新会话会使对象或实体从一个到另一个持续存在吗?

标签: java spring hibernate session


【解决方案1】:

当你告诉它并且当前事务“关闭”时(通常当数据库连接以某种方式返回到池时),Hibernate 将刷新。

因此,您的问题的答案取决于您使用的框架。使用 Spring,当最外层的 @Transactional 方法返回时,会话会被刷新。

您上面的“解决方案”不会长期有效,因为它永远不会关闭会话。当它返回一个结果时,它会泄漏一个数据库连接,所以在几次调用之后,你会用完连接。

您的问题也没有任何意义。 SELECT 不会更改对象,因此在您更改它们之前不需要“持久化”它们。

updateConfigurations()更改后,Hibernate可以选择不立即将它们写入数据库,只更新缓存。

最终,如果您正确配置了所有内容,Spring 将提交事务并刷新缓存。但是当你使用 Spring 时,你永远不应该创建打开和关闭会话,因为它会干扰 Spring 正在做的事情。

【讨论】:

  • 您的解释非常好,但我怎样才能避免这种泄漏?,关键是我希望我在 getListConfigurations() 中选择的对象保留在会话中(休眠缓存),然后当我调用 updateConfigurations() hibernate 将能够与其缓存进行比较,这将导致 1 次更新而不是 100 次(意味着我选择的列表包含 100 个对象)
  • 因为我只修改了我的列表中的一个对象,所以我希望 hibernate 在它的缓存中查找我修改了哪个对象,然后只更新这个
  • 对象是脏的,因为它们来自另一个会话。对于这样的对象,Hibernate 不做任何假设。你需要启动一个事务,获取所有对象,相应地修改它们,然后提交事务。
  • 这似乎很有帮助,我会搜索如何做到这一点并尝试它,之后我会再次更新您!谢谢!
  • 不幸的是,我仍然无法找到使其按预期工作的方法...如果您对代码有任何建议,我将不胜感激。谢谢。
猜你喜欢
  • 1970-01-01
  • 2014-02-18
  • 1970-01-01
  • 1970-01-01
  • 2017-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-06
相关资源
最近更新 更多