【问题标题】:Prevent closing ResultSet on transaction commit防止在事务提交时关闭 ResultSet
【发布时间】:2014-05-09 05:46:01
【问题描述】:

我必须保留在@Transactional Controller 中打开的ResultSet,以便在MessageConverter 中使用。为此,我配置了以下内容:

  1. MVC 拦截器:

    <mvc:interceptors>
       <bean class="org.springframework.orm.hibernate4.support.OpenSessionInViewInterceptor" 
             p:sessionFactory-ref="sessionFactory"/>
    </mvc:interceptors>
    
  2. 在 SessionFactory bean 上:

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
      <property name="hibernateProperties">
        <props>
          <prop key="hibernate.connection.release_mode">on_close</prop>
          ....
        </props>
      </property>
    </bean>
    
  3. 在Controller方法内:

    session.doWork((con) -> { con.setHoldability(HOLD_CURSORS_OVER_COMMIT); });
    

PSQLException: This ResultSet is closed. 仍然存在。这是在控制器方法返回时事务提交时日志中的相关 sn-p:

TRACE o.h.e.j.i.JdbcCoordinatorImpl - Registering result set [org.apache.tomcat.dbcp.dbcp2.DelegatingResultSet@5a63c2aa] 
DEBUG o.h.e.t.s.AbstractTransactionImpl - committing 
TRACE o.h.internal.SessionImpl - Automatically flushing session 
TRACE o.h.internal.SessionImpl - before transaction completion 
DEBUG o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection 
DEBUG o.h.e.t.i.j.JdbcTransaction - re-enabling autocommit 
TRACE o.h.e.t.i.TransactionCoordinatorImpl - after transaction completion 
TRACE o.h.internal.SessionImpl - after transaction completion 
TRACE o.h.internal.SessionImpl - Setting flush mode to: MANUAL 
DEBUG o.h.internal.SessionImpl - Disconnecting session 
TRACE o.h.e.j.i.JdbcCoordinatorImpl - Releasing JDBC container resources [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl@97bfa5f] 
TRACE o.h.e.j.i.JdbcCoordinatorImpl - Closing result set [org.apache.tomcat.dbcp.dbcp2.DelegatingResultSet@5a63c2aa] 
TRACE o.h.e.j.i.JdbcCoordinatorImpl - Closing prepared statement [select...] 
DEBUG o.h.e.j.i.LogicalConnectionImpl - Releasing JDBC connection 
DEBUG o.h.e.j.i.LogicalConnectionImpl - Released JDBC connection 
DEBUG o.h.e.j.s.SqlExceptionHelper - could not advance using next() [n/a] org.postgresql.util.PSQLException: This ResultSet is closed.

我还能做些什么来阻止这种情况发生吗?

【问题讨论】:

  • 资源是否实际映射到 OSIV 过滤器中?其他一切看起来都不错。
  • 我在拦截器配置中有&lt;mvc:mapping path="/resource-path"/&gt;,但没有显示出来,因为没有映射它普遍适用。此外,这部分可以证明是有效的,因为如果我不使用 @Transactional,我会得到我的开放结果集。

标签: java spring hibernate spring-mvc hibernate-4.x


【解决方案1】:

默认情况下,Spring 将自行管理 Hibernate 会话。如HibernateTransactionManager Javadoc 中所述,其中一个后果是Spring 将显式调用session.disconnect(),这将使您的connection.release_mode=on_close 设置无效。要将此行为更改为 Hibernate 管理的会话,请务必将 HibernateTransactionManager 上的 hibernateManagedSession 属性设置为 true

<bean id="transactionManager" 
   class="org.springframework.orm.hibernate4.HibernateTransactionManager"
   p:hibernateManagedSession="true" />

这样做必然会扰乱某些假定默认行为的机制。其中之一是通过TransactionTemplate 进行事务管理:不会自动创建 Hibernate 会话。这可以通过将会话显式绑定到当前线程来解决,最好在TransactionTemplate 的子类中捕获:

@Component
public class HibernateTransactionTemplate extends TransactionTemplate
{
  @Autowired private SessionFactory sf;

  @Autowired @Override public void setTransactionManager(PlatformTransactionManager txm) {
    super.setTransactionManager(txm);
  }

  @Override public <T> T execute(TransactionCallback<T> action) throws TransactionException {
    final Session ses = sf.openSession();
    TransactionSynchronizationManager.bindResource(sf, new SessionHolder(ses));
    try { return super.execute(action); }
    finally {
      ses.close();
      TransactionSynchronizationManager.unbindResource(sf);
    }
  }
}

【讨论】:

    猜你喜欢
    • 2016-04-28
    • 1970-01-01
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    • 2016-06-19
    • 2015-07-31
    • 2013-09-24
    • 1970-01-01
    相关资源
    最近更新 更多