如何从 com.mchange.v2.c3p0.ComboPooledDataSource 请求特定连接?
Posted
技术标签:
【中文标题】如何从 com.mchange.v2.c3p0.ComboPooledDataSource 请求特定连接?【英文标题】:How can I request a specific connection from com.mchange.v2.c3p0.ComboPooledDataSource? 【发布时间】:2017-02-16 22:31:40 【问题描述】:问题:
程序使用com.mchange.v2.c3p0.ComboPooledDataSource
连接Sybase服务器
程序依次执行runSQL1()
和runSQL2()
两种方法
runSQL1()
执行创建#temptable的SQL
SELECT * INTO #myTemp FROM TABLE1 WHERE X=2
runSQL2()
执行从 #temptable 读取的 SQL
SELECT * FROM #myTemp WHERE Y=3
问题:runSQL2()
从池中获得的数据库连接与分配给runSQL1()
的数据库连接不同。
但是,Sybase #temptables 是特定于连接的,因此 runSQL2()
在找不到表时会失败。
我能想到的最明显的解决方案(除了使池大小为 1 的退化之一,此时我们甚至不需要池),就是以某种方式记住 @987654331 使用了池中的哪个特定连接@,并让runSQL2()
请求相同的连接。
com.mchange.v2.c3p0.ComboPooledDataSource
有没有办法做到这一点?
如果可能,我想要一个并发安全的答案(换句话说,如果 runSQL1() 中使用的连接被另一个线程使用,runSQL2() 的获取连接调用将等到该连接被另一个线程释放)。
但是,如果这是不可能的,我可以接受假设数据库连接(我关心的那些)都发生在一个线程中的答案,因此 runSQL2() 请求的任何连接都将 100% 可用如果它可用于 runSQL1()。
我也欢迎任何以其他方式解决问题的解决方案,只要它们不涉及“停止使用 #temptables”作为解决方案的一部分。
【问题讨论】:
为什么不能在运行 part1 之前请求连接,然后将其作为参数传递给两个调用? @ivan 做到了。但我不喜欢这个解决方案,所以我想知道如何获得特定的连接 我也认为@Ivan 提出的解决方案是正确的解决方案。为了以任何其他方式获得它,您需要在第一次收到连接时至少保留一个标识符。完成后,您需要在池管理器上使用反射并找到匹配的连接。而不是仅仅持有对特定连接的引用更干净。如果您确实需要通过使用标识符进行查询来做到这一点,您可以编写自己的包装连接管理器并使用它。 你用你的ComboPooledDataSource
做什么?它应该在数据库使用期间保持打开状态。使用它从中获取您的连接对象。如果#temptable 依赖于特定的连接,那么您只能重复使用与执行runSQL1()
相同的连接。另外,您是否尝试过创建可共享的临时表?
【参考方案1】:
最简单和最明显的方法就是从池中请求连接,然后使用该连接运行runSQL1()
和runSQL2()
。问题中建议的使用模式违背了连接池管理器的一般设计原则,因为它将有效地将它们提升为某种事务管理器。
有一些 Java 框架可能对上述情况有所帮助。例如在 Spring 中,@Transaction
或 TransactionTemplate
可用于划分事务边界,它将保证单个线程使用单个连接(或更准确地说,根据事务传播注释)。 Spring 可以使用许多事务管理器,但最简单的可能是使用DataSourceTransactionManager,它也可以配置为使用c3p0
作为DataSource
。
【讨论】:
以上是关于如何从 com.mchange.v2.c3p0.ComboPooledDataSource 请求特定连接?的主要内容,如果未能解决你的问题,请参考以下文章
关于c3p0 的报错:com.mchange.v2.c3p0......
Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement ->
Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.mchange.v2.c3p0.ComboPoo
C3P0的详细配置说明(com.mchange.v2.c3p0.ComboPooledDataSource)