SqlConnection如何管理IsolationLevel?

Sid*_*war 21 .net c# sql-server ado.net transactions

这篇MSDN文章指出:

隔离级别具有连接范围范围,并且一旦设置为与SET TRANSACTION ISOLATION LEVEL语句的连接,它将保持有效,直到连接关闭或设置了另一个隔离级别.关闭连接并返回到池时,将保留最后一个SET TRANSACTION ISOLATION LEVEL语句的隔离级别.重新使用池连接的后续连接使用在连接池时生效的隔离级别.

SqlConnection的类有任何成员可能持有的隔离级别.那么连接如何知道在哪个隔离级别运行?

我问这个的原因是因为以下情况:

  1. 我在Serializable模式下使用TransactionScope打开了一个事务,比如"T1".
  2. 打开T1的连接.
  3. T1完成/处理,连接返回连接池.
  4. 在同一连接上调用另一个查询(从连接池获取后),此查询以可序列化模式运行!

问题:

  1. 汇集连接如何知道与之相关的隔离级别?
  2. 如何将其还原回其他一些事务级别???

解决方案:
池化连接返回可序列化隔离级别的原因是由于以下原因:

  1. 你有一个连接池(让我们说CP1)
  2. CP1可能有50个连接.
  3. 从CP1中选择一个连接C1并使用Serializable执行它.此连接现在已设置其隔离级别.无论您做什么,都不会重置(除非此连接用于执行不同隔离级别的代码).
  4. 执行查询后,C1(Serializable)返回CP1.
  5. 如果再次执行步骤1-4,则使用的连接可能是除C1之外的其他连接,假设为C2或C3.因此,它的隔离级别也将设置为Serializable.
  6. 因此,慢慢地,Serialzable在CP1中设置为多个连接.
  7. 当您执行未进行显式隔离级别设置的查询时,从CP1中选择的连接将决定隔离级别.例如,如果此类查询请求连接并且CP1使用C1(Serializable)执行此查询,则此查询将在Serializable模式下执行,即使您未明确设置它.

希望能够澄清一些疑惑.:)

Ste*_*ger 10

隔离级别在底层DBMS中实现,比如SqlServer.设置隔离级别最有可能设置SQL命令,这些命令设置连接的隔离级别.

只要连接保持打开,DBMS就会保持隔离级别.因为连接被放入池中,所以它保持打开状态并保持之前的设置.

在搞乱隔离级别时,您应该在任何事务结束时重置隔离级别,或者更好的是,在请求新连接时设置隔离级别.


Rem*_*anu 6

SqlConnection.BeginTransaction接受一个IsolationLevel参数,这就是控制SqlClient连接的隔离级别的方法.另一种选择是使用通用的System.Transactions并指定TransactionOptions.IsolationLevel传递给TransactionScope 构造函数的隔离级别.在SqlClient和System.Transactions编程模型中,必须为每个事务显式指定隔离级别.如果未指定,将使用默认值(SqlClient的Read Committed,System.Transactions的Serializable).

汇集的连接不是盲目重用的.他们有隐藏的内部成员来跟踪当前状态,如当前事务,挂起结果等,框架可以清理返回池的连接.仅仅因为状态未在编程模型中公开,它并不意味着不存在(这适用于任何库类,任何类设计者都可以隐藏internal伞下的成员).

最后,从它调用的池中重新使用任何连接,sp_reset_connection这是一个清理服务器端会话状态的服务器过程.

  • 惊喜!https://connect.microsoft.com/SQLServer/feedback/details/243527/sp-reset-connection-doesnt-reset-isolation-level (6认同)

cro*_*sek 6

它不会将隔离级别返回到原始值。使用实体的示例需要一个空事务来重置级别(尽管它显然不需要提交(不需要 .Complete())。

尝试使用 DB 服务器上的 SP 更改 iso 级别不起作用。输出:

之前:ReadCommitted
期间:可序列化
之后:
SP 复位后可序列化尝试:
XACT复位期间可序列化:XACT 复位
后读取提交:ReadCommitted

// using Dbg = System.Diagnostics.Debug;
XactIso.iso isoEntity = new XactIso.iso();
using (isoEntity)
{
    Dbg.WriteLine("Before: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());

    var xactOpts = new TransactionOptions();
    xactOpts.IsolationLevel = System.Transactions.IsolationLevel.Serializable;

    using (TransactionScope xact = new TransactionScope(TransactionScopeOption.Required, xactOpts))
    {
        Dbg.WriteLine("During: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());
        xact.Complete();
    }

    Dbg.WriteLine("After: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());

    isoEntity.usp_SetXactIsoLevel("ReadCommitted");

    Dbg.WriteLine("After Reset by SP Attempt: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());
    // failed

    var xactOpts2 = new TransactionOptions();
    xactOpts2.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
    using (TransactionScope xact2 = new TransactionScope(TransactionScopeOption.Required, xactOpts2))
        Dbg.WriteLine("During Reset by XACT: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());
    // works w/o commit

    Dbg.WriteLine("After Reset by XACT: " + isoEntity.usp_GetXactIsoLevel().SingleOrDefault());
}
Run Code Online (Sandbox Code Playgroud)

从哪里来的链接

proc [Common].[usp_GetXactIsoLevel]
as
begin          
    select         
        case transaction_isolation_level 
            WHEN 0 THEN 'Unspecified' 
            WHEN 1 THEN 'ReadUncommitted' 
            WHEN 2 THEN 'ReadCommitted' 
            WHEN 3 THEN 'RepeatableRead' 
            WHEN 4 THEN 'Serializable' 
            WHEN 5 THEN 'Snapshot' 
        end as lvl
     from sys.dm_exec_sessions 
    where session_id = @@SPID;
end
Run Code Online (Sandbox Code Playgroud)

和(不起作用):

proc [Common].[usp_SetXactIsoLevel]
    @pNewLevel    varchar(30)
as
begin

    if @pNewLevel = 'ReadUncommitted'
        SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    else if @pNewLevel = 'ReadCommitted'
        SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    else if @pNewLevel = 'RepeatableRead'
        SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    else if @pNewLevel = 'Serializable'
        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    else if @pNewLevel = 'Snapshot'
        SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
    else
        raiserror('Unrecognized Transaction Isolation Level', 16, 1);         
end        
Run Code Online (Sandbox Code Playgroud)