一段Web代码,发生了错误。但是很少发生,应该说是极少,几乎无法重现,代码是另一位同事写的,并且已经用了很久了。
这个BUG可不好找了。好在有错误日志,很快就定位了出错的地方
public static void LoadConfig(){
......
iMapAlise=new ListDictionary ();
try
{
if(iConnString!=null && iConnString!="")
{
if(Config.isDebug) writeLog(iConnString);
System.Data.DataTable dt=getDataTable(Config.attrDBConnString ,"SELECT * FROM GIS_MAPS","MAPS","MAPNAME");
for(int i=0;i<dt.Rows.Count ;i++)
{
string name=dt.Rows[i]["MAPNAME"].ToString ();
string path=dt.Rows[i]["MAPPATH"].ToString ();
if(!System.IO.File.Exists (path)) Config.writeLog ( name+","+path);
iMapAlise.Add (name,path); //错误就发生在此行,说有重复键值
}
dt.Dispose ();
}
alreadyLoaded=true;
}
}
......
}
数据库里面的表主键就是MAPNAME,不可能重复呀。iMapAlise在每次调用的时候都是新new出来的,也不应该重复。难道在程序里面还有别的地方给iMapAlise赋值了?
应用查找大法,第一个找到的iMapAlise当然是声明:
internal static ListDictionary iMapAlise;
问题出来了,静态的!如果有两个地方同时,或间隔时间很短的调用了LoadConfig就会发生错误,场景应该是这样的:
LoadConfig()//CallA
LoadConfig()//CallB
CallA执行iMapAlise=new ListDictionary ();
CallB在CallA开始在iMapAlise中插入数据之前执行iMapAlise=new ListDictionary ();
CallA从数据库中取出数据,比如Name="MapA";
CallA执行iMapAlise.Add (name,path);
CallB从数据库中取出数据,比如Name="MapA";
CallB执行iMapAlise.Add (name,path);
发生错误了!
因为反复测试都没有再出错,无奈,写程序验证我的想法:
Private Sub GetConfigB()
Dim k As Boolean = True
While k
While True
If System.DateTime.Now.Minute = 41 Then
Dim s As String = Huitu.Config.logFilePath
k = False
Exit While
End If
End While
End While
End Sub
Private Sub GetConfigA()
Dim k As Boolean = True
While k
While True
If System.DateTime.Now.Minute = 41 Then
Dim s As String = Huitu.Config.logFilePath
k = False
Exit While
End If
End While
End While
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
'Huitu.Config.getConfig()
Dim thA As New System.Threading.Thread(AddressOf Me.GetConfigA)
Dim thB As New System.Threading.Thread(AddressOf Me.GetConfigB)
thA.Start()
thB.Start()
End Sub
等到10:41分,程序顺利出错了,呵呵
看来静态的咚咚在多用户环境下还是需要格外小心的