如何在EclipseLink中正确获取JPA连接池统计数据?
问题背景
在集成EclipseLink JPA的Dropwizard框架项目中,需要采集连接池活跃连接数、总连接数等运行统计信息,使用以下代码实现时,返回的统计数据始终固定,不随实际业务流量变化:
EntityManager entityManager = (EntityManager) unitOfWorkI.getContext(); ServerSession serverSession = entityManager.unwrap(ServerSession.class); for (Map.Entry<String, ConnectionPool> entry: serverSession.getConnectionPools().entrySet()) { System.out.println("Connection Pool Name: " + entry.getKey()); System.out.println("Min number of Connections: " + entry.getValue().getMinNumberOfConnections()); System.out.println("Max number of Connections: " + entry.getValue().getMaxNumberOfConnections()); System.out.println("Connections in use: " + (entry.getValue().getMaxNumberOfConnections() - entry.getValue().getConnectionsAvailable().size())); } entityManager.close();
故障原因
- 计算逻辑错误:
getMaxNumberOfConnections()返回的是连接池配置的最大允许连接阈值,不是当前连接池实际存在的总连接数,用这个值做基数计算在用连接数从逻辑上就不成立。 - API使用错误:
getConnectionsAvailable()返回的是连接池初始化阶段生成的可用连接集合静态快照,不会同步连接借出、归还、新建、销毁的实时状态,不能用来做实时统计。 - 场景适配错误:Dropwizard JPA模块默认使用外部托管连接池(默认是HikariCP)替代EclipseLink内置连接池,此时读取EclipseLink内部
ConnectionPool对象拿到的只是初始化配置值,和实际运行的连接池完全无关。
修复方案
根据项目实际使用的连接池类型选择对应实现:
场景1:明确使用EclipseLink内置连接池
直接调用EclipseLink ConnectionPool提供的实时统计API,不要自行计算数值,修正后代码如下:
EntityManager entityManager = (EntityManager) unitOfWorkI.getContext(); ServerSession serverSession = entityManager.unwrap(ServerSession.class); for (Map.Entry<String, ConnectionPool> entry : serverSession.getConnectionPools().entrySet()) { ConnectionPool pool = entry.getValue(); System.out.println("Connection Pool Name: " + entry.getKey()); System.out.println("Min number of Connections: " + pool.getMinNumberOfConnections()); System.out.println("Max number of Connections: " + pool.getMaxNumberOfConnections()); // 实时当前总连接数 System.out.println("Total existing Connections: " + pool.getTotalNumberOfConnections()); // 实时在用连接数 System.out.println("Connections in use: " + pool.getNumberOfConnectionsInUse()); // 实时可用空闲连接数 System.out.println("Available Connections: " + pool.getNumberOfConnectionsAvailable()); } entityManager.close();
以上实时统计API从EclipseLink 2.6版本开始提供,返回值会随连接池运行状态动态更新。
场景2:使用Dropwizard默认托管的外部连接池(绝大多数Dropwizard项目的默认配置)
这种场景下不要读取EclipseLink的内部对象,直接从托管连接池拿统计值:
- 如果使用默认的HikariCP连接池,直接注入
HikariDataSource实例,通过getHikariPoolMXBean()方法获取实时指标:getActiveConnections():当前正在使用的活跃连接数getIdleConnections():当前空闲可用连接数getTotalConnections():当前连接池总连接数getThreadsAwaitingConnection():等待获取连接的阻塞线程数
- Dropwizard默认已经把连接池所有运行指标注册到了框架自带的Metrics注册表中,不需要额外手写采集逻辑,直接访问服务admin端口的metrics接口即可拿到全量监控数据。
内容的提问来源于stack exchange,提问作者Lakshan Chathuranga
相关产品推荐
相关产品推荐

