Sid*_*war 21 .net c# sql-server ado.net transactions
这篇MSDN文章指出:
隔离级别具有连接范围范围,并且一旦设置为与SET TRANSACTION ISOLATION LEVEL语句的连接,它将保持有效,直到连接关闭或设置了另一个隔离级别.关闭连接并返回到池时,将保留最后一个SET TRANSACTION ISOLATION LEVEL语句的隔离级别.重新使用池连接的后续连接使用在连接池时生效的隔离级别.
该SqlConnection的类有任何成员可能持有的隔离级别.那么连接如何知道在哪个隔离级别运行?
我问这个的原因是因为以下情况:
问题:
解决方案:
池化连接返回可序列化隔离级别的原因是由于以下原因:
- 你有一个连接池(让我们说CP1)
- CP1可能有50个连接.
- 从CP1中选择一个连接C1并使用Serializable执行它.此连接现在已设置其隔离级别.无论您做什么,都不会重置(除非此连接用于执行不同隔离级别的代码).
- 执行查询后,C1(Serializable)返回CP1.
- 如果再次执行步骤1-4,则使用的连接可能是除C1之外的其他连接,假设为C2或C3.因此,它的隔离级别也将设置为Serializable.
- 因此,慢慢地,Serialzable在CP1中设置为多个连接.
- 当您执行未进行显式隔离级别设置的查询时,从CP1中选择的连接将决定隔离级别.例如,如果此类查询请求连接并且CP1使用C1(Serializable)执行此查询,则此查询将在Serializable模式下执行,即使您未明确设置它.
希望能够澄清一些疑惑.:)
Ste*_*ger 10
隔离级别在底层DBMS中实现,比如SqlServer.设置隔离级别最有可能设置SQL命令,这些命令设置连接的隔离级别.
只要连接保持打开,DBMS就会保持隔离级别.因为连接被放入池中,所以它保持打开状态并保持之前的设置.
在搞乱隔离级别时,您应该在任何事务结束时重置隔离级别,或者更好的是,在请求新连接时设置隔离级别.
SqlConnection.BeginTransaction接受一个IsolationLevel参数,这就是控制SqlClient连接的隔离级别的方法.另一种选择是使用通用的System.Transactions并指定TransactionOptions.IsolationLevel传递给TransactionScope 构造函数的隔离级别.在SqlClient和System.Transactions编程模型中,必须为每个事务显式指定隔离级别.如果未指定,将使用默认值(SqlClient的Read Committed,System.Transactions的Serializable).
汇集的连接不是盲目重用的.他们有隐藏的内部成员来跟踪当前状态,如当前事务,挂起结果等,框架可以清理返回池的连接.仅仅因为状态未在编程模型中公开,它并不意味着不存在(这适用于任何库类,任何类设计者都可以隐藏internal伞下的成员).
最后,从它调用的池中重新使用任何连接,sp_reset_connection这是一个清理服务器端会话状态的服务器过程.
它不会将隔离级别返回到原始值。使用实体的示例需要一个空事务来重置级别(尽管它显然不需要提交(不需要 .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)
| 归档时间: |
|
| 查看次数: |
11825 次 |
| 最近记录: |