如何将Apache-Commons DBCP与EclipseLink JPA和Tomcat 7.x一起使用

时间:2012-07-17 16:15:54

标签: jpa eclipselink apache-commons-dbcp

我一直在开发一个部署在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>

1 个答案:

答案 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。您可以忽略交易部分,因为您没有使用它们,并且已经在生产中,您不太可能发生显着变化,但它可能对未来的开发很有意义。

祝你好运!