You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

大型Oracle INSERT语句执行停滞,触发ORA-00054资源占用错误

解决ORA-00054: resource busy错误的思路(针对批量XML导入场景)

嘿,这个ORA-00054的坑我之前踩过好几次!结合你用C# + Dapper批量导入13个XML到Oracle的场景,咱们来捋捋可能的原因和解决办法:

先搞懂错误本质

ORA-00054说白了就是:你要操作的数据库资源(表、行或者锁)被别的会话占着,而你的操作因为设置了NOWAIT(或者等待超时),没法获取到锁就直接报错了。结合你跑了31分钟才出问题,大概率是长时间运行的操作积累了锁,或者中途出现了资源冲突。

排查&解决步骤

1. 先定位谁在占着资源

先登录Oracle数据库,跑这两个SQL查当前的锁情况:

-- 查被锁定的对象
SELECT lo.object_id, do.object_name, lo.session_id, lo.locked_mode
FROM v$locked_object lo
JOIN dba_objects do ON lo.object_id = do.object_id;

-- 查持有锁的会话详情
SELECT s.sid, s.serial#, s.username, s.program, s.status
FROM v$session s
WHERE s.sid IN (SELECT session_id FROM v$locked_object);
  • 如果发现是你自己的导入会话占着锁,那大概率是代码里的事务没及时提交;
  • 如果是别的会话(比如其他开发人员的查询、更新,或者其他定时任务),那得协调暂停这些操作,或者调整你的导入时间。

2. 检查事务和连接管理

长时间运行的批量操作最容易犯的错就是长事务:比如把所有13个XML的插入都放在一个大事务里,31分钟的事务会一直持有锁,不仅容易引发冲突,万一中间出错回滚也会巨慢。

  • 解决办法:拆分事务,比如每插入N条数据就提交一次(比如每1000条Commit一次)。示例代码:
using (var connection = new OracleConnection(connectionString))
{
    connection.Open();
    var transaction = connection.BeginTransaction();
    try
    {
        int batchSize = 1000;
        for (int i = 0; i < dataList.Count; i += batchSize)
        {
            var batch = dataList.Skip(i).Take(batchSize).ToList();
            string sql = "INSERT INTO your_table (col1, col2) VALUES (:Col1, :Col2)";
            connection.Execute(sql, batch, transaction: transaction);
            
            // 每批提交一次
            transaction.Commit();
            transaction = connection.BeginTransaction();
        }
        // 提交最后一批
        transaction.Commit();
    }
    catch (Exception ex)
    {
        transaction.Rollback();
        throw;
    }
}

另外,一定要确保用using块管理数据库连接,避免连接泄漏导致会话堆积锁资源。

3. 优化批量插入的效率

慢操作更容易碰到锁冲突,因为占用资源的时间太长。试试这些优化:

  • 用Dapper的批量Execute方法(上面的示例就是),比循环单条插入快得多;
  • 直接用OracleBulkCopy(Oracle官方驱动里的类),把数据转成DataTable后批量导入,效率是普通INSERT的好几倍,能大幅缩短操作时间,减少锁冲突概率。示例:
DataTable dataTable = ConvertToDataTable(yourEntityList); // 自己实现实体转DataTable的方法
using (var connection = new OracleConnection(connectionString))
{
    connection.Open();
    using (var bulkCopy = new OracleBulkCopy(connection))
    {
        bulkCopy.DestinationTableName = "YOUR_TABLE";
        // 映射列名(如果实体和表列名一致可以省略)
        bulkCopy.ColumnMappings.Add("Col1", "COL1");
        bulkCopy.ColumnMappings.Add("Col2", "COL2");
        bulkCopy.WriteToServer(dataTable);
    }
}

4. 排查隐含的DDL操作

如果你的表上有触发器,或者插入过程中调用了存储过程,要检查这些逻辑里有没有执行DDL(比如创建索引、修改表结构、更新统计信息)。DDL操作需要排他锁,一旦执行就会锁表,后续的插入都会失败。

  • 解决办法:临时禁用触发器(导入完成后再开启),或者把DDL操作移到导入完成后执行。

5. 调整超时设置

如果错误提示里有“timeout expired”,可以适当调大Dapper的commandTimeout参数,给操作更多等待锁的时间,但这只是缓解办法,核心还是要解决锁的来源:

connection.Execute(sql, dataList, commandTimeout: 600); // 设为10分钟

最后总结

先查锁定位问题根源,再从事务拆分、连接管理、插入效率这几个核心点优化,基本就能解决这个问题。如果是外部会话占锁,那就得协调资源使用时间啦!

内容的提问来源于stack exchange,提问作者Jordec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:16:59