sessions_per_user必须配合resource_limit=true才生效,且须通过profile显式绑定用户;它仅限制认证后的数据库会话数(v$session中status为active或inactive),不控制tcp连接或连接池空闲连接。

SESSIONS_PER_USER 必须配合 RESOURCE_LIMIT=TRUE 才生效
单独执行 CREATE PROFILE 并设置 SESSIONS_PER_USER,数据库完全无视——这是最常被忽略的前提。Oracle 默认关闭所有资源限制,RESOURCE_LIMIT 参数必须为 TRUE,否则任何 PROFILE 中的资源项(包括 SESSIONS_PER_USER)全部失效。
检查当前状态:SHOW PARAMETER resource_limit;若返回 FALSE,立即执行:ALTER SYSTEM SET resource_limit = TRUE SCOPE = BOTH。该操作无需重启实例,但会影响所有后续新建会话。
注意:该参数对密码策略类限制(如 FAILED_LOGIN_ATTEMPTS)无影响,那些始终生效。
PROFILE 绑定必须显式执行 ALTER USER,不能直接改用户
很多人误以为 ALTER USER app_user LIMIT SESSIONS_PER_USER 3 可行,实际语法错误。Oracle 不允许直接在 ALTER USER 中指定资源限制,必须通过 PROFILE 作为中间层。
正确流程只有三步,缺一不可:
- 创建或修改
PROFILE:CREATE PROFILE app_limit LIMIT SESSIONS_PER_USER 3 - 将该
PROFILE显式绑定到用户:ALTER USER app_user PROFILE app_limit - 验证是否落地:
SELECT LIMIT FROM DBA_PROFILES WHERE PROFILE = 'APP_LIMIT' AND RESOURCE_NAME = 'SESSIONS_PER_USER'
已存在的会话不受影响,新连接才会触发限制。改小限额(如从 10 改成 5)不会踢掉已有会话,只拦第 6 次登录。
连接池场景下 SESSIONS_PER_USER 容易被误判为“网络连接数”
SESSIONS_PER_USER 统计的是 v$session 中 USERNAME 相同且 STATUS IN ('ACTIVE', 'INACTIVE') 的记录数,不是 TCP 连接、不是连接池空闲连接、也不是监听器排队请求数。
典型误判现象:
- HikariCP 配了
maximumPoolSize=20,但SESSIONS_PER_USER=5→ 应用一启动就报ORA-02391 - WebLogic 自身维护连接池,又叠加应用层池 → 实际会话数翻倍
- 应用未调用
Connection.close(),大量INACTIVE会话长期滞留,查v$session能看到但应用日志无异常
排查建议:直接查 SELECT COUNT(*) FROM v$session WHERE USERNAME = 'APP_USER',结果 > 限制值即确认是数据库侧超限,而非网络或驱动问题。
Java 多线程环境需额外防 Semaphore 实例泄漏
如果应用层自己实现连接控制(非用 HikariCP 等成熟池),用 Semaphore 限流时,常见致命错误是把 Semaphore 声明为实例变量:Semaphore counter = new Semaphore(8)。
10 个线程各持一个 DatabaseConnection 实例 → 10 个独立 Semaphore → 理论最大连接数变成 10 × 8 = 80,远超 Oracle 服务端配置的 8 会话上限。
必须改为静态共享:
private static final Semaphore CONNECTION_LIMIT = new Semaphore(8, true);
并且在 getConnection() 获取失败时,务必调用 CONNECTION_LIMIT.release(),否则许可泄露导致后续所有线程永久阻塞。
真正难处理的不是配置本身,而是连接池与数据库会话生命周期的错位:close() 只归还逻辑连接,不等于服务端 session 立即释放;而 SESSIONS_PER_USER 数的是服务端真实存活的 session。这两者之间的 gap,必须靠监控 v$session 和规范连接使用习惯来弥合。











