简体   繁体   English

提交/回滚后,SQL Server 2008 R2中快照隔离级别中来自ADO.Net的事务未更改为默认隔离级别

[英]Transaction from ADO.Net in Snapshot Isolation Level in SQL Server 2008 R2 not changing to default isolation level after commit/rollback

I have the following code in C# using ADO.NET for updating data in a SQL Server 2008 R2 database using the SNAPSHOT isolation level. 我在C#中使用ADO.NET编写以下代码,以使用SNAPSHOT隔离级别更新SQL Server 2008 R2数据库中的数据。 This code is working perfectly. 该代码运行良好。 However, if I go to another page in my ASP.Net app after this, where a query runs between this database table joined with another database table on same server, then I get an error that says: 但是,如果此后我转到ASP.Net应用程序中的另一个页面,在此数据库表与同一服务器上的另一个数据库表连接的查询之间运行查询,则会收到一条错误消息:

System.Data.SqlClient.SqlException: Snapshot isolation transaction failed accessing database 'Member_Security' because snapshot isolation is not allowed in this database. System.Data.SqlClient.SqlException:快照隔离事务无法访问数据库'Member_Security',因为此数据库中不允许快照隔离。 Use ALTER DATABASE to allow snapshot isolation. 使用ALTER DATABASE允许快照隔离。

Query that throws an error as pasted above, if it runs after the SNAPSHOT transaction code: 如果查询在SNAPSHOT事务代码之后运行,则会引发如上所述的错误:

select 
   e.EmpId, e.EmpHours, m.SecurityLevel, m.IsPriveleged 
from 
   Emp e 
inner join 
   Member_Security.dbo.Members m

If I do not run the transaction in code below in SNAPSHOT level, then there is no problem. 如果我未在SNAPSHOT级别的以下代码中运行事务,则没有问题。

Why is this happening and how can I correct it? 为什么会发生这种情况,我该如何纠正?

I think in this case SNAPSHOT isolation level is not getting reset to what was before this code ran. 我认为在这种情况下,SNAPSHOT隔离级别没有重置为运行此代码之前的水平。

Code that runs perfectly: 完美运行的代码:

con = new SqlConnection();
con.ConnectionString = ConfigurationManager.ConnectionStrings["EMP"].ConnectionString;
con.Open();
tran = con.BeginTransaction(IsolationLevel.Snapshot);  
cmd = new SqlCommand();
cmd.CommandTimeout = 0; 
cmd.Connection = con;
cmd.Text = "Update emp set empcomm = 200 where empage > 40;"
cmd.Transaction = tran;

try {
    cmd.ExecuteNonQuery();
    tran.Commit();
}
catch(Exception ex)
{
    try 
    { 
        if(tran != null) 
           tran.rollback();
    } 
    catch{}
}
finally 
{ 
     DAL.ResetTransactionIsolationLevel(); 
} //NEED THIS TO SOLVE THIS PROBLEM

UPDATE 1: 更新1:

It seems there is a problem when using an isolation level other than the default one from ADO.Net code according to this paragraph taken from following url: Need to explicitly set Isolation Level when using non-default isolation level in ADO.Net code 似乎使用隔离级别而不是根据来自以下URL的本段规定的ADO.Net代码中的默认隔离级别时存在问题:在ADO.Net代码中使用非默认隔离级别时,需要显式设置隔离级别

After a transaction is committed or rolled back, the isolation level of the transaction persists for all subsequent commands that are in autocommit mode (the SQL Server default). 提交或回滚事务后,该事务的隔离级别对于处于自动提交模式(SQL Server默认设置)的所有后续命令保持不变。 This can produce unexpected results, such as an isolation level of REPEATABLE READ persisting and locking other users out of a row. 这可能会产生意外的结果,例如REPEATABLE READ的隔离级别持续存在,并将其他用户锁定在一行之外。 To reset the isolation level to the default (READ COMMITTED), execute the Transact-SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED statement, or call SqlConnection.BeginTransaction followed immediately by SqlTransaction.Commit. 要将隔离级别重置为默认值(READ COMMITTED),请执行Transact-SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED语句,或调用SqlConnection.BeginTransaction,然后立即调用SqlTransaction.Commit。 For more information on SQL Server isolation levels, see "Isolation Levels in the Database Engine" in SQL Server Books Online. 有关SQL Server隔离级别的更多信息,请参见SQL Server联机丛书中的“数据库引擎中的隔离级别”。

UPDATE 2: 更新2:

The only way I avoided this was to set isolation level to Read Committed after the above transaction was done ie call the method 'ResetTransactionIsolationLevel' in the finally block of above transaction. 我避免这种情况的唯一方法是在完成上述事务后将隔离级别设置为Read Committed,即在上述事务的finally块中调用方法'ResetTransactionIsolationLevel'。 If I did this then I did not see any problems when executing cross-database queries after the SNAPSHOT isolation level. 如果这样做,那么在SNAPSHOT隔离级别之后执行跨数据库查询时,我看不到任何问题。 I added the finally block to show this solution in above code snippet. 我添加了finally块以在上面的代码片段中显示此解决方案。

 public static void ResetTransactionIsolationLevel()
    {
        SqlCommand cmd = new SqlCommand();
        SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["EMP"].ConnectionString);


        try
        {
            cmd.CommandText = "set transaction isolation level read committed";
            cmd.CommandType = CommandType.Text;
            cmd.Connection = conn;
            conn.Open();
            cmd.ExecuteNonQuery();
            conn.Close();
        }
        finally
        {
            cmd.Dispose();
            conn.Close();
            conn.Dispose();
        }
    }

From here: http://msdn.microsoft.com/en-us/library/tcbchxcb(v=vs.110).aspx Snapshot isolation must be enabled by setting the ALLOW_SNAPSHOT_ISOLATION ON database option before it is used in transactions. 从此处: http : //msdn.microsoft.com/zh-cn/library/tcbchxcb( v=vs.110) .aspx在事务中使用快照隔离之前,必须通过在数据库上设置ALLOW_SNAPSHOT_ISOLATION ON来启用快照隔离。

Run this on your database: 在您的数据库上运行此命令:

ALTER DATABASE MyDatabase
SET ALLOW_SNAPSHOT_ISOLATION ON

UPDATE If you want to Read Committed SNAPSHOT in subsequent transactions without specifying it implicitly, also run: UPDATE如果您想在后续事务中读取Committed SNAPSHOT而不隐式指定,请运行:

ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON

Note that this is NOT read committed, and all data is still going through tempdb, so you really need to consider the capacity for your db and application. 请注意,这不是读提交的,并且所有数据仍在通过tempdb,因此您确实需要考虑数据库和应用程序的容量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM