如何在EclipseLink JPA和Tomcat 7.x中使用Apache-Commons DBCP [英] How to use Apache-Commons DBCP with EclipseLink JPA and Tomcat 7.x

查看:127
本文介绍了如何在EclipseLink JPA和Tomcat 7.x中使用Apache-Commons DBCP的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究部署在Tomcat 7上的Web应用程序,该应用程序使用EclipseLink JPA处理持久层.

I've been working on a web application, deployed on Tomcat 7, which use EclipseLink JPA to handle the persistence layer.

一切都可以在测试环境中正常运行,但是由于防火墙阻止了非活动连接的建立,因此我们在生产环境中遇到了严重的问题.基本上,如果防火墙在一段时间内不活动连接,则位于Tomcat服务器和DB服务器之间的连接将杀死该连接,结果是将陈旧"的连接保留在池中.

Everything works fine in a test environment but we're having serious issues in the production environment due to a firewall cutting killing inactive connections. Basically if a connection is inactive for a while a firewall the sits between the Tomcat server and the DB server kill it, with the result of leaving "stale" connections in the pool.

下次使用该连接时,该代码将永远不会返回,直到它收到连接超时" SQLException(下面完整的ex.getMessage()).

The next time that connection is used the code never returns, until it gets a "Connection timed out" SQLException (full ex.getMessage() below).

EL Fine]:2012-07-13 18:24:39.479--ServerSession(309463268)-连接(69352859)-线程(Thread [http-bio-8080-exec-5,5,main])- 我的查询已替换为将其发布到[EL Config]:2012-07-13 18:40:10.229--ServerSession(309463268)-连接(69352859)-线程(线程[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])-通信 尝试在A之外执行读取查询时检测到故障 交易.尝试重试查询.错误为:异常 [EclipseLink-4002](Eclipse Persistence Services- 2.3.0.v20110604-r9504):org.eclipse.persistence.exceptions.DatabaseException内部 异常:java.sql.SQLException:Eccezione IO:连接超时

EL Fine]: 2012-07-13 18:24:39.479--ServerSession(309463268)--Connection(69352859)--Thread(Thread[http-bio-8080-exec-5,5,main])-- MY QUERY REPLACED TO POST IT TO SO [EL Config]: 2012-07-13 18:40:10.229--ServerSession(309463268)--Connection(69352859)--Thread(Thread[http-bio-8080-exec-5,5,main])--disconnect [EL Info]: 2012-07-13 18:40:10.23--UnitOfWork(1062365884)--Thread(Thread[http-bio-8080-exec-5,5,main])--Communication failure detected when attempting to perform read query outside of a transaction. Attempting to retry query. Error was: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: java.sql.SQLException: Eccezione IO: Connection timed out

我已经在persistence.xml中尝试了几种配置,但是由于无法访问防火墙配置,因此使用这些方法没有运气.我也尝试使用setCheckConnections()

I already tried several configuration in the persistence.xml, but since I have no access to the firewall configuration I had no luck with these methods. I also tried to use setCheckConnections()

ConnectionPool cp = ((JpaEntityManager)em).getServerSession().getDefaultConnectionPool();
        cp.setCheckConnections();
        cp.releaseConnection(cp.acquireConnection());

我设法使用testOnBorrow,testWhileIdle和DBCP Apache Commons提供的其他功能在测试脚本中解决了该问题.我想知道如何重写EclipseLink内部连接池以使用自定义连接池,以便我可以提供基于DBCP的已配置池,而不仅仅是使用persistence.xml配置内部池.

I managed to solve the issue in a test script using testOnBorrow, testWhileIdle and other features that are avalaible from DBCP Apache Commons. I'd like to know how to override the EclipseLink internal connection pool to use a custom connection pool so that I can provide an already configured pool, based on DBCP rather than just configuring the internal one using persistence.xml.

我知道我应该提供一个SessionCustomizer,我不确定哪一个是正确的模式.基本上,我想以类似JPA的方式保留DBCP的性能.

I know I should provide a SessionCustomizer, I'm uncertain which one is the correct pattern to use. Basically I would like to preserve the performance of DBCP in a JPA-like way.

我正在Tomcat 7上进行部署,我知道如果切换到GF,就不会出现此问题,但是出于与同一台服务器上其他Web应用程序的一致性的考虑,我希望保留在Tomcat上. /p>

I'm deploying on Tomcat 7, I know that if I switch to GF I won't have this problem, but for a matter of consistency with other webapp on the same server I'd prefere to stay on Tomcat.

推荐答案

您想要的绝对有可能,但是您可能会遇到自己动手"方法的局限性.

What you want is definitely possible, but you might be hitting the limits of the "do it yourself" approach.

这是更难解释的事情之一,但是实际上有两种方法可以配置EntityManagerFactory. 自己动手"方法和容器"方法.

This is one of the more difficult things to explain, but there are effectively two ways to configure your EntityManagerFactory. The "do it yourself" approach and the "container" approach.

调用Persistence.createEntityManagerFactory时,它将最终委托给EclipseLink实现的PersistenceProvider接口的此方法:

When you call Persistence.createEntityManagerFactory it eventually delegates to this method of the PersistenceProvider interface implemented by EclipseLink:

EntityManagerFactory    createEntityManagerFactory(String emName, Map map) 

这里要做的是EclipseLink将自己承担所有工作,包括自己的连接创建和处理.这是自己动手"的方法.我对EclipseLink不太了解,是否知道是否可以使用这种方法来提供连接.在Stackoverflow上待了两天后,似乎也没有其他人知道该信息.

The deal here is EclipseLink will then take it upon itself to do all the work, including its own connection creation and handling. This is the "do it yourself" approach. I don't know EclipseLink well enough to know if there is a way to feed it connections using this approach. After two days on Stackoverflow it doesn't seem like anyone else has that info either.

所以这就是为什么这个在GF中起作用"的原因.当让容器通过注入或查找为您创建EntityManagerFactory时,容器在由EclipseLink实现的PersistenceProvider接口上使用不同的方法:

So here is why this "works in GF". When you let the container create the EntityManagerFactory for you by having it injected or looking it up, the container uses a different method on the PersistenceProvider interface implemented by EclipseLink:

EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) 

总而言之,这个PersistenceUnitInfo是容器实现的接口,上面有两个非常关键的方法:

The long and short of it is that this PersistenceUnitInfo is an interface that the container implements and has these two very key methods on it:

public DataSource getJtaDataSource();
public DataSource getNonJtaDataSource();

在这种模式下,EclipseLink不会尝试执行自己的连接处理,而只是调用这些方法来从容器中获取DataSource.这确实是您所需要的.

With this mode EclipseLink will not try to do its own connection handling and will simply call these methods to get the DataSource from the container. This is really what you need.

您可以采用两种方法解决此问题:

There are two possible approaches you could take to solving this:

  • 您可以尝试自己实例化EclipseLink PersistenceProvider实现,并调用createContainerEntityManagerFactory方法,以传入您自己的PersistenceUnitInfo接口实现,并将以DBCP配置的DataSource实例输入EclipseLink.您将需要自己解析persistence.xml文件,并通过PersistenceUnitInfo输入该数据.同样,EclipseLink也可能会期望TransactionManager,在这种情况下,除非您找到可以添加到Tomcat的TransactionManager,否则您将被困住.

  • You could attempt to instantiate the EclipseLink PersistenceProvider implementation yourself and call the createContainerEntityManagerFactory method passing in your own implementation of the PersistenceUnitInfo interface and feed the DBCP configured DataSource instances into EclipseLink that way. You would need to parse the persistence.xml file yourself and feed that data in through the PersistenceUnitInfo. As well EclipseLink might also expect a TransactionManager, in which case you'll be stuck unless you hunt down a TransactionManager you can add to Tomcat.

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

You could use the Java EE 6 certified version of Tomcat, TomEE. DataSources are configured in the tomee.xml, created using DBCP with full support for all the options you need, and passed to the PersistenceProvider using the described createContainerEntityManagerFactory call. You then get the EntityManagerFactory injected via @PersistenceUnit or look it up.

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

If you do attempt to use TomEE, make sure your persistence.xml is updated to explicitly set transaction-type="RESOURCE_LOCAL" because the default is JTA. Even though it's non-compliant to use JTA with the Persistence.createEntityManagerFactory approach, there aren't any persistence providers that will complain and let you know you're doing something wrong, they treat it as RESOURCE_LOCAL ignoring the schema. So when you go to port your app to an actual certified server, it blows up.

关于TomEE的另一个说明是,在当前版本中,您必须将EclipseLink库放在<tomcat>/lib/目录中.这已固定在行李箱中,只是尚未释放.

Another note on TomEE is that in the current release, you'll have to put your EclipseLink libs in the <tomcat>/lib/ directory. This is fixed in trunk, just not released yet.

我不确定这些幻灯片在没有附带说明的情况下将如何有用,但是本演示文稿的第二部分深入探讨了

I'm not sure how useful these slides will be without the explanation that goes along with them, but the second part of this presentation is a deep dive into how container-managed EntityManager's work, specifically with regards to connection handling and transactions. You can ignore the transaction part as you aren't using them and already have an in production you're not likely to dramatically change, but it might be interesting for future development.

祝你好运!

这篇关于如何在EclipseLink JPA和Tomcat 7.x中使用Apache-Commons DBCP的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆