我有以下代码(简化)来访问我的数据库.我知道使用语句和参数但我缩短了这一点以集中我的问题.
string ConnectionString = "ConnectionStringHere"; //1. insert Transaction SqlConnection myConnection = new SqlConnection(ConnectionString); SqlTransaction myTrans = myConnection.BeginTransaction(); string sUpdate = "INSERT INTO User (FirstName, LastName) VALUES ('jon','doe')"; SqlCommand myCommand = new SqlCommand(sUpdate, myConnection, myTrans); myCommand.ExecuteNonQuery(); //2. select from the same table SqlConnection myConnection2 = new SqlConnection(ConnectionString); string sSelect = "SELECT FirstName, LastName FROM User WHERE ID = 123"; DataTable dtResult = new DataTable(); SqlDataAdapter myDataAdapter2 = new SqlDataAdapter(sSelect, myConnection2); myDataAdapter2.Fill(dtResult); //TimeOut Exception here //submit changes from my transaction here myTrans.Commit();
在第二部分中,我得到一个TimeOutExcetion,因为在我提交我的事务myTrans.Commit()之前我无法访问我的User表.在那之后 – 僵局.
我的问题是 – 在这里避免死锁的最佳做法是什么?我可以通过制作事务的SELECT部分或设置IsolationLevel来避免异常
SqlTransaction myTrans = myConnection.BeginTransaction(IsolationLevel.ReadUncommitted);
但我不确定那些用法.我不必担心无效数据,因为我总是按ID选择.
我没有看到任何理由将SELECT查询作为事务的一部分来解决死锁或超时问题.在您认为的第一个sql连接myConnection上设置ReadUncommitted隔离级别也不是正确的方法.我看到有两种可能的解决方案:>第一个解决方案:在已启动的事务myTrans上设置隔离级别IsolationLevel.ReadUncommitted将无济于事.如果您对脏读取感到满意,那么您实际上应该在要为User表触发select查询而建立的第二个SQL连接myConnection2上设置此隔离级别.要通过myConnection2为select查询设置隔离级别,您需要使用(nolock)表级提示.所以你的查询将开始如下:
string sSelect = "SELECT FirstName, LastName FROM User WITH (NOLOCK) WHERE ID = 123";
您可以获得更多细节here.
另外,请阅读脏读here的后果,这是使用此特定隔离级别的副作用.>第二种解决方案:SQL Server的默认隔离级别为Read Committed.因此,当您使用名为myConnection2的变量开始通过新的SQL连接触发查询时,它正在处理ReadCommitted隔离级别. ReadCommitted隔离级别显示的默认行为是阻塞读取,即如果表上存在未提交的更改(由于活动事务可以提交或回滚),则用户表上的select语句将被阻止.它将等待事务完成,以便在回滚时可以读取新更新的数据或原始数据.如果它不执行这样的阻塞读取,那么它将最终执行脏读,这是一个众所周知的数据库并发问题.如果您不希望SELECT语句被阻止并希望继续使用行的最后一个提交值,则SQL Server中有一个名为READ_COMMITTED_SNAPSHOT的新数据库级别设置.以下是使用SQL脚本更改它的方法:ALTER DATABASE MyDatabase SET READ_COMMITTED_SNAPSHOT ON
引用Pinal Dave的文章here:
If you are having problem with blocking between readers (SELECT) and
writers (INSERT/UPDATE/DELETE), then you can enable this property without changing anything from the application. Which means application would still run under read committed isolation and will still read only committed data.注意:这是数据库级别设置,将使用READCOMMITTED隔离级别影响数据库上的所有事务.
在我看来,你应该采取第一个解决方案.此外,您应该记住几个关键点,以避免SQL Server查询中的死锁.从here引用Pinal Dave:
>最小化事务和事务时间的大小.>每次在应用程序中始终以相同的顺序访问服务器对象.>避免使用游标,循环或在运行时需要用户输入的进程.>减少应用程序中的锁定时间.>如果可能,使用查询提示来防止锁定(NoLock,RowLock)>使用SET DEADLOCK_PRIORITY选择死锁牺牲品.
查看更多关于c# – 避免SQL事务中的死锁的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did69309