gpt4 book ai didi

c# - 在(不相关的?)事务中使用 IsolationLevel.ReadUncommitted 时,SqlDependency 订阅不起作用

转载 作者:行者123 更新时间:2023-11-30 13:57:44 24 4
gpt4 key购买 nike

我已经设法使 SqlDependency 正常工作,但前提是我不在我认为与 SqlDependency 无关的 SQL 事务中使用 IsolationLevel.ReadUncommited

当我在事务中使用 IsolationLevel.ReadUncommitted(下面有大量评论)时,SqlDependency 订阅失败并立即发出 OnChange 通知:

sqlNotificationEventArgs.Info = "Isolation";
sqlNotificationEventArgs.Source = "Statement";
sqlNotificationEventArgs.Type = "Subscribe";

当我删除 IsolationLevel 时,一切都按预期工作(当然,隔离不正确)。

这是我的相关代码:

private static string connString = "the connection string";
[MTAThread]
private static void Main(string[] args)
while(true)
{
using (var context = new LinqDataContext(connString))
{
var conn = context.Connection;
conn.Open();
/***********************************************************************/
/* Remove `IsolationLevel.ReadUncommitted` and the SqlDependency works */
/***********************************************************************/
using (var trans = conn.BeginTransaction(IsolationLevel.ReadUncommitted))
{
// simplified query, the real query uses UPDATE OUTPUT INSERTED
const string sqlCommand = "SELECT [Columns] FROM dbo.[TABLE] WHERE [Status] = 'ready'";
results = conn.Query({transaction: trans, sql: sqlCommand});
trans.Commit();
}
DoAwesomeStuffWithTheResults(results, context);
}
WaitForWork();
}
}

SqlDependency相关代码:

private static ManualResetEvent _quitEvent = new ManualResetEvent(false);

/// <summary>
/// Sets up a SqlDependency a doesn't return until it receives a Change notification
/// </summary>
private static void WaitForWork(){
// in case we have dependency running we need to go a head and stop it first.
SqlDependency.Stop(connString);
SqlDependency.Start(connString);

using (var conn = new SqlConnection(connString))
{
using (var cmd = new SqlCommand("SELECT [Status] From dbo.[TABLE]", conn))
{
cmd.Notification = null;

var dependency = new SqlDependency(cmd);
dependency.OnChange += dependency_OnDataChangedDelegate;

conn.Open();

cmd.ExecuteReader();
}
}
_quitEvent.WaitOne();
SqlDependency.Stop(connString);
}
private static void dependency_OnDataChangedDelegate(object sender, SqlNotificationEventArgs e)
{
((SqlDependency)sender).OnChange -= dependency_OnDataChangedDelegate;
_quitEvent.Set();
}

在设置 SqlDependency 之前,我觉得我已经正确地处理了上下文、它的连接和事务,但事实似乎并非如此。

我在这里做错了什么?

最佳答案

恭喜 SqlDependency 开始工作(我不是在讽刺,很多人都失败了)。

现在是时候阅读 Creating a Query for Notification MSDN 上的主题。您将看到查询对通知有效的条件,包括此要求:

The statement must not run under READ_UNCOMMITTED or SNAPSHOT isolation levels.

我写了关于 the basics of how SqlDependency works ,也许会澄清一些误会。而且,作为辅助节点,由于您使用的是 Linq,您可能会对 LinqToCache 感兴趣,它提供了 Linq 查询和 SqlDependency 之间的桥梁。

另一条评论:不要随意使用 Start()Stop() 您的 SqlDependency。你很快就会后悔的。 Start() 应该在应用程序启动期间被调用一次,而 Stop() 应该在应用程序关闭期间被调用一次(严格来说,是在应用程序域加载和卸载期间)。

现在,关于您的问题:重要的隔离级别是通知查询 之一。这意味着,您附加订阅的查询,不是您执行 UPDATE 的查询(我不会评论在脏读下执行 UPDATE 的智慧... 或 the wisdom of using dirty reads for anything )。据我所知,您显示的代码不应在 read_uncommitted 下发布查询。在您发出 SET TRANSACTION ISOLATION ... 之后,该 session 中的所有后续事务(因此所有语句)都将处于该隔离级别下。您关闭连接(通过处理 DataContext),然后使用不同的连接。除非……你使用连接池。欢迎来到无辜受害者俱乐部:)。 Connection pooling leaks isolation level changes across Close()/Open() boundaries .那就是你的问题。有一些简单的解决方案:

在我们谈话的同时,您还需要阅读以下内容:Using Tables as Queues .

关于c# - 在(不相关的?)事务中使用 IsolationLevel.ReadUncommitted 时,SqlDependency 订阅不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19791152/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com