PL/SQL代码的一次BUG追踪
本周测试同事,在测试我做的一个需求的时候,发现了这么一个bug。
CDMS下发下游系统的数据中,有几条数据有问题,因为其中两个字段是有关联的,都是从同一个字段扩展来的,明眼一看就有问题。
可是这几条数据,都是在cursor里处理的,不会出现,前一个字段扩展用的值是一个样,后一个字段扩展用的是另一个。
我就很费解,并且我在开发环境无法重现。我试了几组数据,下发都没有问题。
然后我就开始检查测试环境出错的数据,发现了猫腻。
现在我就拿Java代码模拟一下这个BUG。
下发下游的数据为Security,如下类所示,我简单的建了三个字段。
package com.chengjf.fxdemo;
public class Security {
// 证券ID
private String securityID;
// 证券名称
private String securityName;
// 证券市场
private String market;
public Security(String securityID, String securityName, String market) {
this.securityID = securityID;
this.securityName = securityName;
this.market = market;
}
public String getSecurityID() {
return securityID;
}
public void setSecurityID(String securityID) {
this.securityID = securityID;
}
public String getSecurityName() {
return securityName;
}
public void setSecurityName(String securityName) {
this.securityName = securityName;
}
public String getMarket() {
return market;
}
public void setMarket(String market) {
this.market = market;
}
}
下发逻辑如下:
public class OracleException {
// 模拟数据库
private Map<String, String> db = new HashMap<String, String>(8);
public static void main(String[] args) {
OracleException exception = new OracleException();
Collection<Security> collection = getSecurities();
Iterator<Security> iterator = collection.iterator();
// 要插入数据库的字段
String systemID = null;
String tradeID = null;
while (iterator.hasNext()) {
Security security = iterator.next();
try {
// 对systemID进行处理
// !这块处理的时候,某些数据不符合条件,导致没有生成systemID
// !而是用上一次处理生成的ID
if ("1".equals(security.getMarket())) {
systemID = security.getSecurityID() + "_SYSTEM";
}
// 对tradeID继续处理
tradeID = security.getSecurityID() + "_TRADE";
// 插入数据库
exception.insertIntoDB(systemID, tradeID);
} catch (IllegalArgumentException e) {
System.err.println(e);
}
}
// 输出数据库结果
System.out.println(exception.db);
/*
* 000002_SYSTEM=600002_TRADE,
* 000001_SYSTEM=000001_TRADE,
* 000003_SYSTEM=000003_TRADE,
* 000004_SYSTEM=600004_TRADE
* 000002竟然对应600002,00004竟然对应600004
* 显然错误
*/
}
/**
* 插入数据库,如果systemID没有则插入,有则更新 借助Map结构的特性
*
* @param systemID
* @param tradeID
*/
private void insertIntoDB(String systemID, String tradeID) {
if (systemID != null && tradeID != null) {
this.db.put(systemID, tradeID);
} else {
throw new IllegalArgumentException();
}
}
/**
* 数据源Cursor
*
* @return
*/
private static Collection<Security> getSecurities() {
Security security1 = new Security("000001", "平安银行", "1");
Security security2 = new Security("000002", "万科A", "1");
Security security3 = new Security("600001", "邯郸钢铁", "2");
Security security4 = new Security("600002", "齐鲁石化", "2");
Security security5 = new Security("000003", "PT金田A", "1");
Security security6 = new Security("000004", "国农科技", "1");
Security security7 = new Security("600003", "ST东北高", "2");
Security security8 = new Security("600004", "白云机场", "2");
return Arrays.asList(new Security[] { security1, security2, security3,
security4, security5, security6, security7, security8 });
}
}
出现BUG原因的,就是在对数据进行处理的时候,没有对每条数据的context进行初始化。下一条数据因为一些逻辑,某些值竟然和上一条数据的某些值相同或者有关系。最终造成了数据不一致的结果。
然而,我发现这种代码在系统中很多,特别是在PL/SQL中。一般变量只在begin开头初始化,每次cursor的loop里都没有重新初始化,都有这种BUG的隐患。
同时,这种BUG应该是最简单的一个BUG,但是可能也是最容易犯的。这种BUG发生的时候跟处理的数据有关系,一般数据正常的时候不会出现这种BUG,但是数据如果有问题,就不灵了。
这种BUG不容易发现,但是应该谨记:
数据初始化非常重要。保证数据处理时的context一切正常。