C# 数据库保存功能出现故障的可能原因
我有一个类似于以下代码的类,它需要是线程安全的。它只是一个将类实例保存/映射到数据库行的函数 如果类实例的ID属性为0,则认为它是一个新项-在这种情况下,将插入一个空行,并返回其自动增量值/行ID。接下来,使用WHERE子句中返回的自动增量值更新行 如果ID属性大于0,则该方法仅使用更新查询 我遇到的问题是偶尔/随机的,会创建空行或重复行。我正在努力确定原因,无法以一种我可以轻松诊断的方式可靠地重现它 对我来说,它有各种比赛条件的迹象,但我不明白为什么会发生这种情况——特别是考虑到围绕着方法的核心的锁: 有人能发现这个类/方法中的问题吗,或者我的问题在其他地方吗C# 数据库保存功能出现故障的可能原因,c#,mysql,thread-safety,C#,Mysql,Thread Safety,我有一个类似于以下代码的类,它需要是线程安全的。它只是一个将类实例保存/映射到数据库行的函数 如果类实例的ID属性为0,则认为它是一个新项-在这种情况下,将插入一个空行,并返回其自动增量值/行ID。接下来,使用WHERE子句中返回的自动增量值更新行 如果ID属性大于0,则该方法仅使用更新查询 我遇到的问题是偶尔/随机的,会创建空行或重复行。我正在努力确定原因,无法以一种我可以轻松诊断的方式可靠地重现它 对我来说,它有各种比赛条件的迹象,但我不明白为什么会发生这种情况——特别是考虑到围绕着方法的核
public class clsItem
{
static clsDatabase DB;
static string TableName = "myTable";
static readonly object syncLock = new Object();
public int ID;
public string Name;
public string Description;
public bool Save()
{
lock(syncLock) {
if (ID < 0 || !(DB.ServerAvailable && DB.CredentialsAuthenticated)) return false;
bool newItem = (ID == 0) ? true : false;
long InsertID = 0;
if (newItem) // make blank row and return ID
{
if (DB.Query("INSERT INTO " + TableName + " values()", ref InsertID) == null || InsertID == 0) return false;
ID = (int)InsertID;
}
List<MySqlParameter> parameters = new List<MySqlParameter>();
FieldInfo[] props = this.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo pi in props)
{
if (newItem && pi.Name == "ID")
parameters.Add(new MySqlParameter(pi.Name, InsertID));
else
parameters.Add(new MySqlParameter(pi.Name, pi.GetValue(this)));
}
string query = "UPDATE " + TableName + " SET name = @Name, desc = @Description WHERE id = @ID";
return (DB.Query(query, parameters) == null) ? false : true;
}
}
}
在受锁保护的块内,可以多次访问ID。设置其值的所有其他位置是否也受同步锁定的保护?使用块访问的其他字段也可能存在同样的问题。请记住,锁定的目的是控制对共享资源的访问,而不仅仅是将条目序列化到特定的代码块中。@hatchet只有当它是新行/项时,此保存函数才会更改ID,或者在类的Load方法中,我应该使用相同的同步锁来保护它吗?。由于这不是一个静态类,我看不出这将如何导致冲突的情况,因为当我看到该实例的ID是公共字段时,该实例的ID仅设置为once,这就增加了它可以在任何地方、任何时间更改的可能性,如果在执行Save时发生这种情况,那将是一个问题。但是没有看到这个类如何被使用的更大背景,我只能指出它是一个潜在的问题。如果您描述一下为什么您认为首先需要锁,也就是说,多个线程正在访问这个类的特定实例,这可能会有所帮助。我明白您的意思,我可能应该使用私有setter而不是字段将其设置为公共属性,但无论如何都不会在其他地方设置它。锁定的原因主要是一个有希望的测试,看看同一个实例被不同的线程保存是否有问题。虽然实际上,该实例可能会被其他线程读取,但对于这个特定的类,每个项在新行中只保存一次。不过,我还有其他课程遵循这种模式。