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

Node.js连接Oracle数据库时DELETE删除重复记录卡住无响应

问题表现
  • 开发过程中误重复发送两次携带相同insert语句的请求,导致相同记录被重复插入2次
  • 执行DELETE语句删除对应重复记录时,请求一直卡在sending request状态无法推进,问题截图:DELETE请求卡住截图
  • 测试验证规律:删除无重复值的记录(例如request_id为1002的非重复记录)时,DELETE操作可正常完成;删除存在重复值的记录(例如request_id为1001的2条重复记录)时,请求会一直卡住无响应
  • 涉及的接口实现代码如下:
var express=require('express');
var router=express.Router();
var oracledb=require('oracledb');

router.post('/ins-rpt',function(req,res,next){
//get the data from req
const {stat,rid,rptcomp,reqr}=req.body;
//connect with db
var connectionString="(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP) 
           (HOST = localhost)(PORT = 1521))(CONNECT_DATA =(SERVER 
           = DEDICATED)(SERVICE_NAME = orcl))"
oracledb.getConnection(
    {
        user: 'system',
        password:'Valli1234',
        tns:connectionString
    }, async function(err,con){
        if(err){
            res.status(500).json({
                message : 'not connected'
            })
        }
        else{
            //reqd opn
            var q="delete from rpt where request_id=:1";
            
            //send response
            await con.execute(q,[], 
             {autoCommit:true},function(e,s){
                    if(e){
                        res.status(500).json({
                            message : e
                        })
                    }
                    else
                    {
                        res.status(200).json({
                            message : s
                        })
                    }
                })
            }

        });
})

module.exports=router;
问题原因
  1. 核心阻塞原因是Oracle行锁等待:之前两次重复插入的请求,存在未正常提交/回滚的事务,这个事务一直持有那两条重复记录的行级排他锁。当新发起DELETE请求要删除这两条记录时,必须等持有锁的事务提交/回滚释放锁才能继续执行,所以会一直挂起。而测试的非重复记录是已经正常提交的,没有未释放的锁,所以删除可以正常完成。
  2. 代码本身存在3个明显bug,会放大这类问题:
    • DELETE语句用了绑定变量:1,但执行时传入的绑定参数是空数组[],根本没有传入要删除的request_id值
    • 混用了await和callback写法:oracledb的execute方法传入回调函数时不会返回Promise,加await完全无效,会导致事务状态异常、连接泄漏
    • 操作完成后没有调用con.close()释放数据库连接,连接泄漏到一定程度会直接导致所有后续数据库请求卡住
修复步骤
  1. 先处理当前的锁阻塞,登录Oracle执行以下SQL找到持有锁的会话,杀掉阻塞会话即可释放锁,之后DELETE操作就能正常执行:
-- 查询RPT表上的锁对应会话
SELECT s.sid, s.serial#
FROM v$locked_object l, dba_objects o, v$session s
WHERE l.object_id = o.object_id
AND l.session_id = s.sid
AND o.object_name = 'RPT';

-- 替换成上面查询到的sid和serial#,杀掉阻塞会话
ALTER SYSTEM KILL SESSION 'sid,serial#';
  1. 修复接口代码问题,统一用async/await写法,保证连接正确释放、参数正确传入,参考写法:
const express = require('express');
const router = express.Router();
const oracledb = require('oracledb');

router.post('/ins-rpt', async function(req, res, next) {
  const { stat, rid, rptcomp, reqr } = req.body;
  let con;
  const connectionString = "(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = orcl))";

  try {
    con = await oracledb.getConnection({
      user: 'system',
      password: 'Valli1234',
      tns: connectionString
    });

    // 绑定参数位置传要删除的request_id,这里用rid对应从请求体取的参数,按实际业务调整即可
    const deleteSql = "delete from rpt where request_id = :1";
    const result = await con.execute(deleteSql, [rid], { autoCommit: true });

    res.status(200).json({ message: result });
  } catch (err) {
    res.status(500).json({ message: err.message || '数据库操作失败' });
  } finally {
    // 无论操作成功失败,都必须释放数据库连接
    if (con) await con.close();
  }
});

module.exports = router;
  1. 长期避免重复插入问题,建议给request_id字段加唯一约束,从数据库层面直接拦截重复数据,不用靠业务逻辑兜底。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:57:21