任何人都可以快速概述一下使用TransactionScope和NHibernate吗?我是否需要对session/IEnlistmentNotification/etc执行任何特殊操作.让这个工作?有什么陷阱我应该担心吗?例如,我可以替换所有的hibernate事务:
var transaction = session.BeginTransaction(); try { // code transaction.Commit(); } catch (Exception) { transaction.Rollback(); }
有了这个?:
using (var scope = new TransactionScope()) { // code scope.Complete(); }
Iain.. 18
我已经使用nHibernate 2.1一段时间了,经过一些生产问题并尝试了很多变化之后,我们已经确定了以下方法,根据避免与NHibernate和TransactionScope的泄漏连接:
using (var scope = new TransactionScope(TransactionScopeOption.Required)) { using (var session = sessionFactory.OpenSession()) using (var transaction = session.BeginTransaction()) { // do what you need to do with the session transaction.Commit(); } scope.Complete(); }
由于我们正在使用MSMQ和WCF,因此我们不得不使用环境事务.
我们发现不使用session.BeginTransaction()导致连接泄漏.我们还发现在提交事务后重新使用会话会导致竞争条件(nHibernate不是线程安全的,DTSC提交/回滚发生在后台线程上).
我已经使用nHibernate 2.1一段时间了,经过一些生产问题并尝试了很多变化之后,我们已经确定了以下方法,根据避免与NHibernate和TransactionScope的泄漏连接:
using (var scope = new TransactionScope(TransactionScopeOption.Required)) { using (var session = sessionFactory.OpenSession()) using (var transaction = session.BeginTransaction()) { // do what you need to do with the session transaction.Commit(); } scope.Complete(); }
由于我们正在使用MSMQ和WCF,因此我们不得不使用环境事务.
我们发现不使用session.BeginTransaction()导致连接泄漏.我们还发现在提交事务后重新使用会话会导致竞争条件(nHibernate不是线程安全的,DTSC提交/回滚发生在后台线程上).
我使用不同的供应商测试了它,它只是有效.如果您没有"scope.Complete()",则事务将回滚.如果有多个持久资源,您可能需要让MSDTC运行所涉及的机器.在这种情况下,MSDTC将自动检测环境ADO.NET事务并管理整个事务.
如果您正在使用支持使用轻量级事务管理器的连接提供程序,例如SQL Server 2005/2008,则上述工作正常.
如果您使用的是SQL Server 7/2000,那么即使您只打了一个数据库/资源,您的所有事务也将成为分布式事务.在大多数情况下,这可能不是您想要的,并且性能代价高昂.
因此,请检查您的连接提供程序和数据库服务器组合是否适合与TransactionScope一起使用.
我相信只要遵守一些约束,就可以用NHibernate事务替换它:
使用合理的最新NHibernate版本(> = 3.1)。
底层的ADO.NET数据提供程序必须支持TransactionScope(对于SQL Server,对于ODP.NET,Oracle> = 10即可)。
在 TransactionScope中创建您的NH会话,以确保它被征募。
手动处理NHibernate 冲洗。另请参阅此处和此处。
准备分布式事务。如果在一个作用域中创建多个会话,则最初的本地事务可能会升级为分布式事务。即使在使用ODAC 11.2.0.3.20的Oracle 11.2 DB上使用相同的连接字符串,我也看到了这种情况。在SQL Server 2008 R2上,它没有升级。(顺便说一句,可以通过查看Transaction.Current.TransactionInformation.DistributedIdentifier来看到这一点,对于本地事务为null。)尽管分布式事务有一些优势,但它们更昂贵,并且设置起来有些麻烦。(请参阅此处如何针对Oracle执行此操作)。为确保升级永远不会在Oracle中发生,请在连接字符串中设置“ Promotable Transaction = local”。如果某些代码尝试这样做,则会创建一个异常。
我希望就这些;-)
PS:我添加了Oracle详细信息,因为它们会使我的关注点和其他方面受益。