我一直在开发一个部署在Tomcat 7上的Web应用程序,它使用EclipseLink JPA来处理持久层。
在测试环境中一切正常但我们在生产环境中遇到严重问题,因为防火墙切断了非活动连接。基本上,如果连接暂时处于非活动状态,则Tomcat服务器和数据库服务器之间的防火墙会将其终止,从而导致池中出现“陈旧”连接。
下次使用该连接时,代码永远不会返回,直到它获得“连接超时”SQLException(下面的完整ex.getMessage())。
EL Fine]:2012-07-13 18:24:39.479 - 的ServerSession(309463268) - 连接(69352859) - 线程(线程[HTTP-BIO-8080-EXEC -5,5-,主]) - 我的查询被替换为发布到[EL配置]:2012-07-13 18:40:10.229 - 的ServerSession(309463268) - 连接(69352859) - 线程(线程[HTTP-BIO-8080-EXEC -5,5-,主]) - 断开 [EL Info]:2012-07-13 18:40:10.23 - 的UnitOfWork(1062365884) - 线程(线程[HTTP-BIO-8080-EXEC -5,5-,主]) - 通信 尝试在a之外执行读取查询时检测到故障 交易。试图重试查询。错误是:异常 [EclipseLink-4002](Eclipse持久性服务 - 2.3.0.v20110604-r9504):org.eclipse.persistence.exceptions.DatabaseException内部 例外:java.sql.SQLException:Eccezione IO:连接超时
我已经在persistence.xml中尝试了几个配置,但由于我无法访问防火墙配置,所以我对这些方法没有好运。我也尝试使用setCheckConnections()
ConnectionPool cp = ((JpaEntityManager)em).getServerSession().getDefaultConnectionPool();
cp.setCheckConnections();
cp.releaseConnection(cp.acquireConnection());
我设法使用testOnBorrow,testWhileIdle和其他可从DBCP Apache Commons获得的功能在测试脚本中解决问题。我想知道如何覆盖EclipseLink内部连接池以使用自定义连接池,以便我可以基于DBCP提供已配置的池,而不是仅使用persistence.xml配置内部池。
我知道我应该提供一个SessionCustomizer,我不确定哪一个是正确使用的模式。基本上我想以类似JPA的方式保留DBCP的性能。
我正在Tomcat 7上部署,我知道如果我切换到GF我不会遇到这个问题,但为了与同一服务器上的其他webapp保持一致,我宁愿留在Tomcat上。< / p>
答案 0 :(得分:3)
你想要的绝对是可能的,但你可能会达到“自己动手”的极限。
这是要解释的难度之一,但实际上有两种配置EntityManagerFactory
的方法。 “自己动手”的方法和“容器”方法。
当你调用Persistence.createEntityManagerFactory
时,它最终会委托EclipseLink实现的PersistenceProvider
接口的这个方法:
EntityManagerFactory createEntityManagerFactory(String emName, Map map)
此处的交易是EclipseLink将自行完成所有工作,包括自己的连接创建和处理。这是“自己动手”的方法。我不太了解EclipseLink,知道是否有办法使用这种方法为它提供连接。在Stackoverflow上呆了两天之后,似乎其他任何人都没有这个信息。
所以这就是为什么这个“在GF工作”。当您让容器通过注入或查找它来为您创建EntityManagerFactory
时,容器在EclipseLink实现的PersistenceProvider
接口上使用不同的方法:
EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map)
它的长短是这个PersistenceUnitInfo
是容器实现的接口,并且有两个非常关键的方法:
public DataSource getJtaDataSource();
public DataSource getNonJtaDataSource();
使用此模式,EclipseLink不会尝试进行自己的连接处理,只需调用这些方法即可从容器中获取DataSource
。这真的是你需要的。
您可以采取两种方法来解决这个问题:
您可以尝试自己实例化EclipseLink PersistenceProvider
实现并调用createContainerEntityManagerFactory
方法传递您自己的PersistenceUnitInfo
接口实现并提供配置的DBCP {{1以这种方式将实例导入EclipseLink。您需要自己解析DataSource
文件,并通过persistence.xml
提供该数据。 EclipseLink也可能期望PersistenceUnitInfo
,在这种情况下,除非你追捕可以添加到Tomcat的TransactionManager,否则你将被卡住。
您可以使用经过Java EE 6认证的Tomcat版本TomEE。 DataSource在TransactionManager
中配置,使用DBCP创建,完全支持您需要的所有选项,并使用描述的tomee.xml
调用传递给PersistenceProvider
。然后,您可以通过createContainerEntityManagerFactory
注册EntityManagerFactory
或查找。
如果您尝试使用TomEE,请确保更新@PersistenceUnit
以明确设置persistence.xml
,因为默认值为transaction-type="RESOURCE_LOCAL"
。尽管使用JTA
方法使用JTA
是不合规的,但是没有任何持久性提供程序会抱怨并让您知道自己做错了什么,他们将其视为{{1忽略架构。因此,当您将应用程序移植到实际经过认证的服务器时,它会爆炸。
关于TomEE的另一个注意事项是,在当前版本中,您必须将EclipseLink库放在Persistence.createEntityManagerFactory
目录中。这是在行李箱中修复的,尚未发布。
我不确定这些幻灯片在没有附带说明的情况下会有多大用处,但本演示文稿的第二部分深入探讨how container-managed EntityManager's work, specifically with regards to connection handling and transactions。您可以忽略交易部分,因为您没有使用它们,并且已经在生产中,您不太可能发生显着变化,但它可能对未来的开发很有意义。
祝你好运!