从GlassFish迁移至TomEE时Oracle数据库性能退化与连接池问题
批量插入性能衰减排查问题
问题背景
将老旧项目从Java 7迁移至Java 8,同时从GlassFish迁移至TomEE,使用Oracle 19c数据库、JDBC驱动版本8。保存数据时出现性能衰减:单条/批量保存初始耗时约60ms,但每次调用statement.executeBatch()或statement.executeQuery()的耗时逐渐增加,最终可达5分钟,进而引发连接池错误,该问题在GlassFish上未出现。
核心插入代码
Connection con = null; PreparedStatement statement = null; CallableStatement call = null; try { con = HermesDS.getConnection(); String extendedSql = "INSERT INTO hrm_wi_influence_for_ins(doc_type, doc_id, influence, cln_segment_type," + "is_user_input, pw_from_date, pw_to_date, planned_stop, inform_client," + " customer_number, service_type, address, customer_name, customer_segment, customer_sub_segment," + "SLA_CODE) " + "SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? FROM DUAL"; statement = con.prepareStatement(extendedSql); int j = 0; final int maxBatchSize = 30; con.setAutoCommit(false); long time = System.currentTimeMillis(); for (Map.Entry<String, InfluenceData> entry : influences.entrySet()) { String influence = entry.getKey().trim(); InfluenceData influenceData = entry.getValue(); statement.setString(1, docType); statement.setBigDecimal(2, docId); statement.setString(3, influence); statement.setString(4, influenceData.getSegment()); statement.setBigDecimal(5, (influenceData.getIsUserInput() != null && influenceData.getIsUserInput()) ? BigDecimal.ONE : BigDecimal.ZERO); statement.setString(6, influenceData.getPlanStart()); statement.setString(7, influenceData.getPlanEnd()); statement.setString(8, influenceData.getPlanIdle()); statement.setString(9, influenceData.getInformClient()); if (influenceData.getCustomerNumber() != null) { statement.setString(10, influenceData.getCustomerNumber().toString()); } else { statement.setString(10, ""); } statement.setString(11, influenceData.getServiceType()); statement.setString(12, influenceData.getAddress()); statement.setString(13, influenceData.getCustomerName()); statement.setString(14, influenceData.getSegment()); statement.setString(15, influenceData.getUnicornSubSegment()); statement.setString(16, influenceData.getClnSla()); statement.addBatch(); time = System.currentTimeMillis(); if (++j == maxBatchSize) { statement.executeBatch(); con.commit(); statement.clearBatch(); j = 0; System.out.println("executeBatch finished in: " + (System.currentTimeMillis() - time) + "ms"); } } } // 注:原代码未展示finally块的资源释放逻辑
日志现象
前30条:
INSERT INTO hrm_wi_influence_for_ins --> 17ms
executeBatch finished in: 24ms接下来30条:
--> 10ms
executeBatch finished in: 19ms后续某批次30条:
--> 6ms
executeBatch finished in: 2947ms
观察到statement.clearBatch()未有效清空批处理,所有行在查询中累积,初始30行,10次操作后变为300行,导致耗时激增。
TomEE数据源配置
JdbcDriver oracle.jdbc.OracleDriver JdbcUrl jdbc:oracle:thin:--------- UserName --------- Password --------- accessToUnderlyingConnectionAllowed = true jtaManaged = false DataSourceCreator = tomcat initialSize=10 maxActive=100 maxIdle=20 minIdle=10 timeBetweenEvictionRunsMillis=34000 minEvictableIdleTimeMillis=55000 validationQuery=SELECT 1 from dual validationInterval=30000 testOnBorrow=true removeAbandoned=true removeAbandonedTimeout=1200 logAbandoned=true
排查思路
验证批处理清空逻辑:
- 打印
executeBatch()返回的影响行数数组,确认每次是否仅处理30条数据。若返回数组长度大于30,说明批处理未被正确清空。 - 替换
clearBatch()逻辑:每次执行完批处理后关闭当前PreparedStatement,重新创建新实例继续添加数据。若性能恢复稳定,说明原clearBatch()未生效,可能是驱动或容器的statement缓存问题。
- 打印
检查JDBC驱动兼容性:
- 确认Oracle JDBC驱动8与Oracle 19c的匹配性,排查是否存在批处理相关已知bug。
- 尝试升级/降级JDBC驱动至稳定兼容版本,验证问题是否消失。
排查连接池配置:
- 添加
statementCacheSize=0关闭Tomcat数据源的statement缓存,避免缓存实例残留批处理数据。 - 临时关闭
removeAbandoned(设为false)、延长validationInterval,观察是否因连接验证或资源回收导致额外开销。
- 添加
数据库端排查:
- 查询Oracle的
v$sql视图,查看批量SQL的实际执行计划和绑定参数数量,确认是否存在批处理累积。 - 通过
v$session_wait查看会话等待事件,排查锁等待、redo日志瓶颈、表空间不足等问题。
- 查询Oracle的
代码逻辑补全:
- 循环结束后添加判断,执行剩余未达批量大小的批处理数据并提交,避免后续复用statement时累积数据。
- 确认finally块中是否正确关闭
PreparedStatement和Connection,避免资源泄漏导致连接池耗尽。
关于clearBatch()的说明
根据JDBC规范,clearBatch()用于清空当前PreparedStatement中所有已添加的批处理命令,调用后addBatch()应重新累积新命令。正常情况下,Oracle JDBC驱动的clearBatch()会清空内部维护的批处理数组。若出现未清空的情况,可能是:
- 驱动版本存在bug,导致批处理命令未被正确清除;
- TomEE/Tomcat的statement缓存机制复用了未清空的实例;
- 代码存在线程安全问题(当前代码中statement为方法内局部变量,此可能性较低)。
内容的提问来源于stack exchange,提问作者Sergej Kalva
相关产品推荐
相关产品推荐

