You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus Panache高并发事务下JDBC连接获取失败及正确关闭方法

解决Quarkus 2.16 + 非响应式Hibernate ORM下Panache高并发事务连接耗尽问题

你遇到的Unable to acquire JDBC Connection本质是数据库连接池耗尽,核心原因是并发量远超连接池承载能力,加上事务边界、线程模型和数据库操作逻辑的不合理,导致连接无法及时归还。以下是针对性的解决方案:

1. 控制并发请求量

transformToUniAndMerge默认会无限制并行执行所有请求,1000个并发请求直接打满连接池(默认连接池大小通常只有10-20)。必须限制并发数,建议设置为和连接池最大容量一致:

return multi
        .onItem().transformToUniAndMerge(10, number -> { // 10对应连接池max-size,可根据配置调整
            return Uni.createFrom()
                    .deferred(() -> executeSomeTransaction(number))
                    .runSubscriptionOn(Infrastructure.getDefaultWorkerPool());
        })

2. 优化事务边界,避免嵌套事务

你的代码存在事务嵌套问题:executeSomeTransaction已经标记了@Transactional,但updateItemNonUni又加了@Transactional(REQUIRED),这会导致事务上下文混乱,延长连接占用时间。直接去掉updateItemNonUni上的事务注解,复用外层事务即可。

3. 修复仓库更新逻辑,减少连接占用

原代码先findById再更新的方式不仅低效,还会延长连接持有时间。改用Panache的批量更新语句,直接在数据库层面完成操作:

@Override
public Uni<Void> updateItem(Item item) {
    return Uni.createFrom().deferred(() -> {
        String updateQuery = "UPDATE Item SET balance = ?1, status = ?2, updatedDate = ?3 WHERE id = ?4";
        return update(updateQuery, item.getBalance(), item.getStatus(), LocalDateTime.now(), item.getID())
                .invoke(count -> {
                    if (count == 0) {
                        throw new NoSuchElementException("Item not found with id: " + item.getID());
                    }
                })
                .replaceWithVoid();
    }).runSubscriptionOn(Infrastructure.getDefaultWorkerPool());
}

同时去掉updateItem里的emitOn——非响应式Hibernate ORM的操作必须在Worker线程完成,切换回EventLoop只会打乱事务上下文,导致连接无法及时释放。

4. 调整连接池配置

在application.properties里优化连接池参数,匹配你的并发需求:

# 连接池最大容量,根据服务器和数据库性能调整
quarkus.datasource.jdbc.max-size=20
# 最小空闲连接数
quarkus.datasource.jdbc.min-size=5
# 空闲连接超时时间,及时回收闲置连接
quarkus.datasource.jdbc.idle-timeout=30s
# 获取连接超时时间,避免无限等待
quarkus.datasource.jdbc.acquisition-timeout=5s

5. 简化线程模型

去掉executeSomeTransaction里的emitOn(MutinyHelper.executor(Vertx.currentContext()))——数据库操作完成后不需要切换回EventLoop,多余的线程切换会导致事务上下文丢失,连接无法正常归还到池子里。

总结

核心思路是控制并发量不超过连接池承载能力,同时优化事务和数据库操作逻辑,减少连接的占用时间,确保连接能及时归还到池子里。按上述调整后,连接耗尽的问题应该能得到解决。

内容的提问来源于stack exchange,提问作者Hzt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:02:03