【问题标题】:Lock Ordering in C3p0C3p0 中的锁排序
【发布时间】: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


【解决方案1】:

我不知道如何解决锁定问题,但我认为你应该退后一步,想想原来的问题。 “我正在尝试在我们的应用程序中记录数据库连接的创建和销毁...”

我会推荐以下。

创建一个类并使其实现 javax.sql.DataSource。 创建一个相同类型的字段并将所有方法委托给它。 在 getConnection() 方法中返回您自己的 Connection 类环绕 java.sql.Connection 等等。 然后将此类包装在您的原始数据源周围。 在您的课程中,您现在可以简单地创建一个记录器并记录您希望在日志中看到的所有操作。

【讨论】:

    猜你喜欢
    • 2017-06-13
    • 1970-01-01
    • 2019-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多