【发布时间】:2009-03-16 15:21:17
【问题描述】:
我正在尝试使用 c3p0 的 ConnectionCustomizer 在我们的应用程序中记录数据库连接的创建和销毁。在其中,我有一些看起来像这样的代码:
log(C3P0Registry.getPooledDataSources())
我遇到了死锁。我发现 c3p0 在其库中至少有几个使用同步方法的对象,并且似乎没有指定它们预期的锁定顺序。当我记录连接时,我会锁定C3P0Registry,最终锁定PoolBackedDataSource(只需创建数据源列表就是访问导致锁定的哈希码)。
关闭连接提供程序(调用C3P0ConnectionProvider.close())会导致以相反的顺序调用锁。但是,当子数据源被关闭时,我的日志记录被触发了。结果是死锁。
似乎我对 c3p0 库的两个调用都是有效的预期调用:
C3P0ConnectionProvider.close()C3P0Registry.getPooledDataSources()
似乎(除非文档中明确说明)管理它自己的锁定策略应该是库的责任。 (我这样说不是为了责怪任何人.. 只是为了确认我对最佳实践的理解)
我应该如何处理这个问题?由于 c3p0 使用同步方法而不是更现代的机制,因此我无法真正测试锁。
根据我的DataSource 关闭代码,我可以先获取C3P0Registry 锁,然后再关闭DataSource。我会猜测正确的锁定顺序,我不知道我是否觉得舒服。
我认为我无法反转日志调用的锁定顺序。我需要C3P0Registry 来获取DataSources 的列表,所以如果不先锁定C3P0Registry 来获取对它们的引用,我就无法锁定DataSources。
另一个解决方案,当然是在 c3p0 之上提供另一个更高级别的锁。在连接池的情况下,这似乎与这一点无关。
现在,我正在回滚我的日志记录。感谢您的帮助。
【问题讨论】:
-
正在经历类似的事情,有兴趣了解您是否找到了更多相关信息。
-
我最终在调用 close() 的代码周围添加了一个同步块,以保证我以与日志记录相同的顺序获取锁。这很草率,但话又说回来,C3p0 中的锁定策略也是如此。
标签: java multithreading deadlock connection-pooling c3p0