我正在使用NServiceBus构建一个系统,而我的DataLayer正在使用Linq 2 SQL。
系统由2项服务组成。
Service1从NSB接收消息。 它将查询我的数据库中的Table1 并将记录插入Table1 如果满足某个条件,则会向第二个服务发送新的NSB消息
Service1将在从Service1接收消息时更新Table1中的记录,并执行其他一些与数据库无关的工作。 Service2是一个长期运行的过程。
我遇到的问题是Service2更新表1中的记录,表被锁定。锁定似乎已经到位,直到Service2完成所有处理。 即我的datacontext被丢弃后,锁不会被释放。
这会导致Service1中的查询超时。 一旦Service2完成处理,Service1将再次恢复处理而不会出现问题。
例如,Service1代码可能如下所示:
int x =0;
using (DataContext db = new DataContext())
{
x = (from dp in db.Table1 select dp).Count(); // this line will timeout while service2 is processing
Table1 t = new Table1();
t.Data = "test";
db.Table1.InsertOnSubmit(t);
db.SubmitChanges();
}
if(x % 50 == 0)
CallService2();
service2中的代码可能如下所示:
using (DataContext db = new DataContext())
{
Table1 t = db.Table1.Where(t => t.id == myId);
t.Data = "updated";
db.SubmitChanges();
}
// I would have expected the lock to have been released at this point, but this is not the case.
DoSomeLongRunningTasks();
// lock will be released once service2 exits
我不明白为什么在Service2中放置datacontext时没有释放锁。
要解决我一直在呼唤的问题:
db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
这是有效的,但我不喜欢使用它。 我想妥善解决这个问题。
之前有没有人遇到过这类问题,有没有人知道如何解决? 为什么在丢弃datacontext之后没有释放锁?
提前致谢。
P.S。对非常长的帖子感到抱歉。
编辑:
在现实世界(ish)的情况下看这个,例如运费:
service1将crate记录添加到数据库中。 将包添加到容器记录中(如果不存在容器记录,则创建一个容器记录) 如果存在特定数量或包装箱记录,则创建装运记录并关闭所有容器并分配到装运记录。
然后调用service2来处理发货记录。 对service2的调用是一个Bus.Send调用,但可能是一个传奇的一部分。 service2将更新分配给它的船的每个箱子记录。 然后处理一些其他装运说明。 当service2正在处理时,可以收到更多的包装箱以供下次运输使用,但就目前而言,在service2处理完运输之前,它们无法分配到容器。
答案 0 :(得分:4)
您看到该行为的原因是NServiceBus使用的默认隔离级别(对于TransactionScope来说是相同的)是Serializable - 它会锁定整个表。
您要做的是在NServiceBus级别设置不同的隔离级别。
为了做到这一点,你需要使用流畅的初始化API,并在调用.MsmqTransport()之后调用方法.IsolationLevel(IsolationLevel.ReadCommitted)或传入一些其他值。我不建议低于那个(比如读未提交)。
在上面描述的场景中,我不会将所有这些放在一个处理程序中,而是更喜欢使用saga来管理顶级流,因为你似乎很高兴在处理程序中途打破隔离边界。
希望有所帮助。