IT Share you

Spring MVC에서 ScrollableResults-backed Stream을 반환 유형으로 사용하는 데 문제가 있습니다.

shareyou 2020. 11. 15. 12:01
반응형

Spring MVC에서 ScrollableResults-backed Stream을 반환 유형으로 사용하는 데 문제가 있습니다.



중요 참고 사항 : 이것은 4.1.2의 대상 수정 버전과 함께 Spring 문제 로 받아 들여졌습니다 .


내 목표는 Hibernate에서 HTTP 응답을 생성 할 때 O (1) 공간 복잡성을 달성하는 것 ScrollableResults입니다. MessageConverter에서 반환 된 개체를 처리하기 위해 a 가 발송 되는 표준 메커니즘을 유지하고 싶습니다 @Controller. 다음을 설정했습니다.

  1. MappingJackson2HttpMessageConverterJsonSerializerJava 8을 처리하는 a 풍부 합니다 Stream.
  2. 사용자 정의 ScrollableResultSpliterator포장에 필요한 ScrollableResultsStream;
  3. OpenSessionInViewInterceptor내에서 Hibernate 세션을 열어두기 위해 필요 MessageConverter;
  4. 설정 hibernate.connection.release_mode하기 ON_CLOSE;
  5. JDBC 연결에 필요한 ResultSet 보유 가능성이 있는지 확인하십시오 con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT).

또한 이러한 종류의 유지 기능을 지원하는 데이터베이스가 필요합니다. PostgreSQL은 그러한 데이터베이스이며 이것에 문제가 없습니다.

내가 만난 마지막 걸림돌은 HibernateTransactionManager트랜잭션 커밋에서 사용되는 정책입니다 . 기본 세션이 "Hibernate-managed"가 disconnect()아니면 다른 모든 것과 함께 커서를 닫습니다. 이러한 정책은 내 요구 사항과는 거리가 먼 일부 특수 시나리오, 특히 "대화 범위 세션"에서 유용합니다.

나는 나쁜 해킹 으로이 문제를 해결했습니다. 제거 된 disconnect()호출을 제외하고는 원본의 복사-붙여 넣기 인 메서드로 문제가되는 메서드를 재정의 해야했지만 개인 API에 액세스하려면 리플렉션에 의존해야합니다.

public class NoDisconnectHibernateTransactionManager extends HibernateTransactionManager
{
  private static final Logger logger = LoggerFactory.getLogger(NoDisconnectHibernateTransactionManager.class);

  public NoDisconnectHibernateTransactionManager(SessionFactory sf) { super(sf); }

  @Override
  protected void doCleanupAfterCompletion(Object transaction) {
    final JdbcTransactionObjectSupport txObject = (JdbcTransactionObjectSupport) transaction;
    final Class<?> c = txObject.getClass();
    try {
      // Remove the session holder from the thread.
      if ((Boolean)jailBreak(c.getMethod("isNewSessionHolder")).invoke(txObject))
        TransactionSynchronizationManager.unbindResource(getSessionFactory());

      // Remove the JDBC connection holder from the thread, if exposed.
      if (getDataSource() != null)
        TransactionSynchronizationManager.unbindResource(getDataSource());

      final SessionHolder sessionHolder = (SessionHolder)jailBreak(c.getMethod("getSessionHolder")).invoke(txObject);
      final Session session = sessionHolder.getSession();
      if ((Boolean)jailBreak(HibernateTransactionManager.class.getDeclaredField("prepareConnection")).get(this)
          && session.isConnected() && isSameConnectionForEntireSession(session))
      {
        // We're running with connection release mode "on_close": We're able to reset
        // the isolation level and/or read-only flag of the JDBC Connection here.
        // Else, we need to rely on the connection pool to perform proper cleanup.
        try {
          final Connection con = ((SessionImplementor) session).connection();
          DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
        }
        catch (HibernateException ex) {
          logger.debug("Could not access JDBC Connection of Hibernate Session", ex);
        }
      }
      if ((Boolean)jailBreak(c.getMethod("isNewSession")).invoke(txObject)) {
        logger.debug("Closing Hibernate Session [{}] after transaction",  session);
        SessionFactoryUtils.closeSession(session);
      }
      else {
        logger.debug("Not closing pre-bound Hibernate Session [{}] after transaction", session);
        if (sessionHolder.getPreviousFlushMode() != null)
          session.setFlushMode(sessionHolder.getPreviousFlushMode());
      }
      sessionHolder.clear();
    }
    catch (ReflectiveOperationException e) { throw new RuntimeException(e); }
  }

  static <T extends AccessibleObject> T jailBreak(T o) { o.setAccessible(true); return o; }
}

Since I regard my approach as the "right way" to generate ResultSet-backed responses, and since the Streams API makes this approach very convenient, I would like to solve this in a supported way.

Is there a way to get the same behavior without my hack? If not, would this be a good thing to request via Spring's Jira?


Cleaning up. As Marko Topolnik had said here

Yes, I missed this part that the holdability setting is only applied when encountering a pre-existing session. This means that my "idea" how it could be done is already the way it is done. It also means that my comment about failures doesn't apply: you either want holdability and skipping the session disconnection — or you don't need either. So if you can't get holdability, there is no reason not to disconnect the session at commit, therefore there's no reason to activate the "allowResultSetAccessAfterCompletion" in that case.

참고URL : https://stackoverflow.com/questions/26324112/trouble-using-scrollableresults-backed-stream-as-return-type-in-spring-mvc

반응형