在 Spring MVC 中使用 ScrollableResults 支持的 Stream 作为返回类型时出现问题
2022-08-31 15:02:57
重要提示:这已被接受为目标修复版本 4.1.2 的 Spring 问题。
我的目标是在从Hibernate的生成HTTP响应时实现O(1)空间复杂性。我想保留标准机制,其中调度a来处理从.我设置了以下内容:ScrollableResults
MessageConverter
@Controller
-
MappingJackson2HttpMessageConverter
通过处理 Java 8 的 a 进行了丰富JsonSerializer
Stream
; - 需要包装成
ScrollableResultSpliterator
ScrollableResults
Stream
; -
OpenSessionInViewInterceptor
需要使休眠会话在MessageConverter
; - 设置为
hibernate.connection.release_mode
ON_CLOSE
; - 确保 JDBC 连接具有必要的结果集可保持性:。
con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT)
此外,我需要一个支持这种可保持性的数据库。PostgreSQL就是这样一个数据库,我对此没有问题。
我遇到的最后一个绊脚石是事务提交时使用的策略:除非底层会话是“休眠管理的”,否则它会关闭我的光标以及其他所有内容。这样的策略在某些特殊情况下很有用,特别是“会话范围的会话”,这与我的要求相去甚远。HibernateTransactionManager
disconnect()
我已经设法用一个糟糕的黑客来解决这个问题:我不得不用一个方法覆盖有问题的方法,除了删除的调用之外,它实际上是原始方法的复制粘贴,但它必须诉诸反射来访问私有API。disconnect()
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; }
}
由于我认为我的方法是生成 ResultSet 支持的响应的“正确方法”,并且 Streams API 使此方法非常方便,因此我想以受支持的方式解决此问题。
有没有办法在没有我的黑客攻击的情况下获得相同的行为?如果没有,通过Spring的Jira请求这是一件好事吗?