spring - 无法为事务打开 JPA EntityManager,在任务执行期间数据库连接关闭
问题描述
我一直在寻找类似的问题,但我发现的每个问题都有点不同。
我正在使用 SpringBoot (1.5.2.RELEASE) 和 PostgresSQL DB (42.0.0)。
我在下面描述问题:
我有一个方法,它需要一些实体,将其发送到外部服务,并将结果保存到数据库。每个实体都被一一获取(不在列表中)。这个过程有时需要几秒钟,有时甚至几分钟(取决于要处理的实体)。
一切正常,除非突然抛出异常:
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.TransactionException: JDBC begin transaction failed:
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:431)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:447)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:277)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)
at com.service.someClass.settings.SettingsServiceImpl$$EnhancerBySpringCGLIB$$897e9c29.getPropertySettings(<generated>)
..rest of stackTrace
有时我需要 2:15(分:秒),有时需要 2:40 才能得到这个例外。
在对 DBeaver 进行一些调查后,我检查了与 DB 的连接select * from pg_stat_activity;
。在流程执行期间,我正在刷新pg_stat_activity
我注意到一个连接负责创建事务和提交。在几秒钟内SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE
会出现该连接的查询。在开始时,我可以看到 3 个连接。在进程执行期间,我可以看到正在创建一个额外的连接,它从当前工作表中读取一些实体。一段时间后,负责创建和提交会话的连接消失了。休息连接已经获得了当前的查询SELECT 1
,此时后端中的异常被抛出(我之前粘贴过)。
更具可读性(我希望)的版本如下:
我已经阅读了有关数据库连接配置的信息,并且该症状将我引导至 Tomcat 配置,如下所示:
tomcat:
removeAbandoned: true
removeAbandonedTimeout: 120
testOnBorrow: true
validationQuery: SELECT 1;
validationInterval: 30000
testWhileIdle: true
timeBetweenEvictionRunsMillis: 60000
maxActive: 10
initialSize: 2
minIdle: 2
maxIdle: 5
测试了什么?
经过更多阅读后,我尝试设置removeAbandoned: false
. 整个过程无一例外地完成。有什么不同?在创建了一个与 DB 的额外连接并完成了进程之后 - 该连接仍然出现在pg_stat_activity
.
当我设置removeAbandonedTimeout:
为较低的值时 - 进程崩溃得更快。我试过 60 和 10。当我设置值 10 时,进程在 30 秒后崩溃,第二次在 ~50 秒后崩溃。当它设置为 120 时,它会在 ~2:30-2:50(分钟)后崩溃得更多。
这就是为什么我假设以某种方式完成整个工作(创建和提交事务)的主要连接(错误与否)被识别为已放弃的连接(据我所知 - 未关闭)。
什么是重要的?关闭的连接一直在“工作” - 改变价值query
列并更新开始和结束时间执行。现在更奇怪的是为什么突然关门了。
我不是很有经验,但我认为 TransactionManager (Spring) 可能有问题。
解决方案
经过文档研究,我发现了我的问题的起源和解决方案。
在我的情况下,问题在于 Tomcat 配置和我的进程可以执行几分钟的事实。
当服务开始工作时,它会从连接池中借用一个到 DB 的免费连接。这时一个计时器开始计算具体的数据库客户端占用特定连接的时间。事实上,我的连接每 3 秒执行几个查询,我假设(错误)根据定义它不能被放弃。
弃?
那么实际上,这abandoned
意味着什么?abandoned
当某些数据库客户端从连接池中借用连接并且没有将其归还某些值时,特定连接就变成了(removeAbandonedTimeout: (int)
默认为 180 秒)。什么是重要的?这并不影响您如何使用该连接。如果它处于空闲状态,或者正在执行查询......有
什么帮助?
就我而言,我在 .yml 配置文件属性中定义:
spring:
datasource:
jdbcInterceptors: ResetAbandonedTimer
每次准备语句或执行查询时,计时器将重置连接池上的放弃计时器。这样即使是长进程(活进程)也不会超时。
我发现了一个与我的问题相关的 stackoverflow帖子,并跟踪我找到了很好的文章,其中很好地描述了这个功能
什么是好奇?即使在官方 Tomcat文档中我也没有找到解决方案。它说的是使用org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer
和它的作用,但没有说什么属性可以“打开”这个功能。
希望它对某人有所帮助并节省时间。
推荐阅读
- reactjs - 在 Gutenberg ServerSideRender 完成时执行操作
- javascript - 使用 npm 在 macOS 上安装 webpack
- time-complexity - 我是否为这个关于算法时间复杂度的问题选择了正确答案?
- java - 当我添加侦听器时,所有现有节点的 ChildEventListener 的 onAddChild 都会触发
- c - 使用 C 中的合并排序或快速排序对很长的链表进行排序
- android - 在片段类的 onViewCreated() 方法中访问上下文对象 - 空上下文情况
- amazon-web-services - 负载均衡器位于区域或 AZ 的哪个位置?(对于架构图)
- javascript - 如何在全日历中显示从 api 获取事件?
- c# - 如何显示所选 ID 中的数据
- ios - 记录进度、错误、错误、请求等日志的最佳网站