【问题标题】:How to use Apache-Commons DBCP with EclipseLink JPA and Tomcat 7.x如何将 Apache-Commons DBCP 与 EclipseLink JPA 和 Tomcat 7.x 一起使用
【发布时间】:2012-07-16 14:52:23
【问题描述】:

我一直在开发一个 Web 应用程序,部署在 Tomcat 7 上,它使用 EclipseLink JPA 来处理持久层。

在测试环境中一切正常,但由于防火墙切断了不活动的连接,我们在生产环境中遇到了严重问题。基本上,如果连接在一段时间内处于非活动状态,那么位于 Tomcat 服务器和 DB 服务器之间的防火墙就会将其杀死,从而在池中留下“陈旧”的连接。

下次使用该连接时,代码永远不会返回,直到出现“连接超时”SQLException(下面是完整的 ex.getMessage())。

EL Fine]: 2012-07-13 18:24:39.479--ServerSession(309463268)--Connection(69352859)--Thread(Thread[http-bio-8080-exec-5,5,main])-- 我的查询已替换为将其发布到 SO [EL Config]:2012-07-13 18:40:10.229--ServerSession(309463268)--Connection(69352859)--Thread(Thread[http-bio-8080-exec-5,5,main])--断开连接 [EL信息]:2012-07-13 18:40:10.23--UnitOfWork(1062365884)--Thread(Thread[http-bio-8080-exec-5,5,main])--通讯 尝试在外部执行读取查询时检测到失败 交易。正在尝试重试查询。错误是:异常 [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 上。

【问题讨论】:

    标签: jpa eclipselink apache-commons-dbcp


    【解决方案1】:

    您想要的肯定是可能的,但您可能会达到“自己动手”方法的极限。

    这是比较难解释的事情之一,但实际上有两种方法可以配置您的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 配置的 DataSource 实例提供给 EclipseLink。您需要自己解析persistence.xml 文件并通过PersistenceUnitInfo 提供该数据。同样 EclipseLink 也可能需要 TransactionManager,在这种情况下,除非您找到可以添加到 Tomcat 的 TransactionManager,否则您将被卡住。

    • 您可以使用 Java EE 6 认证版本的 Tomcat,TomEE。数据源在tomee.xml 中配置,使用DBCP 创建并完全支持您需要的所有选项,并使用描述的createContainerEntityManagerFactory 调用传递给PersistenceProvider。然后,您可以通过@PersistenceUnit 注入EntityManagerFactory 或查找它。

    如果您确实尝试使用 TomEE,请确保您的 persistence.xml 已更新为明确设置 transaction-type="RESOURCE_LOCAL",因为默认值为 JTA。尽管将JTAPersistence.createEntityManagerFactory 方法一起使用是不合规的,但没有任何持久性提供者会抱怨并让您知道您做错了什么,他们将其视为RESOURCE_LOCAL 忽略架构。因此,当您将应用程序移植到实际经过认证的服务器时,它会崩溃。

    关于 TomEE 的另一个注意事项是,在当前版本中,您必须将 EclipseLink 库放在 <tomcat>/lib/ 目录中。这是在trunk中修复的,只是还没有发布。

    如果没有随附的说明,我不确定这些幻灯片会有多大用处,但本演示文稿的第二部分是深入探讨 how container-managed EntityManager's work, specifically with regards to connection handling and transactions。您可以忽略事务部分,因为您没有使用它们并且已经在生产中,您不太可能进行显着更改,但它可能对未来的开发很有趣。

    祝你好运!

    【讨论】:

    • 嗨,大卫,感谢您的回复。您的回答基本上证实了(以非常好的和详细的方式)我最终理解的内容。由于这些原因,我选择了 GF 选项,花了几个小时来调整项目(其中大部分是针对 GF 3.1.2 附带的 Mojarra JSF 实现中的一个已知的细微错误)。我从来没有听说过 TomEE,我看过它,它似乎是一个相当新的和有前途的项目。我会在八月份试一试。再次感谢您的详细回答,非常感谢。
    猜你喜欢
    • 2011-06-10
    • 2013-09-04
    • 2012-09-24
    • 2011-06-26
    • 2019-02-10
    • 1970-01-01
    • 2015-04-29
    • 1970-01-01
    • 2012-04-29
    相关资源
    最近更新 更多