在(无关?)Transaction中使用IsolationLevel.ReadUncommitted时,SqlDependency预订不起作用

Dav*_*och 3 c# sql transactions sqldependency sql-server-2012

我已经设法让SqlDependency工作,但只要我不使用IsolationLevel.ReadUncommited我认为是与SqlDependency无关的SQL事务.

当我IsolationLevel.ReadUncommitted在事务中使用时(下面有很多注释),S​​qlDependency订阅失败,并立即OnChange通知:

sqlNotificationEventArgs.Info = "Isolation";
sqlNotificationEventArgs.Source = "Statement";
sqlNotificationEventArgs.Type = "Subscribe";
Run Code Online (Sandbox Code Playgroud)

当我删除I​​solationLevel时,一切都按预期工作(当然,隔离是不对的).

这是我的相关代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud)

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

我在这做错了什么?

Rem*_*anu 7

恭喜你开始SqlDependency工作(我根本没有讽刺,很多人都没有成功).

现在是时候阅读MSDN上的创建通知查询主题了.您将看到查询对通知有效的条件,包括此要求:

该语句不能在READ_UNCOMMITTED或SNAPSHOT隔离级别下运行.

我写了关于工作原理的基础知识SqlDependency,或许会澄清一些误解.而且,作为一个副节点,由于你正在使用Linq,你可能会对LinqToCache感兴趣,它提供了Linq查询和之间的桥梁SqlDependency.

另一个评论:不要Start()Stop()你的SqlDependencyilly威利.你很快就会后悔的.Start()应用程序启动期间应该只调用一次,在应用Stop()程序关闭期间恰好调用一次(严格来说,是在appdomain加载和卸载期间).

现在,关于您的问题:重要的隔离级别是通知的查询之一.这意味着,在其上附加订阅,查询上你做的查询UPDATE(读我不会弄脏下执行更新的智慧评论...或者使用肮脏的啥子东西读).据我所知,您显示的代码不应在read_uncommitted下发布查询.SET TRANSACTION ISOLATION ...在该会话中发出所有后续事务(ergo all statements)之后将处于该隔离级别.您关闭连接(通过处理DataContext),然后使用不同的连接.除非......你使用连接池.欢迎来到无辜受害者俱乐部:).连接池泄漏跨越Close()/ Open()边界的隔离级别更改.那是你的问题.有一些简单的解决方案:

在我们谈论的同时,您还需要阅读:使用表作为队列.