.net 在单个线程上使用事务时sqlite和SubSonic的锁定问题

.net 在单个线程上使用事务时sqlite和SubSonic的锁定问题,.net,sqlite,subsonic,transactions,subsonic2.2,.net,Sqlite,Subsonic,Transactions,Subsonic2.2,我在尝试使用亚音速和SQLite事务时遇到锁定异常。我从一个线程使用它,并且没有其他进程访问我的数据库,所以我真的没想到会有这样的问题 如果我像下面这样编写代码,那么在循环中对Save()的第二次调用会出现异常,所以对Save()的第三次调用会出现异常 using (TransactionScope ts = new TransactionScope()) { using (SharedDbConnectionScope sharedConne

我在尝试使用亚音速和SQLite事务时遇到锁定异常。我从一个线程使用它,并且没有其他进程访问我的数据库,所以我真的没想到会有这样的问题

如果我像下面这样编写代码,那么在循环中对Save()的第二次调用会出现异常,所以对Save()的第三次调用会出现异常

       using (TransactionScope ts = new TransactionScope())
       {
            using (SharedDbConnectionScope sharedConnectinScope = new SharedDbConnectionScope())
            { 
                SomeDALObject x = new SomeDALObject()
                x.Property1 = "blah";
                x.Property2 = "blah blah";
                x.Save();

                foreach (KeyValuePair<string, string> attribute in attributes)
                { 
                    AnotherDALObject y = new AnotherDALObject()
                    y.Property1 = attribute.Key
                    y.Property2 = attribute.Value
               
                    y.Save();  // this is where the exception is raised, on the 2nd time through this loop
                }
            }
       }
如果我用另一种方式嵌套using语句,外部是SharedDbConnectionScope,那么我会得到一个
TransactionException
,消息是“操作对事务状态无效”。堆栈跟踪是:

   at System.Data.SQLite.SQLite3.Step(SQLiteStatement stmt)
   at System.Data.SQLite.SQLiteDataReader.NextResult()
   at System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
   at System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
   at System.Data.SQLite.SQLiteCommand.ExecuteNonQuery()
   at System.Data.SQLite.SQLiteTransaction..ctor(SQLiteConnection connection, Boolean deferredLock)
   at System.Data.SQLite.SQLiteConnection.BeginDbTransaction(IsolationLevel isolationLevel)
   at System.Data.SQLite.SQLiteConnection.BeginTransaction()
   at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope)
   at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction)
   at System.Data.SQLite.SQLiteConnection.Open()
   at SubSonic.SQLiteDataProvider.CreateConnection(String newConnectionString)
   at SubSonic.SQLiteDataProvider.CreateConnection()
   at SubSonic.SQLiteDataProvider.ExecuteScalar(QueryCommand qry)
   at SubSonic.DataService.ExecuteScalar(QueryCommand cmd)
   at SubSonic.ActiveRecord`1.Save(String userName)
   at SubSonic.ActiveRecord`1.Save()
   at (my line of code above).
at System.Transactions.TransactionState.EnlistVolatile(InternalTransaction tx, IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions, Transaction atomicTransaction)
   at System.Transactions.Transaction.EnlistVolatile(IEnlistmentNotification enlistmentNotification, EnlistmentOptions enlistmentOptions)
   at System.Data.SQLite.SQLiteEnlistment..ctor(SQLiteConnection cnn, Transaction scope)
   at System.Data.SQLite.SQLiteConnection.EnlistTransaction(Transaction transaction)
   at System.Data.SQLite.SQLiteConnection.Open()
   at SubSonic.SQLiteDataProvider.CreateConnection(String newConnectionString)
   at SubSonic.SQLiteDataProvider.CreateConnection()
   at SubSonic.SQLiteDataProvider.ExecuteScalar(QueryCommand qry)
   at SubSonic.DataService.ExecuteScalar(QueryCommand cmd)
   at SubSonic.ActiveRecord`1.Save(String userName)
   at SubSonic.ActiveRecord`1.Save()
   at (my line of code above)
内部异常为“事务超时”

我在生成的DAL类中没有任何自定义代码,或者任何我能想到的导致这种情况的聪明的东西

还有谁遇到过这样的事务问题,或者有人能建议我从哪里开始寻找问题吗

谢谢


更新:我注意到在版本1.0.61-65(例如)的发行说明中提到了与事务相关的内容,因此更新SubSonic以使用最新版本的.Net数据提供程序可能会解决其中一些问题…

我们使用SQL lite来测试与数据库操作相关的代码。 SQL lite不支持嵌套事务。 我们有类似的问题,我们有NHibernate和.Net交易。
最终,我们不得不使用SQL Express测试与数据库相关的代码。

我们使用SQL lite测试与数据库操作相关的代码。 SQL lite不支持嵌套事务。 我们有类似的问题,我们有NHibernate和.Net交易。
最终,我们不得不使用SQL Express来测试与数据库相关的代码。

在为亚音速2.x修改sqlite提供程序时,我在现有亚音速sqlserver测试的基础上创建了一整套单元测试。(这些测试也与修订后的代码一起签入。)唯一失败的测试是与事务相关的测试(也可能是迁移测试)。如您所见,“数据库文件已锁定”错误消息。Subsonic主要是为sql server编写的,它不像SQLIte那样进行文件级锁定,所以有些东西不起作用;它需要重写才能更好地处理这个问题

我从来没有像你那样使用过TransactionScope。我这样做我的亚音速2.2事务,到目前为止与SQLite提供程序没有问题。我可以确认,如果处理多行,或者处理速度非常慢,则需要使用SQLite事务

public void DeleteStuff(List<Stuff> piaRemoves)
{
    QueryCommandCollection qcc = new QueryCommandCollection();

    foreach(Stuff item in piaRemoves)
    {
        Query qry1 = new Query(Stuff.Schema);
        qry1.QueryType = QueryType.Delete;
        qry1.AddWhere(Stuff.Columns.ItemID, item.ItemID);
        qry1.AddWhere(Stuff.Columns.ColumnID, item.ColumnID);
        qry1.AddWhere(Stuff.Columns.ParentID, item.ParentID);
        QueryCommand cmd = qry1.BuildDeleteCommand();
        qcc.Add(cmd);
    }
    DataService.ExecuteTransaction(qcc);
}
public void deleteTuff(列表)
{
QueryCommandCollection qcc=新的QueryCommandCollection();
foreach(文件中的填充项)
{
Query qry1=新查询(Stuff.Schema);
qry1.QueryType=QueryType.Delete;
qry1.AddWhere(Stuff.Columns.ItemID,item.ItemID);
qry1.AddWhere(Stuff.Columns.ColumnID,item.ColumnID);
qry1.AddWhere(Stuff.Columns.ParentID,item.ParentID);
QueryCommand cmd=qry1.BuildDeleteCommand();
qcc.Add(cmd);
}
DataService.ExecuteTransaction(qcc);
}

在为亚音速2.x修改sqlite提供程序时,我基于现有亚音速sqlserver测试创建了一整套单元测试。(这些测试也与修订后的代码一起签入。)唯一失败的测试是与事务相关的测试(也可能是迁移测试)。如您所见,“数据库文件已锁定”错误消息。Subsonic主要是为sql server编写的,它不像SQLIte那样进行文件级锁定,所以有些东西不起作用;它需要重写才能更好地处理这个问题

我从来没有像你那样使用过TransactionScope。我这样做我的亚音速2.2事务,到目前为止与SQLite提供程序没有问题。我可以确认,如果处理多行,或者处理速度非常慢,则需要使用SQLite事务

public void DeleteStuff(List<Stuff> piaRemoves)
{
    QueryCommandCollection qcc = new QueryCommandCollection();

    foreach(Stuff item in piaRemoves)
    {
        Query qry1 = new Query(Stuff.Schema);
        qry1.QueryType = QueryType.Delete;
        qry1.AddWhere(Stuff.Columns.ItemID, item.ItemID);
        qry1.AddWhere(Stuff.Columns.ColumnID, item.ColumnID);
        qry1.AddWhere(Stuff.Columns.ParentID, item.ParentID);
        QueryCommand cmd = qry1.BuildDeleteCommand();
        qcc.Add(cmd);
    }
    DataService.ExecuteTransaction(qcc);
}
public void deleteTuff(列表)
{
QueryCommandCollection qcc=新的QueryCommandCollection();
foreach(文件中的填充项)
{
Query qry1=新查询(Stuff.Schema);
qry1.QueryType=QueryType.Delete;
qry1.AddWhere(Stuff.Columns.ItemID,item.ItemID);
qry1.AddWhere(Stuff.Columns.ColumnID,item.ColumnID);
qry1.AddWhere(Stuff.Columns.ParentID,item.ParentID);
QueryCommand cmd=qry1.BuildDeleteCommand();
qcc.Add(cmd);
}
DataService.ExecuteTransaction(qcc);
}

我最终使用了Paul的建议,并将我的代码改写为如下内容:

    QueryCommandCollection qcc = new QueryCommandCollection();

    SomeDALObject x = new SomeDALObject()
    x.Property1 = "blah";
    x.Property2 = "blah blah";
    qcc.Add(x.GetSaveCommand());

    foreach (KeyValuePair<string, string> attribute in attributes)
    { 
        AnotherDALObject y = new AnotherDALObject()
        y.Property1 = attribute.Key
        y.Property2 = attribute.Value

        qcc.Add(y.GetSaveCommand());
    }

    DataService.ExecuteTransaction(qcc);
QueryCommandCollection qcc=newquerycommandcollection();
SomeDALObject x=新的SomeDALObject()
x、 属性1=“诸如此类”;
x、 Property2=“诸如此类”;
qcc.Add(x.GetSaveCommand());
foreach(属性中的KeyValuePair属性)
{ 
AnotherDALObject y=新的AnotherDALObject()
y、 Property1=属性.Key
y、 Property2=属性值
qcc.Add(y.GetSaveCommand());
}
DataService.ExecuteTransaction(qcc);
这实际上要好得多,因为数据库命中的所有准备工作都是在打开事务之前完成的,因此打开事务的时间要少得多

如果您需要返回自动生成的ID以便为子记录运行插入,那么这将无法很好地工作;为此,您需要使用不同的方法

然后我遇到了一些其他线程/事务问题:当多个线程同时执行DataService.ExecuteTransaction()时,我会得到AccessViolationExceptions和NullReferenceExceptions,基本上有点混乱。但随着SQLDataProvider的更新,改为使用亚音速并同时改为使用亚音速似乎立即解决了这个问题。万岁

更新:事实上,我在使用亚音速sqlite时仍然遇到线程问题。基本上,亚音速中的SQLiteDataProvider不是为处理multit而编写的