我们遇到了一些显然以错误的隔离级别执行的数据库代码的问题。在代码的这个特定部分,它应该使用“READ UNCOMMITTED”执行以最小化锁。在这一点上,不一致的数据是可以的。
然而,代码实际上是用 READ COMMITTED 读取的,我们不知道为什么。
这是我们所做的:
- 打开连接
- 在此连接上执行“SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED”
- 打断点
- 执行 SQL
在断点上,我们向数据库发出以下命令:
select s.session_id, s.transaction_isolation_level, st.text from sys.dm_exec_sessions s
inner join sys.sysprocesses sp on (sp.spid = s.session_id)
CROSS APPLY sys.dm_exec_sql_text(sp.sql_handle) st
此 SQL 现在报告 4 个池连接,其中一个是我们的连接,我们可以超越断点来执行我们的 SQL,它具有以下状态:
53 2 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
IE。会话 53 具有隔离级别 2(已提交读),在此会话上执行的最后一个 SQL 是“SET TRANSACTION ...”命令。
怎么会这样?
我们用 SQL Profiler 验证了这个连接在我们的 .NET 代码打开它之前没有存在,所以它没有从连接池中重用。
然而,有了一个新的连接,并且在其上执行的唯一且第一个 SQL 明确告诉它使用 READ UNCOMMITTED,连接如何仍然是 READ COMMITTED?
我们应该在这里看什么?
连接字符串(已编辑位)如下所示:
SERVER=hostname;DATABASE=dbname;Integrated Security=false;USER ID=sa;PASSWORD=****;Application Name=appname;Type System Version=SQL Server 2000;Workstation ID=hostname;
连接是正常SqlConnection
连接,以正常方式打开。
不幸的是,如果我们编写打开 SqlConnection 的普通代码,我们将无法重现该问题,因此应用程序状态肯定有问题,但由于 SqlProfiler 和 Sql Server 都告诉我们是的,SQL 已执行,但没有,我不在乎。
什么会影响这一点?
完全相同的代码也会打开其他连接,也就是说,代码会执行多次并打开许多连接,因此池中会出现多个连接,但只有第一个连接会出现此问题。
这是 SQL Server 2008 R2,我们在 2012 年也重现了这个问题。
编辑
好的,还有更多信息。
首先,我们启用池化,或者更确切地说,我们没有明确禁用它,也没有调整连接字符串来创建“N”个池。
但是,此连接是使用此特定连接字符串打开的第一个连接,因此不会从池中检索它。另请参阅下面关于它永久“生病”的说明。
这个连接是这样建立的:
var conn = new SqlConnection(...);
conn.StateChance += connection_StateChange;
private void connection_StateChange(Object sender, StateChangeEventArgs e)
{
if (e.CurrentState == ConnectionState.Open)
{
using (IDbCommand cmd = ((SqlConnection)sender).CreateCommand())
{
cmd.CommandText = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED";
cmd.ExecuteNonQuery();
}
在此之前我们没有执行任何其他 SQL。
请注意,此代码在应用程序的生命周期中被多次使用,只有它打开的第一个连接最终会出错。
这种联系也变得永远病态。因为每次我们打开连接(即使我们可能把它从连接池中取出),上面的状态改变事件都会执行,试图再次设置隔离级别。这也失败了,但仅针对此单个连接。
此外,自从我发布此问题以来,我们发现了一件事会影响这一点。
通过更改我在上面发布的连接字符串:
...;Type System Version=SQL Server 2000;...
对此:
...;Type System Version=SQL Server 2008;MultipleActiveResultSets=true;...
然后这个问题就消失了,在前面列出的断点处,连接现在处于“READ UNCOMMITTED”状态。
这是一条红鲱鱼,在我们实际执行代码之前,我们的概述中不再报告连接。
我们正在继续调试。