【问题标题】:Using TransactionScope multiple times多次使用 TransactionScope
【发布时间】:2011-09-26 10:51:09
【问题描述】:

这是使用事务范围的正确方法吗:

我有一个代表事物一部分的对象:

public class ThingPart
{
    private DbProviderFactory connectionFactory;

    public void SavePart()
    {
        using (TransactionScope ts = new TransactionScope()
        {
            ///save the bits I want to be done in a single transaction
            SavePartA();
            SavePartB();
            ts.Complete(); 
        }
    }

    private void SavePartA()
    {
        using (Connection con = connectionFactory.CreateConnection()
        {
            con.Open();
            Command command = con.CreateCommand();
            ...
            command.ExecuteNonQuery();             
        }
    }

    private void SavePartB()
    {
        using (Connection con = connectionFactory.CreateConnection()
        {
            con.Open();
            Command command = con.CreateCommand();
            ...
            command.ExecuteNonQuery();             
        }
    }
}

还有代表事物的东西:

public class Thing
{
    private DbProviderFactory connectionFactory;

    public void SaveThing()
    {
        using (TransactionScope ts = new TransactionScope()
        {
            ///save the bits I want to be done in a single transaction
            SaveHeader();
            foreach (ThingPart part in parts)
            {
                part.SavePart();
            }  
            ts.Complete();    
        }
    }

    private void SaveHeader()
    {
        using (Connection con = connectionFactory.CreateConnection()
        {
            con.Open();
            Command command = con.CreateCommand();
            ...
            command.ExecuteNonQuery();             
        }
    }
}

我也有管理很多事情的东西

public class ThingManager
{    
    public void SaveThings
    {        
        using (TransactionScope ts = new TransactionScope)
        {            
            foreach (Thing thing in things)
            {
                thing.SaveThing();
            }            
        }        
    }    
}

我的理解是:

  • 连接不会是新的,每次都会从池中重复使用(假设 DbProvider 支持连接池并且已启用)
  • 事务将是这样的,如果我只是调用ThingPart.SavePart(从任何其他类的上下文之外),那么 A 部分和 B 部分要么都被保存,要么都不被保存。
  • 如果我调用Thing.Save(从任何其他类的上下文之外),那么标题和所有部分将全部保存或不保存,即所有事情都将发生在同一个事务中
  • 如果我打电话给ThingManager.SaveThings,那么我所有的东西都会被保存或者什么都不会保存,即所有事情都将发生在同一个事务中。
  • 如果我更改所使用的 DbProviderFactory 实现,它应该不会产生影响

我的假设正确吗?

忽略任何关于对象结构或持久性责任的内容,这是一个帮助我理解我应该如何做事的例子。部分原因是当我尝试将 oracle 替换为 SqlLite 作为数据库提供程序工厂时,它似乎不起作用,我想知道我应该在哪里花时间调查。

【问题讨论】:

    标签: transactions connection connection-pooling transactionscope


    【解决方案1】:

    回答你的问题(我假设 Microsoft SQL Server 2005 或更高版本):

    1. 连接不会是新的并从池中重复使用

      • 这取决于 - 例如如果所有连接都到同一个数据库,具有相同的凭据,并且 SQL 能够使用轻量级事务管理器(SQL 2005 及更高版本),则 SAME 连接将被重用于聚合事务中的后续步骤。 (但如果您要求的是 SQL 连接池仍然有效?)
    2. Atomic SavePart - 是的,这将按预期工作 ACID。
    3. 是的,具有相同范围的嵌套 TransactionScopes 也将是原子的。只有在最外层的 TS 完成后才会提交事务。
    4. 是的,也是原子的,但请注意,您将升级 SQL 锁。如果单独提交每个事物(及其 ThingParts)是有意义的,那么从 SQL 并发的角度来看,这将是更可取的。
    5. Provider 需要与 TransactionScope 资源管理器兼容(并且可能也符合 DTC)。例如不要将您的数据库移动到 Rocket U2 并期望 TransactionScopes 能够正常工作。

    只有一个问题 - new TransactionScope() defaults to isolation level READ_SERIALIZABLE - 这对于大多数情况来说通常过于悲观 - READ COMMITTED 通常更适用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多