使用Hibernate,c3p0,Guice和Guice-persist,我们遇到了一个奇怪的问题,即事务后数据的连接没有释放到池中。
它似乎与JpaPersistService的完成方式有关,在一个threadLocal变量中缓存EntityManager:
private final ThreadLocal<EntityManager> entityManager = new ThreadLocal<EntityManager>();
我的问题是:
(我们的问题:1)经典8h超时后mysqld杀死mysql连接,因此entityManager不再可用。可以通过启用c3p0 keep-alive来解决,但由于应用程序有时会长时间不使用,我们希望避免保持无用的主动连接。 2)似乎每个EntityManager都做一些缓存,并且entite在entityManager之间不一致。没看过如何解决这个问题)
答案 0 :(得分:3)
终于找到了解决方案。
似乎这是guice-persist中的一个特殊错误。
如果EntityManager被注入UnitOfWork
之外或者超出事务,那么就会创建一个永不关闭的EntityManager,导致出现奇怪的问题。
guice-persist的文档并未指出这一点。
如果您不在交易中或Provider<EntityManager>
EntityManager
而不是直接注入UnitOfWork
答案 1 :(得分:2)
我相信你遇到了与我相同的问题:Guice JPA - "This connection has been closed." error
这一切都在Issue 730: Automatically started UnitOfWork is never ended
中得到了很好的描述使用JpaPersistService时,如果您尝试访问 在一个活跃的UnitOfWork之外的EntityManager,Guice会 自动为您启动一个。但是,因为Guice没有(和 不知道何时结束这个UnitOfWork,它永远不会。
结果?违规线程将使用相同的EntityManager 在整个应用程序的生命周期。这是一个糟糕的状态 应用程序运行,我们不可避免地耗尽可用 一段时间后内存崩溃。
这里真正的杀手是,当你做完时,它并不是很明显 这个错误。唯一真正的提示是你得到的 不同线程之间数据库中的数据不一致(由于 EMs第一级缓存)或应用程序内存消耗 不断发展。 在我的情况下,池中的活动连接让我怀疑它,然后,当我打开详细日志记录时,我注意到应用程序根本没有从池中借用连接,而是重新使用已经由未公开的EntityManager。
实际上,报告的这个问题实际上有很多重复:http://code.google.com/p/google-guice/issues/list?can=1&q=UnitOfWork
因此,我认为注入EntityManager并不会带来太多好处。实际使用任何EntityManager方法时会发生此问题。您只需要确保每个访问都在UnitOfWork中。怎么做取决于你的申请。