多线程环境中的PetaPoco事务

时间:2012-06-25 15:07:00

标签: petapoco

我只是以多线程的方式测试PetaPoco Transaction ...

我有一个简单的测试用例:

- 简单值对象称之为MediaDevice - 插入记录更新1000次

void TransactionThread(Object object)
{


    Database db = (Database) object;

    for(int i= 0; i < 1000;i++)
    {


        Transaction transaction = db.GetTransaction();

        MediaDevice device = new  MediaDevice();
        device.Name = "Name";
        device.Brand = "Brand";

        db.Insert(device);

        device.Name = "Name_Updated";
        device.Brand = "Brand_Updated";


        db.Update(device);

        transaction.Complete();

    }


    long count = db.ExecuteScalar<long>("SELECT Count(*) FROM MediaDevices");

    Console.WriteLine("Number of all records:" + count);

}

我在两个这样的线程中调用它:[两个线程的单个数据库对象]

void TransactionTest()
{

    Database db =  GetDatabase();

    Thread tThread1 = ... // thread for  TransactionTest()

    Thread tThread2 = ... // thread for  TransactionTest()

     tThread1.Start(db); // pass Database to TransactionTest()
     tThread2.Start(db); // pass same Database to TransactionTest()

}

我收到Null错误或有时数据库的对象处理错误..

但是当我提供两个数据库实例时,

void TransactionTest()
{

    Database db =  GetDatabase();
    Database db2 =  GetDatabase();

    Thread tThread1 = ... // thread for  TransactionTest()

    Thread tThread2 = ... // thread for  TransactionTest()


    tThread1.Start(db);  // pass Database instance db to TransactionTest()
    tThread2.Start(db2); // pass Database intance db2 to TransactionTest()

}

Everthing还可以......

那么当我在事务中检查PetaPoco源代码时,我会在transaction.Complete中看到它

 public virtual void Complete()
        {
            _db.CompleteTransaction();
            _db = null;
        }

我的问题是能够使用来自多个线程的事务我是否必须使用Database对象的新副本?或者我做错了什么?

为了使线程安全,我是否必须在每次数据更新查询时打开和关闭新数据库?

3 个答案:

答案 0 :(得分:4)

是的,每个线程需要一个单独的PetaPoco数据库实例。请参阅PetaPoco文档中的引用:

  

注意:要使事务起作用,所有操作都需要使用相同的操作   PetaPoco数据库对象的实例。所以你可能想要   使用每个http请求或每个线程的IOC容器来提供服务   该对象的共享实例。个人StructureMap是我的   最喜欢的。

我加粗了提供线索的短语。它说每个线程应该使用一个PetaPoco数据库对象的实例。

答案 1 :(得分:1)

您可以在select查询中使用nolock,因为该表可能已被锁定。 long count = db.ExecuteScalar(“SELECT Count(*)with nolock FROM MediaDevices”);

答案 2 :(得分:1)

抱歉,老兄..是的,你是对的。他们将对象更改为null。所以你不能使用相同的对象进行线程化。你必须使用他们描述的db = GetDataBase(); DB2 = GetDataBase();

否则您可以更改您的要求的源代码。我认为他们的许可证允许它。但我不确定。