1

使用 Hibernate、c3p0、Guice 和 Guice-persist,我们遇到了奇怪的问题,即事务后数据连接没有释放到池中。

似乎它与JpaPersistService的完成方式有关,将 EntityManager 缓存在 threadLocal 变量中:

private final ThreadLocal<EntityManager> entityManager = new ThreadLocal<EntityManager>();

我的问题是:

  • 我们是否应该删除 guice-persist 并将其替换为创建新 entityManager 的东西,然后在每次需要时关闭它(如此建议)?
  • 或者缓存 entityManager 是要走的路,我们应该用别的东西来解决我们的问题?

(我们的问题:1)mysqld在经典的8h超时后终止mysql连接,因此entityManager不再可用。可以通过开启c3p0 keep-alive来解决,但由于应用程序有时会长时间不使用,我们希望避免保持无用的活动连接。2)似乎每个EntityManager都做了一些缓存,entite在entityManager之间是不连贯的。没看怎么解决)

4

2 回答 2

3

终于找到了解决办法。

似乎这是 guice-persist 中的一个特殊错误。

如果 EntityManager 在事务外部UnitOfWork或外部注入,则会创建一个永不关闭的 EntityManager,从而导致奇怪的问题。

guice-persist 的文档并没有指出这一点。

解决方案是如果您不在事务Provider<EntityManager>EntityManagerUnitOfWork

于 2013-02-02T10:45:24.640 回答
2

我相信您遇到的问题和我遇到的一样:Guice JPA - “此连接已关闭。” 错误

这在第 730 期中有很好的描述:自动启动的 UnitOfWork 永远不会结束

使用 JpaPersistService 时,如果您尝试访问活动 UnitOfWork 之外的 EntityManager,Guice 将自动为您启动一个。然而,由于 Guice 不(也不可能)知道何时结束这个 UnitOfWork,所以它永远不会知道。

结果?在应用程序的整个生命周期中,有问题的线程将被同一个 EntityManager 卡住。这对于应用程序运行来说是一个糟糕的状态,我们不可避免地会在一段时间后耗尽可用内存并崩溃。

这里真正的杀手是当你犯了这个错误时一点都不明显。唯一真正的提示是您在不同线程之间从数据库中获取不一致的数据(由于 EM 一级缓存),或者应用程序的内存消耗不断增长。就我而言,是池中的活动连接让我怀疑它,然后,当我打开详细日志记录时,我注意到应用程序根本没有从池中借用连接,而是重用了已经持有的连接未关闭的EntityManager。

实际上,实际上报告了此问题的很多重复项:http ://code.google.com/p/google-guice/issues/list?can=1&q=UnitOfWork

因此,我认为注入 EntityManager 并没有多大用处。当您实际使用任何 EntityManager 方法时,就会出现问题。您只需要确保每个访问都在 UnitOfWork 内。如何做到这一点取决于您的应用程序。

于 2013-02-15T16:06:58.523 回答