错误信息

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 参数设置过小

  • 解决: 增加 processessessions 参数

2. 连接池泄漏

  • 原因: 应用程序没有正确释放数据库连接

  • 解决: 检查代码,确保所有连接都被正确关闭

3. 数据库实例过载

  • 原因: 数据库负载过高,无法处理新的连接请求

  • 解决: 优化 SQL 查询,增加服务器资源

4. 监听器配置问题

  • 原因: TNS 监听器配置不正确

  • 解决: 检查 listener.oratnsnames.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 错误主要是由于数据库连接数不足导致的。解决方案包括:

  1. 短期: 关闭空闲连接,释放资源

  2. 长期: 增加 processessessions 参数

  3. 预防: 优化应用程序连接管理,配置合理的连接池

  4. 监控: 定期检查连接数使用情况,设置告警

最佳实践:

  • 数据库层面:设置合理的 processes 参数(建议至少 300)

  • 应用层面:使用连接池,确保连接正确关闭

  • 运维层面:定期监控,及时发现问题

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐