Closed statement SQLException causing rollback on v6.2024.5

Hi,

Our product code, using standard JPA API, replicates data on a secondary data source by a background job. Sporadically, upon saving (Entity merge), a “Closed Statement” SQLException arises, causing the contextual transaction to rollback.
The issue is randomly intermittent, and the application is not under any relevant load (no stress tests).

Versions
Java JDK 11 from Docker image eclipse-temurin:11-jdk-alpine
Payara: Payara 6 Community Edition 6.2024.5
Oracle driver: ojdbc8 19.23.0.0.0
Execution context
Datasource: Secondary datasource used for data replication, from PersistanceContext configuration
Thread: From a Thread Pool not managed by Payara - Not an HTTP request context
Transaction Manager: Provided by Payara, but EntityManager.joinTransaction() to join the transaction in the thread local
Entity Manager: Not injected by Payara, created programmatically with the EntityManagerFactory
Stack Trace of the Exception
2024-06-06 14:37:38.822 [ERROR] [pfdev_app] [replication-worker-1]: Replication encountered error
org.eclipse.persistence.exceptions.DatabaseException:
Internal Exception: java.sql.SQLException: Closed Statement
Error Code: 17009
Call: SELECT ***** FROM **** WHERE ((**** = ?) AND (**** = ?))
bind => [2 parameters bound]
Query: ReadObjectQuery(referenceClass=PsgridProcessinghistory )
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:343) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:702) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:569) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2048) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:611) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:263) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:280) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:266) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectOneRow(DatasourceCallQueryMechanism.java:813) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectOneRowFromTable(ExpressionQueryMechanism.java:2912) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectOneRow(ExpressionQueryMechanism.java:2865) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.queries.ReadObjectQuery.executeObjectLevelReadQuery(ReadObjectQuery.java:563) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1236) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:913) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1195) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.queries.ReadObjectQuery.execute(ReadObjectQuery.java:448) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1283) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:3008) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1841) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1823) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1773) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.AbstractSession.readObject(AbstractSession.java:3767) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.MergeManager.registerObjectForMergeCloneIntoWorkingCopy(MergeManager.java:1108) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfCloneIntoWorkingCopy(MergeManager.java:575) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChanges(MergeManager.java:324) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.mergeCloneWithReferences(UnitOfWorkImpl.java:3661) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.mergeCloneWithReferences(RepeatableWriteUnitOfWork.java:402) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.mergeCloneWithReferences(UnitOfWorkImpl.java:3621) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.mergeInternal(EntityManagerImpl.java:644) ~[org.eclipse.persistence.jpa.jar:?]
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.merge(EntityManagerImpl.java:622) ~[org.eclipse.persistence.jpa.jar:?]
at com.company.application.firecluster.PSGridReplicationRunnableImpl.lambda$run$7(PSGridReplicationRunnableImpl.java:315) ~[Application-Core-EJBs-2.0.7.1-SNAPSHOT.jar:?]
at com.company.application.firecluster.EjbContextHolder.execute(EjbContextHolder.java:17) ~[Application-Core-EJBs-2.0.7.1-SNAPSHOT.jar:?]
at jdk.internal.reflect.GeneratedMethodAccessor625.invoke(Unknown Source) ~[?:?]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:588) ~[ejb-container.jar:?]
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:408) ~[ejb-container.jar:?]
at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4835) ~[ejb-container.jar:?]
at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:653) ~[ejb-container.jar:?]
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:834) ~[ejb-container.jar:?]
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:603) ~[ejb-container.jar:?]
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doCall(SystemInterceptorProxy.java:163) ~[ejb-container.jar:?]
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:140) ~[ejb-container.jar:?]
at jdk.internal.reflect.GeneratedMethodAccessor108.invoke(Unknown Source) ~[?:?]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:888) ~[ejb-container.jar:?]
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:833) ~[ejb-container.jar:?]
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:603) ~[ejb-container.jar:?]
at org.jboss.weld.module.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:81) ~[weld-osgi-bundle.jar:5.0.1.Final]
at org.jboss.weld.module.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:52) ~[weld-osgi-bundle.jar:5.0.1.Final]
at jdk.internal.reflect.GeneratedMethodAccessor103.invoke(Unknown Source) ~[?:?]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:888) ~[ejb-container.jar:?]
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:833) ~[ejb-container.jar:?]
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:375) ~[ejb-container.jar:?]
at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:4807) ~[ejb-container.jar:?]
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4795) ~[ejb-container.jar:?]
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:212) ~[ejb-container.jar:?]
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:90) ~[ejb-container.jar:?]
at com.sun.proxy.$Proxy341.execute(Unknown Source) ~[?:?]
at com.company.application.firecluster.EJB31_Generated__EjbContextHolder__Intf____Bean.execute(Unknown Source) ~[Application-Core-EJBs-2.0.7.1-SNAPSHOT.jar:?]
at com.company.application.firecluster.PSGridReplicationRunnableImpl.lambda$run$8(PSGridReplicationRunnableImpl.java:186) ~[Application-Core-EJBs-2.0.7.1-SNAPSHOT.jar:?]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
at java.base/java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: java.sql.SQLException: Closed Statement
at oracle.jdbc.driver.OracleClosedStatement.setString(OracleClosedStatement.java:492) ~[ojdbc8.jar:19.22.0.0.0]
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setString(OraclePreparedStatementWrapper.java:257) ~[ojdbc8.jar:19.22.0.0.0]
at com.sun.gjc.spi.base.PreparedStatementWrapper.setString(PreparedStatementWrapper.java:270) ~[__xa_jdbc_ra.jar:?]
at jdk.internal.reflect.GeneratedMethodAccessor117.invoke(Unknown Source) ~[?:?]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
at com.sun.gjc.spi.jdbc40.ProfiledConnectionWrapper40$1.invoke(ProfiledConnectionWrapper40.java:455) ~[__xa_jdbc_ra.jar:?]
at com.sun.proxy.$Proxy522.setString(Unknown Source) ~[?:?]
at org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.setParameterValueInDatabaseCall(DatabasePlatform.java:2376) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.platform.database.oracle.Oracle9Platform.setParameterValueInDatabaseCall(Oracle9Platform.java:588) ~[org.eclipse.persistence.oracle.jar:?]
at org.eclipse.persistence.internal.databaseaccess.DatabaseCall.prepareStatement(DatabaseCall.java:799) ~[org.eclipse.persistence.core.jar:?]
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:630) ~[org.eclipse.persistence.core.jar:?]
… 65 more

Any help with resolving this issue would be greatly appreciated.

This problem can have several causes. I would investigate the following points:

  1. is a keep-alive query or something like that set up? If a DB connection is unused for too long, it could be closed
  2. then you could build a wrapper around the EntityManager and extend the “close()” method so that a log message is issued when this happens.
  3. perhaps the bean in which the second EntityManager is injected could also be passivated, which would transitively close the database connection.