Dav*_*och 3 c# sql transactions sqldependency sql-server-2012
我已经设法让SqlDependency工作,但只要我不使用IsolationLevel.ReadUncommited
我认为是与SqlDependency无关的SQL事务.
当我IsolationLevel.ReadUncommitted
在事务中使用时(下面有很多注释),SqlDependency订阅失败,并立即OnChange
通知:
sqlNotificationEventArgs.Info = "Isolation";
sqlNotificationEventArgs.Source = "Statement";
sqlNotificationEventArgs.Type = "Subscribe";
Run Code Online (Sandbox Code Playgroud)
当我删除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();
}
}
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之前,我觉得我已经正确处理了上下文,它的连接和事务,但似乎并非如此.
我在这做错了什么?
恭喜你开始SqlDependency
工作(我根本没有讽刺,很多人都没有成功).
现在是时候阅读MSDN上的创建通知查询主题了.您将看到查询对通知有效的条件,包括此要求:
该语句不能在READ_UNCOMMITTED或SNAPSHOT隔离级别下运行.
我写了关于工作原理的基础知识SqlDependency
,或许会澄清一些误解.而且,作为一个副节点,由于你正在使用Linq,你可能会对LinqToCache感兴趣,它提供了Linq
查询和之间的桥梁SqlDependency
.
另一个评论:不要Start()
和Stop()
你的SqlDependency
illy威利.你很快就会后悔的.Start()
应用程序启动期间应该只调用一次,在应用Stop()
程序关闭期间恰好调用一次(严格来说,是在appdomain加载和卸载期间).
现在,关于您的问题:重要的隔离级别是通知的查询之一.这意味着,在其上附加订阅,查询不上你做的查询UPDATE
(读我不会弄脏下执行更新的智慧评论...或者使用肮脏的啥子东西读).据我所知,您显示的代码不应在read_uncommitted下发布查询.SET TRANSACTION ISOLATION ...
在该会话中发出所有后续事务(ergo all statements)之后将处于该隔离级别.您关闭连接(通过处理DataContext),然后使用不同的连接.除非......你使用连接池.欢迎来到无辜受害者俱乐部:).连接池泄漏跨越Close()
/ Open()
边界的隔离级别更改.那是你的问题.有一些简单的解决方案:
Open()
在我们谈论的同时,您还需要阅读:使用表作为队列.