在 Hibernate/C3P0 中处理连接池耗尽并避免死锁
Handling connection pool exhaustion and avoiding deadlock in Hibernate/C3P0
我的旧应用程序跟随链查询我的数据库:Spring Tx -> Hibernate -> C3P0
。现在需要在现有架构的基础上实现新功能
我通常使用 @Transactional
注释或手动调用 PlatformTransactionManager
.
进入事务上下文
有时,为了执行异步和大数据操作,我使用 SessionFactory
API 打开一个无状态会话。我们从来没有遇到过任何额外的问题,因为我们的线程池得到了很好的控制
第一次,我的要求是并行执行多个数据库操作以加快性能。我对此有疑问,因为我对多线程操作极其小心。
对于数据库中的每个实体,我可以在单独的线程上执行协调操作。但是每个协调操作为其生成的两个线程中的每一个都使用一对连接。所以基本上每个线程有4个连接。
多线程class教导学生为了防止死锁(吃哲学家问题),资源应该以事务的方式获取:一旦你得到一个叉子,如果你不能在一个合理的时间,释放第一个再试一次。
我的问题很简单。鉴于 SessionFactory
API,如果池已满,我如何编写不会无限期等待来自 c3p0 的 4 个连接的代码?我的意思是我需要 4 StatelessSession
s 只有在有 4 个空间的情况下,否则我可以等待并重试。
据我所知,SessionFactory
API 是阻塞的,不允许设置看门狗
目前的想法是使用普通的旧解决方法。
一般来说,在 Java 世界中,如果 API 不提供获取资源的看门狗方法,您可以将其委托给 Future
,后者提供 get(int timeout, TimeUnit timeUnit)
API 来约束执行。
第一步:获取资源的看门狗定时器
基本上,我如何在超时范围内获得无状态会话?
private Future<StatelessSession> getStatelessSession(SessionFactory sessionFactory)
{
return asyncTaskExecutor.submit(new Callable<StatelessSession>()
{
@Override
public StatelessSession call() throws Exception
{
return sessionFactory.openStatelessSession();
}
});
}
try {
StatelessSession session = getStatelessSession(sessionFactory).get(3000,TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// go to step 2
}
第 2 步:像哲学家那样吃饭
正如我所说,我的问题看起来基本上就像用餐哲学家,除了我们不只有两把叉子,还有勺子和刀子,总共 4 把。
StatelessSession session1, session2, session3, session4;
for (int i=0; i<MAX_ATTEMPTS;i++) {
try {
session1 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
continue;
}
try {
session2 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session1.close();
continue;
}
try {
session3 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session2.close();
session1.close();
continue;
}
try {
session4 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session3.close();
session2.close();
session1.close();
continue;
}
}
如果超过 MAX_ATTEMPTS
会发生什么,由您决定,开发者!
我的旧应用程序跟随链查询我的数据库:Spring Tx -> Hibernate -> C3P0
。现在需要在现有架构的基础上实现新功能
我通常使用 @Transactional
注释或手动调用 PlatformTransactionManager
.
有时,为了执行异步和大数据操作,我使用 SessionFactory
API 打开一个无状态会话。我们从来没有遇到过任何额外的问题,因为我们的线程池得到了很好的控制
第一次,我的要求是并行执行多个数据库操作以加快性能。我对此有疑问,因为我对多线程操作极其小心。
对于数据库中的每个实体,我可以在单独的线程上执行协调操作。但是每个协调操作为其生成的两个线程中的每一个都使用一对连接。所以基本上每个线程有4个连接。
多线程class教导学生为了防止死锁(吃哲学家问题),资源应该以事务的方式获取:一旦你得到一个叉子,如果你不能在一个合理的时间,释放第一个再试一次。
我的问题很简单。鉴于 SessionFactory
API,如果池已满,我如何编写不会无限期等待来自 c3p0 的 4 个连接的代码?我的意思是我需要 4 StatelessSession
s 只有在有 4 个空间的情况下,否则我可以等待并重试。
据我所知,SessionFactory
API 是阻塞的,不允许设置看门狗
目前的想法是使用普通的旧解决方法。
一般来说,在 Java 世界中,如果 API 不提供获取资源的看门狗方法,您可以将其委托给 Future
,后者提供 get(int timeout, TimeUnit timeUnit)
API 来约束执行。
第一步:获取资源的看门狗定时器
基本上,我如何在超时范围内获得无状态会话?
private Future<StatelessSession> getStatelessSession(SessionFactory sessionFactory)
{
return asyncTaskExecutor.submit(new Callable<StatelessSession>()
{
@Override
public StatelessSession call() throws Exception
{
return sessionFactory.openStatelessSession();
}
});
}
try {
StatelessSession session = getStatelessSession(sessionFactory).get(3000,TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// go to step 2
}
第 2 步:像哲学家那样吃饭
正如我所说,我的问题看起来基本上就像用餐哲学家,除了我们不只有两把叉子,还有勺子和刀子,总共 4 把。
StatelessSession session1, session2, session3, session4;
for (int i=0; i<MAX_ATTEMPTS;i++) {
try {
session1 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
continue;
}
try {
session2 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session1.close();
continue;
}
try {
session3 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session2.close();
session1.close();
continue;
}
try {
session4 = tryGetSessionOrBoooooom();
} catch(TimeoutException ex) {
session3.close();
session2.close();
session1.close();
continue;
}
}
如果超过 MAX_ATTEMPTS
会发生什么,由您决定,开发者!