ORA-12516 错误解决方案ORA-12516: TNS:listener could not find available handler with matching protocol stac
ORA-12516 错误主要是由于数据库连接数不足导致的。短期: 关闭空闲连接,释放资源长期: 增加processes和sessions参数预防: 优化应用程序连接管理,配置合理的连接池监控: 定期检查连接数使用情况,设置告警最佳实践数据库层面:设置合理的processes参数(建议至少 300)应用层面:使用连接池,确保连接正确关闭运维层面:定期监控,及时发现问题。
错误信息
ORA-12516: TNS:listener could not find available handler with matching protocol stack
错误含义
TNS 监听器无法找到可用的处理程序来匹配协议栈,通常表示数据库连接数已满。
问题诊断
1. 检查当前连接数
-- 查看当前会话数 SELECT COUNT(*) FROM v$session; -- 查看最大会话数 SELECT value FROM v$parameter WHERE name = 'sessions'; -- 查看当前进程数 SELECT COUNT(*) FROM v$process; -- 查看最大进程数 SELECT value FROM v$parameter WHERE name = 'processes';
2. 典型问题场景
-
当前进程数: 149
-
最大进程数: 150
-
结论: 进程数已达上限,无法创建新连接
解决方案
方案一:临时解决(紧急情况)
1. 查看并关闭空闲连接
-- 查看所有会话 SELECT sid, serial#, username, status, machine, program, logon_time FROM v$session WHERE username IS NOT NULL ORDER BY status, logon_time; -- 查看空闲连接 SELECT sid, serial#, username, status, machine FROM v$session WHERE status = 'INACTIVE' AND username IS NOT NULL; -- 杀掉特定会话(谨慎操作) ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;
2. 重启监听器
lsnrctl stop lsnrctl start
3. 重启数据库(如果可以)
SHUTDOWN IMMEDIATE; STARTUP;
方案二:永久解决(推荐)
1. 增加数据库进程数
-- 以 sysdba 身份登录
sqlplus / as sysdba
-- 增加 processes 参数到 300(根据实际需求调整)
ALTER SYSTEM SET processes=300 SCOPE=SPFILE;
-- 相应地增加 sessions 参数(通常是 processes * 1.1 + 5)
ALTER SYSTEM SET sessions=335 SCOPE=SPFILE;
-- 重启数据库使参数生效
SHUTDOWN IMMEDIATE;
STARTUP;
-- 验证修改
SELECT name, value FROM v$parameter WHERE name IN ('processes', 'sessions');
-- 或使用 SHOW 命令
SHOW PARAMETER processes;
SHOW PARAMETER sessions;
2. 推荐的参数值
| 应用规模 | processes | sessions | 说明 |
|---|---|---|---|
| 小型应用 | 200 | 225 | 适合小型企业应用 |
| 中型应用 | 300 | 335 | 适合中等规模应用 |
| 大型应用 | 500 | 555 | 适合大型企业应用 |
计算公式: sessions = processes * 1.1 + 5
注意: 增加 processes 会增加内存消耗,需要确保服务器有足够的内存。
应用程序层面优化
1. 检查连接泄漏
Java 示例(正确的连接管理)
// 使用 try-with-resources 自动关闭连接
try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
// 处理结果
} catch (SQLException e) {
// 异常处理
}
传统方式(确保在 finally 中关闭)
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection();
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
// 处理结果
} catch (SQLException e) {
// 异常处理
} finally {
if (rs != null) try { rs.close(); } catch (SQLException e) {}
if (stmt != null) try { stmt.close(); } catch (SQLException e) {}
if (conn != null) try { conn.close(); } catch (SQLException e) {}
}
2. 优化连接池配置
HikariCP 配置示例
# 最大连接数(不要超过数据库的 processes 限制) spring.datasource.hikari.maximum-pool-size=50 # 最小空闲连接数 spring.datasource.hikari.minimum-idle=5 # 连接超时时间(毫秒) spring.datasource.hikari.connection-timeout=30000 # 空闲连接最大存活时间(毫秒) spring.datasource.hikari.idle-timeout=600000 # 连接最大生命周期(毫秒) spring.datasource.hikari.max-lifetime=1800000
Druid 配置示例
# 初始化连接数 spring.datasource.druid.initial-size=5 # 最小空闲连接数 spring.datasource.druid.min-idle=5 # 最大活跃连接数 spring.datasource.druid.max-active=50 # 获取连接等待超时时间 spring.datasource.druid.max-wait=60000 # 配置间隔多久进行一次检测,检测需要关闭的空闲连接(毫秒) spring.datasource.druid.time-between-eviction-runs-millis=60000 # 配置连接在池中最小生存时间(毫秒) spring.datasource.druid.min-evictable-idle-time-millis=300000
3. 查找长时间运行的会话
-- 查找连接时间超过 1 小时的会话 SELECT sid, serial#, username, status, ROUND((SYSDATE - logon_time) * 24, 2) AS hours_connected, machine, program, sql_id FROM v$session WHERE username IS NOT NULL AND (SYSDATE - logon_time) * 24 > 1 ORDER BY logon_time; -- 查看会话正在执行的 SQL SELECT s.sid, s.serial#, s.username, s.status, q.sql_text FROM v$session s LEFT JOIN v$sql q ON s.sql_id = q.sql_id WHERE s.username IS NOT NULL AND s.status = 'ACTIVE';
常见原因分析
1. 数据库连接数已满
-
原因:
processes参数设置过小 -
解决: 增加
processes和sessions参数
2. 连接池泄漏
-
原因: 应用程序没有正确释放数据库连接
-
解决: 检查代码,确保所有连接都被正确关闭
3. 数据库实例过载
-
原因: 数据库负载过高,无法处理新的连接请求
-
解决: 优化 SQL 查询,增加服务器资源
4. 监听器配置问题
-
原因: TNS 监听器配置不正确
-
解决: 检查
listener.ora和tnsnames.ora配置
监控和预防
1. 定期监控连接数
-- 创建监控视图 CREATE OR REPLACE VIEW v_connection_monitor AS SELECT (SELECT value FROM v$parameter WHERE name = 'processes') AS max_processes, (SELECT COUNT(*) FROM v$process) AS current_processes, ROUND((SELECT COUNT(*) FROM v$process) / (SELECT value FROM v$parameter WHERE name = 'processes') * 100, 2) AS usage_percent, (SELECT value FROM v$parameter WHERE name = 'sessions') AS max_sessions, (SELECT COUNT(*) FROM v$session) AS current_sessions FROM dual; -- 查询监控数据 SELECT * FROM v_connection_monitor;
2. 设置告警阈值
当连接数使用率超过 80% 时,应该发出告警。
3. 定期清理空闲连接
-- 创建定时任务清理超过 2 小时的空闲连接 BEGIN DBMS_SCHEDULER.CREATE_JOB ( job_name => 'KILL_IDLE_SESSIONS', job_type => 'PLSQL_BLOCK', job_action => 'BEGIN FOR rec IN (SELECT sid, serial# FROM v$session WHERE status = ''INACTIVE'' AND username IS NOT NULL AND (SYSDATE - logon_time) * 24 > 2) LOOP EXECUTE IMMEDIATE ''ALTER SYSTEM KILL SESSION '''''' || rec.sid || '','' || rec.serial# || '''''' IMMEDIATE''; END LOOP; END;', start_date => SYSTIMESTAMP, repeat_interval => 'FREQ=HOURLY; INTERVAL=1', enabled => TRUE ); END; /
快速操作清单
紧急情况(5分钟内解决)
-- 1. 检查当前状态 SELECT COUNT(*) FROM v$process; SELECT value FROM v$parameter WHERE name = 'processes'; -- 2. 杀掉空闲会话 SELECT 'ALTER SYSTEM KILL SESSION ''' || sid || ',' || serial# || ''' IMMEDIATE;' FROM v$session WHERE status = 'INACTIVE' AND username IS NOT NULL; -- 3. 执行生成的 KILL 语句
永久解决(需要重启数据库)
-- 1. 以 sysdba 登录 sqlplus / as sysdba -- 2. 修改参数 ALTER SYSTEM SET processes=300 SCOPE=SPFILE; ALTER SYSTEM SET sessions=335 SCOPE=SPFILE; -- 3. 重启数据库 SHUTDOWN IMMEDIATE; STARTUP; -- 4. 验证 SHOW PARAMETER processes; SHOW PARAMETER sessions;
相关错误代码
-
ORA-12516: 连接数已满
-
ORA-12518: 监听器无法分配连接
-
ORA-12519: 超过最大连接数
-
ORA-00020: 超过最大进程数
参考资料
总结
ORA-12516 错误主要是由于数据库连接数不足导致的。解决方案包括:
-
短期: 关闭空闲连接,释放资源
-
长期: 增加
processes和sessions参数 -
预防: 优化应用程序连接管理,配置合理的连接池
-
监控: 定期检查连接数使用情况,设置告警
最佳实践:
-
数据库层面:设置合理的
processes参数(建议至少 300) -
应用层面:使用连接池,确保连接正确关闭
-
运维层面:定期监控,及时发现问题
更多推荐


所有评论(0)