程序不足SQL来凑

来源:这里教程网 时间:2026-03-03 18:11:37 作者:
2020  月的某天早晨,客户医院反应医保刷卡出现异常,前端程序未提示任何数据库相关的报错。软件厂商通过调式程序,定位某公共函数向数据库发送SQL  时未能得到返回值,但手动发起SQL  时都能正常返回。此函数从2001  年上线以来,一直都处于平稳运行状态,从未做过变更。另外,在紧急情况下临时重建表格可以暂时缓解上述问题。由于异常不定时出现,给客户带来了很大的困扰,因此客户,希望我们能从数据库层面彻底解决问题。

以下是应用厂商调试程序的过程,如下图所说:

上图是程序调试——  ls_paraname  参数赋值  HZYB_BRXZ  的情况

    程序调试——字段  XTSB  赋值  0  的情况

程序调试—    is_valule  值为空的情况

整个函数体的逻辑比较简单,  select  若能正常取值(即  sqlcode=0  )则开始事务,若出现异常  (即  sqlcode<>0  )则将新值插入  GY_XTCS  表,其中,  li_xtsb    ls_parametername  为绑定变量,具体程序代码如下:
//*************************************************************************************//// Author   : // Created  : 2001.5.23// Modified :// Log       ://*************************************************************************************// string ls_paraname,ls_valulels_paraname=upper(ls_csmc)select CSZ into :ls_valule from GY_XTCS whereXTSB=:li_xtsb and CSMC=:ls_paraname;IF sqlca.sqlcode <> 0 THEN gf_Begin_Transaction(sqlca) insertinto  GY_XTCS(XTSB,CSMC,CSZ,BZ,MRZ)              values(:li_xtsb,:ls_paraname,:ls_default,:ls_bz,:ls_default) ;IF sqlca.sqlcode = 0 THEN gf_Commit_Transaction(sqlca) ELSE gf_Rollback_Transaction(sqlca) END IF ls_valule=ls_defaultend ifIF IsNull(ls_valule) THEN ls_valule = ""return ls_valule
出现异常时(sqlcode<>0  ),程序提示ls_value  返回值为空,但手动PL/SQL  带入相同参数值时返回正常,表GY_XTCS  只有2000  多条记录,表结构也比较简单。代码如下:
-- Create tableSQL> create table GY_XTCS(  xtsb  NUMBER(5) default 0 not null,  csmc  VARCHAR2(40) not null,  csz   VARCHAR2(100),  mrz   VARCHAR2(40),  bz    VARCHAR2(200),  xgpb  NUMBER(1) default 0,  jgid  NUMBER(3) default 1,  xtsb2NUMBER(5) default 0)-- Create/Recreate primary, unique and foreign keyconstraintsSQL> alter table GY_XTCS  add constraintPK_GY_XTCS primary key (XTSB, CSMC);
检查故障时间段数据库告警日志、AWR  ASH  报告及历史会话信息,均未发现异常。
措施一:尝试在gy_xtcs  上加入触发器进行控制和监测,把成功或失败的信息都记录在新增的SS_ZHBC  表中,强制不让其更新,以减少重号现象的发生。创建触发器后,虽然可以阻止重号现象的发生,但依然还是存在异常。
再次怀疑表  GY_XTCS  存在脏数据(  CSZ  为空)。
措施二,删除脏数据后,程序可以正常运行一段时间,但还会不定时出现异常。
头脑风暴:既然不是脏数据,故障点手动执行语句又能正常返回,就从侧面说明故障时间点,数据库的运行是正常的。起初我们怀疑程序本身存在异常,可能根本就没有把SQL  发送给数据库,或是发送给数据库的语句没有执行,存在错误解析。
措施三,尝试开启数据库10035  解析失败跟踪,告警信息(ALERT  )中确实出现了大量无效SQL  ,但都与此次故障不相关:
SQL> ALTER SYSTEM SET EVENTS '10035 trace namecontext forever, level 1';SQL> ALTER SYSTEM SET EVENTS '10035 trace namecontext off';
问题再一次陷入僵局,回到原点再次梳理程序出现sqlcode<>0  的情况,开发人员按我们的需求带入不同的变量进行测试,测试分为以下三种场景。

   情况一:gy_xtcs  表有记录但CSZ  为空,测试结果sqlcode=0 

   情况二:gy_xtcs  表没有记录,测试结果sqlcode=100 

   情况三:gy_xtcs  表有记录,且CSZ  有值,测试结果sqlcode=0 

从整个测试结果来看,只有gy_xtcs  表没有记录的时候sqlcode<>0  XTSB  CSMC  是程序传入的值,因此不存在异常数据。
措施四,再次尝试开启应用客户端SQL  跟踪,命令如下:
SQL> execdbms_system.set_sql_trace_in_session(97,2217,true);
SQL> execdbms_system.set_sql_trace_in_session(97,2217,false);
故障时间点无任何上述查询相关信息,这个结果再次说明程序并没有将SQL  发送给数据库处理,矛头再一次指向了程序本身。
深入排查10  年前的程序,可能性不大,既然目的是解决问题,何不换一种解决思路呢?由于程序本身的逻辑并不复杂,我们完全可以用功能相同的  函数来实现,如果再次出现问题也方便后续排查。
措施五:在数据库中创建相同功能的函数,替换程序的公共函数,以降低重复交互,实现代码如下:
SQL> create or replace functiongf_getpara(li_xtsb    in number,                                      ls_csmc    in varchar2,                                      ls_default in varchar2,                                     ls_bz      in varchar2)  returnvarchar2 is  ls_valulevarchar2(100);begin  select CSZ    intols_valule    fromGY_XTCS   where XTSB= li_xtsb     and CSMC= upper(ls_csmc);  IFls_valule is null THEN    ls_valule:= '';  end if; return(ls_valule);exception  whenno_data_found then    insertinto GY_XTCS      (XTSB,CSMC, CSZ, BZ, MRZ)    values      (li_xtsb,upper(ls_csmc), ls_default, ls_bz, ls_default);    IF SQL%FOUNDTHEN      COMMIT;    else     ROLLBACK;    END IF;   return(ls_valule);end gf_getpara;
用了新函数之后,经过几个月的观察,问题再也没有出现过。
很庆幸,最终问题能够得到解决,作为乙方的技术人员查明问题的根本原因所在是很关键的,但重点还是要解决问题,而不能本末倒置钻牛角尖,如果一直排查数据库则将陷入僵局,花费大量的时间,最终损伤的是客户的利益,及时调整方向或许能够得到意想不到的效果。

相关推荐