当我们需要在应用程序中进行数据库访问时,我们使用以下模式:
- 为了查询,我们有一个带有方法的静态工厂类
CreateOpenConnection
其作用无非是new SqlConnection(myConnectionString)
并打电话Open()
在上面。在执行查询之前调用此方法,并在查询返回后释放连接。
- 对于插入/更新/删除,我们使用工作单元模式,其中批处理更改并通过调用提交到数据库
work.Commit()
像这样:
工作.提交:
using (var tranScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
using (var conn = DapperFactory.CreateOpenConnection())
{
var count = _changeTracker.CommitChanges(conn);
tranScope.Complete();
return count;
}
}
这似乎非常适合作为 Web 服务的一部分进行一般使用,但目前当我尝试将其与 Rebus 结合使用时,MSDTC 遇到了麻烦。
据我所知,Rebus(当它处理队列中的消息时)创建了一个新的TransactionScope
以便在处理消息失败的情况下,可以回滚内容。现在,到目前为止,这本身运行良好。我可以开一个新的SqlConnection
在 Rebus 消息处理程序中没有任何问题(但是,使用我们的旧实体框架查询and同一 Rebus 内的手动 SqlConnectionsTransactionScope
不起作用,但我现在不认为这是一个问题)。但昨天我问了以下问题:
Rebus中某种消息类型的串行处理 https://stackoverflow.com/questions/16837668/serial-processing-of-a-certain-message-type-in-rebus/16843938#16843938
答案似乎是使用 Rebus 的 saga 功能。我尝试实现这个并对其进行配置,以便将 Rebus 传奇持久化到新的 SQL Server 数据库(具有不同的连接字符串)。据推测,使用 SQL Server 持久性会打开一个SqlConnection
它自己的,因为任何时候我尝试创建一个SqlConnection
现在,我得到以下异常:
分布式事务管理器 (MSDTC) 的网络访问已被禁用。请使用组件服务管理工具在 MSDTC 的安全配置中启用 DTC 进行网络访问。
启用 MSDTC 是我非常想要的,very在配置和性能开销方面,很想避免这样做。我可能是错的,但这似乎也没有必要。
我认为这里发生的是 Rebus 创建了一个环境TransactionScope
并且那SqlConnection
它会创建该范围的入伍者。当我尝试创建自己的SqlConnection
它还尝试加入该环境范围,并且由于涉及多个连接,因此它被提升为 MSDTC,但失败了。
我有一个关于如何解决这个问题的想法,但我不知道这是否是正确的做法。我要做的是:
- Add
Enlist=false
到我的应用程序的连接字符串,以便它永远不会加入环境事务。
- 修改
Commit
方法,这样它就不会创建新的TransactionScope
(我的连接不会再订阅,因为我只是告诉它不应该)但它使用conn.BeginTransaction
.
Like so:
var transaction = conn.BeginTransaction();
try
{
var count = _changeTracker.CommitChanges(conn);
transaction.Commit();
return count;
}
catch
{
transaction.Rollback();
throw;
}
finally
{
transaction.Dispose();
}
我只是不确定这是否是正确的方法以及可能的缺点是什么。
有小费吗?
UPDATE:澄清一下,这不是work.Commit()
这一直给我带来问题,我很确定它会起作用,但我从来没有到达那里,因为我的querying就是失败。
失败的例子:
public int? GetWarehouseID(int appID)
{
var query = @"
select top 1 ID from OrganizationUnits o
where TypeID & 16 = 16 /* warehouse */";
using (var conn = _dapper.OpenConnection())
{
var id = conn.Query<int?>(query).FirstOrDefault();
return id;
}
}
当TransactionScope
是由 Rebus 创建的,也是经过SqlConnection
由Rebus打开。打开后my SqlConnection
,它尝试加入并崩溃