Oracle数据库ORA-00021错误分析和解决

在这里插入图片描述

好的,我们来详细解析一下 Oracle 数据库中的 ORA-00021 错误。这是一个与会话管理相关的特定错误。


官方正式语言说明

错误代码: ORA-00021
错误信息: session attached to some other process; cannot switch session
中文翻译: 会话附加到其他进程;无法切换会话

官方解释:
ORA-00021 是一个会话状态错误。它表示一个服务器进程(Server Process)尝试在其当前不拥有的 Oracle 会话上执行操作,具体来说是执行 ALTER SYSTEM KILL SESSION 命令时,目标会话与命令发出的会话是同一个会话。

在内部,每个服务器进程都附加到一个特定的会话。此错误是一种保护机制,旨在防止会话错误地终止自身或干扰其不拥有的其他会话的内部状态。会话只能由外部进程(如另一个服务器进程或后台进程)来终止。


通俗易懂的语言讲解

一句话解释: 你想用自己的右手砍掉自己的右手,这是不可能的。数据库会话也是如此——一个会话不能自己杀死自己

举个例子:

  1. 你在 SQL*Plus 中连接到了数据库,这个连接就是 会话A
  2. 在同一个 SQL*Plus 窗口里,你执行了命令:ALTER SYSTEM KILL SESSION 'A的SID, A的SERIAL#';(即你试图杀死你当前正在使用的这个会话)。
  3. 数据库会立刻阻止你这个“自杀”行为,并报错:ORA-00021。它会告诉你:“你不能自己结束自己,请让别的会话(比如另一个SQL*Plus窗口)来执行这个命令”。

原因与原理

  1. 根本原因:一个会话试图终止其自身。
  2. 数据库原理
    • 会话与进程绑定:在专用服务器模式下,一个用户会话(Session)与一个服务器进程(Server Process)是紧密绑定的。这个进程负责处理该会话的所有SQL请求和事务。
    • 内部状态管理:会话拥有复杂的内存结构(如UGA,PGA的一部分)和事务状态。允许一个会话终止自身会导致其正在使用的资源进入一个不可预测的、不一致的中间状态,从而使清理工作变得异常复杂甚至不可能。
    • 设计上的隔离:Oracle 的设计要求会话管理操作(如终止)必须由一个独立的、外部的实体来执行。这确保了操作的原子性和安全性。发出终止命令的会话(执行者)和目标被终止的会话(受害者)必须是两个独立的实体。

常见发生场景

这个错误的发生场景非常单一和明确:

  1. 用户或DBA误操作:这是唯一的场景。用户在自己的当前会话中,查询了 V$SESSION 视图找到自己会话的 SIDSERIAL#,然后直接在当前会话中执行了杀死该会话的命令。
    -- 在会话A中执行以下查询,找到了自己的SID和SERIAL#
    SELECT sid, serial#, username, machine FROM v$session WHERE username = USER;
    
    -- 假设返回:SID=123, SERIAL#=45678
    -- 接着,用户错误地在**同一个会话A**中执行:
    ALTER SYSTEM KILL SESSION '123, 45678';
    -- 此时,ORA-00021 错误立即产生。
    

相关联的其他 ORA 错误

  • ORA-00028: your session has been killed:这是成功杀死会话后,目标会话会收到的错误。当会话A成功杀死了会话B,会话B下一次尝试执行任何操作时,就会收到 ORA-00028,告知它已被终止。ORA-00021 是杀手收到的错误,而 ORA-00028 是受害者收到的错误。
  • ORA-03135: connection lost contact:如果会话被杀死后,网络或客户端没有及时收到通知,可能会抛出此错误。
  • ORA-00020: maximum number of processes exceeded:当系统进程数达到上限时,可能无法创建新的会话来执行杀死操作,但这与 ORA-00021 的直接关联性较弱。

定位原因的方法

定位 ORA-00021 的原因非常简单直接,不需要复杂的排查:

  1. 检查执行的命令:立刻回顾你刚刚执行的 ALTER SYSTEM KILL SESSION 语句。
  2. 核对会话信息:将命令中的 SIDSERIAL# 与当前会话的信息进行比对。
    -- 在你收到错误的会话中,执行以下查询:
    SELECT sid, serial# FROM v$session WHERE audsid = USERENV('SESSIONID');
    -- 或者
    SELECT sid, serial# FROM v$session WHERE sid = (SELECT DISTINCT sid FROM v$mystat);
    
  3. 确认匹配:你会发现,你要杀死的会话标识符(SID, SERIAL#)与你当前会话的标识符完全一致。这就是问题所在。

解决方案

解决 ORA-00021 的方法非常简单,就是换一个会话来执行终止操作

正确操作步骤:

  1. 打开一个新的连接:从你的客户端工具(如 SQL*Plus, SQL Developer, Toad等)重新建立一个到数据库的新会话。我们称这个新会话为 会话B。确保你在会话B中操作。
  2. 在新的会话B中查询目标会话:找到你真正想要杀死的那个会话(原来的会话A)的 SIDSERIAL#
    SELECT sid, serial#, username, program, machine, status
    FROM v$session
    WHERE username = '要杀死的用户'; -- 或根据program/machine条件查找
    
  3. 在会话B中执行终止命令:使用上一步查到的正确 SIDSERIAL#
    ALTER SYSTEM KILL SESSION '123, 45678'; -- 假设这是会话A的标识
    
  4. 验证结果:命令会返回 System altered,表示成功提交了终止请求。之后,原来的会话A(被杀死的那一个)在下次进行网络往返时(如执行一条查询),就会收到 ORA-00028 错误并被断开连接。

总结一下:
遇到 ORA-00021 -> 不要慌张,这只是一个操作方式错误 -> 打开一个新的数据库连接窗口 -> 在新的窗口里执行杀死旧会话的命令 -> 问题解决。

这个错误本身不会对数据库造成任何损害,它只是一个防止错误操作的保护性提示。

欢迎关注我的公众号《IT小Chen》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值