Oracle记录被锁的查询与强制删除方法

问题场景

在Oracle数据库日常运维中,我们经常会遇到数据记录被锁定的情况。当一个用户正在修改某条记录时,Oracle会自动对该记录加锁,以防止其他用户同时修改造成数据不一致。但有时由于程序异常、事务未正常提交或用户误操作,会导致锁长时间持有,影响其他用户的正常操作。

查询被锁记录

要解决锁问题,首先需要查看当前数据库中的锁情况。以下是常用的查询语句:

sql 复制代码
-- 查询当前被锁的对象和会话信息
SELECT 
    t2.username,
    t2.sid,
    t2.serial#,
    t2.logon_time,
    t1.object_id,
    t1.oracle_username,
    t1.os_user_name,
    t1.process,
    t1.locked_mode
FROM 
    v$locked_object t1,
    v$session t2 
WHERE 
    t1.session_id = t2.sid 
ORDER BY 
    t2.logon_time;

查询结果字段说明

字段名 说明

username 数据库用户名

sid 会话ID

serial# 会话序列号

logon_time 登录时间

object_id 被锁对象ID

oracle_username Oracle用户名

os_user_name 操作系统用户名

process 操作系统进程ID

locked_mode 锁模式

更详细的锁信息查询

sql 复制代码
-- 查询更详细的锁信息,包括SQL语句
SELECT 
    s.username,
    s.sid,
    s.serial#,
    s.status,
    l.object_id,
    o.object_name,
    o.object_type,
    l.locked_mode,
    s.machine,
    s.program,
    s.sql_id,
    sq.sql_text
FROM 
    v$locked_object l,
    dba_objects o,
    v$session s,
    v$sql sq
WHERE 
    l.object_id = o.object_id
    AND l.session_id = s.sid
    AND s.sql_id = sq.sql_id(+)
ORDER BY 
    s.logon_time;
sql 复制代码
强制删除锁记录
确认了被锁的会话后,可以使用以下命令强制终止会话:

sql
-- 终止指定会话
ALTER SYSTEM KILL SESSION 'sid,serial#';

-- 示例:终止sid=123, serial#=456的会话
ALTER SYSTEM KILL SESSION '123,456';
立即终止会话
如果会话无法正常终止,可以加上IMMEDIATE选项:

sql
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;

完整处理流程

步骤1:查询锁信息

首先执行查询语句,找出锁定的对象和相关会话。

步骤2:分析锁原因

查看:

哪个用户持有锁

锁了多长时间

执行的是什么SQL语句

是否可以通过联系用户解决

步骤3:尝试正常解决

如果可能,联系持有锁的用户:

请其提交或回滚事务

检查应用程序是否正常

步骤4:强制终止会话

如果无法联系用户或问题急需解决,使用KILL SESSION命令。

步骤5:验证结果

终止后再次查询锁信息,确认锁已被释放。

注意事项

  1. 风险提示
    数据一致性:强制终止会话可能导致未提交的事务回滚

业务影响:正在执行的操作会被中断

依赖会话:某些会话可能是关键业务进程

  1. 最佳实践
sql 复制代码
sql
-- 在终止前,可以先查看会话的详细信息
SELECT 
    sid,
    serial#,
    username,
    program,
    machine,
    status,
    to_char(logon_time, 'yyyy-mm-dd hh24:mi:ss') as logon_time,
    last_call_et/3600 as hours_active
FROM 
    v$session
WHERE 
    sid = [目标SID];

-- 终止前记录信息,便于审计

INSERT INTO session_kill_audit

(kill_time, sid, serial#, username, killer, reason)

VALUES

(SYSDATE, 123, 456, 'USER_A', USER, '会话长时间持有锁');

  1. 防止锁问题的建议
sql 复制代码
sql
-- 1. 设置会话超时
ALTER PROFILE DEFAULT LIMIT IDLE_TIME 30;  -- 30分钟空闲超时

-- 2. 监控长时间运行的会话
SELECT 
    s.sid,
    s.serial#,
    s.username,
    s.program,
    s.status,
    s.last_call_et/60 as minutes_idle,
    t.start_time,
    t.used_ublk
FROM 
    v$session s,
    v$transaction t
WHERE 
    s.taddr = t.addr(+)
    AND s.status = 'ACTIVE'
    AND s.last_call_et > 300  -- 超过5分钟
ORDER BY 
    s.last_call_et DESC;

-- 3. 使用NOWAIT选项避免等待锁

SELECT * FROM table_name FOR UPDATE NOWAIT;

高级锁管理

查询锁等待链

sql 复制代码
sql
-- 查看锁等待关系
SELECT 
    (SELECT username FROM v$session WHERE sid = a.sid) blocker,
    a.sid,
    ' is blocking ',
    (SELECT username FROM v$session WHERE sid = b.sid) blocked,
    b.sid
FROM 
    v$lock a,
    v$lock b
WHERE 
    a.block = 1
    AND b.request > 0
    AND a.id1 = b.id1
    AND a.id2 = b.id2;

查询具体的锁类型

sql 复制代码
sql
-- 锁模式说明
SELECT 
    lm.locked_mode,
    lm.mode_description,
    COUNT(*) as lock_count
FROM 
    v$locked_object lo,
    (SELECT 0 locked_mode, 'None' mode_description FROM dual UNION ALL
     SELECT 1, 'Null (NULL)' FROM dual UNION ALL
     SELECT 2, 'Row-S (SS)' FROM dual UNION ALL
     SELECT 3, 'Row-X (SX)' FROM dual UNION ALL
     SELECT 4, 'Share (S)' FROM dual UNION ALL
     SELECT 5, 'S/Row-X (SSX)' FROM dual UNION ALL
     SELECT 6, 'Exclusive (X)' FROM dual) lm
WHERE 
    lo.locked_mode = lm.locked_mode
GROUP BY 
    lm.locked_mode, lm.mode_description
ORDER BY 
    lm.locked_mode;

自动化监控脚本

可以创建定期作业监控锁情况:

sql 复制代码
sql
-- 创建锁监控表
CREATE TABLE lock_monitor (
    monitor_time DATE,
    username VARCHAR2(30),
    sid NUMBER,
    serial# NUMBER,
    object_name VARCHAR2(128),
    locked_mode NUMBER,
    session_status VARCHAR2(8),
    minutes_active NUMBER
);
sql 复制代码
-- 创建监控作业
BEGIN
    DBMS_SCHEDULER.create_job (
        job_name        => 'LOCK_MONITOR_JOB',
        job_type        => 'PLSQL_BLOCK',
        job_action      => 'BEGIN
            INSERT INTO lock_monitor
            SELECT 
                SYSDATE,
                s.username,
                s.sid,
                s.serial#,
                o.object_name,
                lo.locked_mode,
                s.status,
                s.last_call_et/60
            FROM 
                v$locked_object lo,
                dba_objects o,
                v$session s
            WHERE 
                lo.object_id = o.object_id
                AND lo.session_id = s.sid
                AND s.last_call_et > 300;  -- 超过5分钟
            COMMIT;
        END;',
        start_date      => SYSTIMESTAMP,
        repeat_interval => 'FREQ=MINUTELY;INTERVAL=5',
        enabled         => TRUE
    );
END;

总结:

Oracle锁管理是DBA日常工作的重要组成部分。正确处理锁问题需要:

准确诊断:使用正确的查询找出问题根源

谨慎操作:在强制终止前评估影响

预防为主:通过监控和优化减少锁问题发生

文档记录:所有操作应有记录,便于追溯和分析

相关推荐
imbackneverdie1 小时前
2025国自然资助率12.29%创新低!2026年如何用数据与AI“破局”?
数据库·人工智能·自然语言处理·aigc·ai写作·课题·国家自然科学基金
3824278271 小时前
python:mysql数据库
数据库·python·mysql
小宇的天下1 小时前
Calibre DESIGNrev DRC/LVS启动和准备文件(10-1)
服务器·数据库·oracle
我爱娃哈哈1 小时前
告别Redis瓶颈:Caffeine本地缓存优化实战指南
数据库·redis·缓存
虾说羊1 小时前
transferManager为什么在工作中禁止使用 (怎么进行优化 怎么避免多线程的堵塞)
java·服务器·数据库
机灵猫1 小时前
Redis 内部机制:持久化、内存淘汰与延迟优化
数据库·redis·缓存
小成很成1 小时前
sql 开发基础版(命令)
数据库·mysql
ClouGence1 小时前
打通复杂医疗数据链路:某头部医疗服务商的数据底座落地经验分享
数据库·经验分享·数据分析
我在北国不背锅2 小时前
Milvus向量数据库索引说明
数据库·milvus
9稳2 小时前
基于PLC的液体自动混合加热控制系统设计
开发语言·网络·数据库·labview·plc