数据库连接未使用 jpaFlowExecutionListener 关闭

2024-04-27

我正在使用 Spring Web Flow 来构建应用程序。我正在利用Flow Managed Persistence Context因此实体管理器在流程执行期间保持打开状态,我可以访问延迟加载的属性(类似于OpenEntityManagerInViewFilter or OpenSessionInViewFilter对于 Spring MVC)。当我使用这个时,每次提交表单时,活动数据库连接数都会增加,如果我不使用FMPC,则打开连接数没有问题)。

我正在使用以下设置。

事务管理器:

@Bean
@Autowired
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    return new JpaTransactionManager(entityManagerFactory);
}

数据源:

@Bean
public DataSource dataSource() {
    final BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty(PROPERTY_DATABASE_DRIVER));
    dataSource.setUrl(environment.getRequiredProperty(PROPERTY_DATABASE_URL));
    dataSource.setUsername(environment.getProperty(PROPERTY_DATABASE_USERNAME, ""));
    dataSource.setPassword(environment.getProperty(PROPERTY_DATABASE_PASSWORD, ""));
    return dataSource;
}

实体管理器工厂:

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    final LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
    factoryBean.setDataSource(dataSource());
    factoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_ENTITYMANAGER_PACKAGES_TO_SCAN));

    final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter() {
        {
            setDatabase(Database.valueOf(environment.getRequiredProperty(PROPERTY_DATABASE_TYPE)));
            setDatabasePlatform(environment.getRequiredProperty(PROPERTY_HIBERNATE_DIALECT));
        }
    };
    factoryBean.setJpaVendorAdapter(vendorAdapter);

    final Properties jpaProperties = new Properties();
    jpaProperties.put(PROPERTY_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_HIBERNATE_FORMAT_SQL));
    jpaProperties.put(PROPERTY_HIBERNATE_NAMING_STRATEGY, environment.getRequiredProperty(PROPERTY_HIBERNATE_NAMING_STRATEGY));
    jpaProperties.put(PROPERTY_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_HIBERNATE_SHOW_SQL));
    jpaProperties.put(PROPERTY_HIBERNATE_HB2DDL_SQL, environment.getRequiredProperty(PROPERTY_HIBERNATE_HB2DDL_SQL));

    factoryBean.setJpaProperties(jpaProperties);

    return factoryBean;
}

JpaFlowExecutionListener:

@Bean
@Autowired
public JpaFlowExecutionListener jpaFlowExecutionListener(EntityManagerFactory entityManagerFactory, JpaTransactionManager transactionManager) {
    return new JpaFlowExecutionListener(entityManagerFactory, transactionManager);
}

The BasicDataSource has maxActive set to 8默认情况下,当我达到 8 个活动连接时,页面就会挂起。为什么请求完成后连接没有关闭?我使用了 Chrome 调试工具(网络窗格)来确保没有 AJAX 请求运行或任何其他内容,我的页面提交(HTTP POST)触发 301 重定向,然后给我一个新的 HTTP GET 并导致状态200,一切都好。

从一个页面转到下一个页面时,会调用一个服务层,但正如您从我的 bean 中看到的,我正在使用JpaTransactionManagerSWF 文档说明如下:

  • 注意:默认情况下,除最终提交之外的所有数据访问都是非事务性的。但是,如果底层 JPA 事务管理器支持的话,流程可以在只读系统事务上下文中的对话期间调用事务服务层来获取对象。例如,当与 Hibernate JPA 提供程序一起使用时,Spring 的 JPA TransactionManager 确实支持这一点。在这种情况下,Spring 将处理将 FlushMode 设置为 MANUAL,以确保不会刷新对托管持久实体的任何正在进行的更改,同时以事务方式读取新对象。

为了完整起见,我的 spring-web-flow 配置:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:webflow="http://www.springframework.org/schema/webflow-config"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/webflow-config
           http://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd">

    <!-- Flow executor, repsonsible for creating and executing flows -->
    <webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
        <webflow:flow-execution-listeners>
            <webflow:listener ref="jpaFlowExecutionListener"/>
        </webflow:flow-execution-listeners>
    </webflow:flow-executor>

    <!-- Flow registry, responsible for loading all flows so executor can execute them -->
    <webflow:flow-registry id="flowRegistry" base-path="/WEB-INF/webflow/flows" flow-builder-services="flowBuilderServices">
        <webflow:flow-location-pattern value="/**/*-flow.xml"/>
    </webflow:flow-registry>

    <!-- Flow builder services -->
    <webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="mvcViewFactoryCreator"/>

    <!-- MvcViewFactoryCreator -->
    <bean id="mvcViewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
        <property name="viewResolvers">
            <list>
                <ref bean="viewResolver"/>
            </list>
        </property>
    </bean>

    <!-- Flow handler adapter, responsible for answering request for a flow -->
    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
        <property name="flowExecutor" ref="flowExecutor"/>
    </bean>

    <!-- Flow handler mapping, lets Spring MVCs DispatcherServlet know to send flow request to SWF -->
    <bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
        <property name="flowRegistry" ref="flowRegistry"/>
        <property name="order" value="0"/>
        <property name="interceptors">
            <list>
                <ref bean="localeChangeInterceptor" />
            </list>
        </property>
    </bean>
</beans>

我的流量有<persistence-context />定义在顶部。

我有以下最终状态(重新启动流程),即使我调用它并且 URL 参数更改为e2s1,活动连接数不重置:

<end-state id="restart" commit="true" view="redirect:/main"/>

所以看来默认的休眠属性hibernate.connection.release_mode is on_close。考虑到 EntityManager 在整个流程中保持打开状态,它永远不会关闭,并且会为流程中的每个请求从池中获取新连接。

将属性更改为after_transaction解决了这个问题。但是,在获取延迟加载的集合的情况下,它仍然不起作用,每个延迟属性都会从池中获取新的连接。为了解决这个问题我扩展了JpaFlowExecutionListener有了这个:

public class AvoidLeakJpaFlowExecutionListener extends JpaFlowExecutionListener {

    public AvoidLeakJpaFlowExecutionListener(EntityManagerFactory entityManagerFactory, PlatformTransactionManager transactionManager) {
        super(entityManagerFactory, transactionManager);
    }

    @Override
    public void paused(RequestContext context) {
        super.paused(context);
        EntityManager entityManager = (EntityManager) context.getFlowScope().get(PERSISTENCE_CONTEXT_ATTRIBUTE);
        if (entityManager != null && entityManager instanceof HibernateEntityManager) {
            HibernateEntityManager hibernateEntityManager = (HibernateEntityManager) entityManager;
            hibernateEntityManager.getSession().disconnect();
        }
    }
}

这种方法解决了延迟加载集合的问题,但仍然会泄漏连接当使用 WebFlow 的持久性上下文完成延迟初始化实体的加载时,并且此加载是在转换到未配置的子流期间执行的。如中所述在这个错误报告中 https://jira.spring.io/browse/SWF-1525(我也在那里找到了这个解决方案)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据库连接未使用 jpaFlowExecutionListener 关闭 的相关文章

随机推荐

  • 水平滚动视图无法正常工作 swiftUI

    我试图显示一些水平视图 但它不起作用 下面是我正在使用的代码 State var userDataList UserModel var body some View VStack spacing 10 VStack prefView pad
  • iOS App 中 AVAudioPlayer 和 MPMusicPlayerController 的独立音量控制。

    在我的应用程序中 我使用 AVAudioPlayer 播放下载的音频 同时使用 MPMusicPlayerController 播放用户 iPod 音乐库中的音频 我需要能够调整 AVAudioPlayer 实例的音量 使其声音更大 比来自
  • 为什么 GCC 9.1.0 有时会抱怨 strncpy() 的这种使用?

    这是一个 40 行 MCVE 最小 完整 可验证的示例 https stackoverflow com help mcve 或者接近最小的东西 从最初包含 32 个标头的 1675 行源文件中删减 其中大多数包含多个其他标头 编译它gcc
  • gcc 如何知道内联汇编中使用的寄存器大小?

    我有内联汇编代码 define read msr index buf asm volatile rdmsr d buf 1 a buf 0 c index 使用该宏的代码 u32 buf 2 read msr 0x173 buf 我发现反汇
  • 如何在活动脚手架导轨 3 中添加新链接

    我需要在我的出租车列表页面中添加一个新链接 地图 我使用的是 active scaffold 和 Rails 3 2 1 我当前的页面如下所示 我需要在每条记录中显示类似于编辑 删除 显示的链接 地图 在我的数据库中 我有字段名称 纬度 经
  • 你怎么知道无限长的承诺链何时完全结束?

    我试图使用 Promise 强制序列化一系列 Ajax 调用 用户每次按下按钮时都会进行这些 Ajax 调用 我可以成功地序列化操作 如下所示 sample async function real world this is an Ajax
  • 在 MS 企业库或 Log4net 等第 3 方组件上创建包装器是一个好习惯吗?

    这更像是一个很好的练习题 我想提供不同的通用库 如日志记录 缓存等 有很多第三方库 如 MS 企业库 log4Net NCache 等 我想知道直接使用这些服务或在每个服务上创建包装器并使用 DI 在代码中注入该服务是否是一个好习惯 reg
  • C++ iostream 的自定义操纵器

    我想为 ostream 实现一个自定义操纵器 以对插入流中的下一个项目进行一些操作 例如 假设我有一个自定义操纵器quote std ostringstream os std string name Joe os lt lt SELECT
  • pandas 中的索引对象——为什么 pd.columns 返回索引而不是列表

    来自 R 背景 我发现 非常高 使用Indexpandas 中的对象有点令人不安 例如 如果train是一个pandas DataFrame 有什么特殊原因吗train columns应该返回一个Index而不是一个列表 如果它是一个Ind
  • 如何在 Android 上检测从 3g 到 H+ 的网络类型更改

    通过连接管理器和广播接收器 我能够获取连接和断开连接事件 如下所述埃里克的帖子在这里 https stackoverflow com questions 1783117 network listener android 我想知道的是网络连接
  • IntelliJ IDEA 在项目 jar 中查找类

    我看过一些关于通过在目录中搜索 jar 来查找类的帖子 这让我认为 IntelliJ IDEA 中一定有一个工具可以做到这一点 有人知道这样的工具以及如何使用它吗 如果 jar 文件作为项目依赖项导入 您可以键入cmd n然后搜索它
  • ROS中spin和rate.sleep的区别

    我是 ROS 新手 正在尝试了解这个强大的工具 我很困惑spin and rate sleep功能 谁能帮助我了解这两个功能之间的区别以及何时使用每个功能 ros spin and ros spinOnce 负责处理通信事件 例如到达的消息
  • Java EE / Jakarta EE 支持 Java 模块系统吗?是否可以使用Java模块系统制作Web应用程序?

    我正在使用 Java 11 和 Maven 3 6 1 构建我的第一个模块化应用程序 我的IDE是IntellijIDEA 2019 1 3 我添加了一个模块 app 并添加module info java 但我很困惑 因为即使我向应用程序
  • fork 和现有线程?

    在linux系统上 子进程查看现有线程的方式与父进程相同吗 int main create thread 1 int child pid fork if 0 child pid else 由于子进程复制了整个地址空间 因此线程的状态会发生什
  • 如何在节点中转义 shell 命令的字符串?

    In nodejs http nodejs org 执行外部命令的唯一方法是通过 sys exec cmd 我想调用外部命令并通过标准输入为其提供数据 在nodejs中 似乎还没有一种方法可以打开命令 然后将数据推送到它 仅执行并接收其标准
  • 查找游戏对象的子对象的子对象

    我在场景中有一个预制件 我想访问该预制件的子项 该预制件的结构如下 PauseMenu UI Resume TextField TextField2 UI Side Back lt I need this child UI Home tra
  • 如何 adb 提取 SD 卡中文件夹中的所有文件

    我的 SD 卡中有一个文件夹 mnt sdcard Folder1 Folder2 Folder3 jpg 文件夹 1 和文件夹 2 的名称保持不变 文件夹 2 内有文件夹 3 4 5 等 我想使用 adb 将所有 jpeg 文件而不是所有
  • 具有多个数据源的 Spring Boot + JNDI

    我尝试创建一个 Spring Boot 应用程序 它连接两个数据源 我能够通过遵循 Spring 文档来实现这一目标 但我面临的挑战是实现以下目标 通过使用 Spring Boot DataSourceAutoConfiguration 通
  • Baqend 中的关系和 ACL

    我试图弄清楚 baqend 是否可以做到这一点 或者甚至是正确的方法 我有很多用户 使用 Baqend 附带的默认用户帐户系统 其中一些用户将是公司的管理员 一家公司将拥有 1 到 5 名管理员用户 有一个单独的数据类 其中包含公司的记录和
  • 数据库连接未使用 jpaFlowExecutionListener 关闭

    我正在使用 Spring Web Flow 来构建应用程序 我正在利用Flow Managed Persistence Context因此实体管理器在流程执行期间保持打开状态 我可以访问延迟加载的属性 类似于OpenEntityManage