对于数据访问当然会涉及到事务管理,对于 NHibernate 来说,通常我们使用下面的方式进行。
// 创建新公司 var session = Assyria.DataAccess.SessionFactory.GetCurrentSession(); using (NHibernate.ITransaction transaction = session.BeginTransaction()) { session.Save(company); transaction.Commit(); }
会话的 BeginTransaction 用来启动事务管理,Commit 方法用来显式提交事务。
在 Spring.NET 中,对于事务管理提供了完善的支持,尤其与 NHibernate 的集成,更是非常方便。
首先,Spring.NET 在程序集 Spring.Data.NHibernate32 中提供了 Spring.Data.NHibernate.LocalSessionFactoryObject,作为会话工厂对象。然后,通过在 Spring.Data.NHibernate32 中提供的 Spring.Data.NHibernate.HibernateTransactionManager 实现 Nhibernate 的事务管理。
具体事务的支持,可以通过特性来实现。
<tx:attribute-driven transaction-manager="transactionManager"/>
这样,数据访问的配置文件一般如下所示。
<?xml version="1.0" ?> <objects xmlns="http://www.springframework.net" xmlns:db="http://www.springframework.net/database" xmlns:tx="http://www.springframework.net/tx" > <!--描述--> <description> 数据访问的配置信息 包括:DbProvider NHibernate 异常处理 事务处理 </description> <!-- 通过主应用程序的上下文配置文件引用 --> <object type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core"> <property name="ConfigSections" value="databaseSettings"/> </object> <!-- 数据库的配置 --> <db:provider id="DbProvider" provider="SqlServer-2.0" connectionString="Data Source=${db.server};Database=TSQLFundamentals2008;Integrated Security=true;" /> <!-- NHibernate 配置 --> <!-- 可以通过 name 为其指定别名 name="SessionFactory" --> <object id="NHibernateSessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject,Spring.Data.NHibernate32" > <!-- 关于数据库连接的配置,直接使用 DbProvider 中的设置,这样,不需要为 Hibernate 再提供连接串和驱动 --> <property name="DbProvider" ref="DbProvider"/> <!-- 包含有映射文件的程序集,需要分析的hbm程序集名称 --> <property name="MappingAssemblies"> <list> <value>Forbetter.Domain</value> </list> </property> <!-- 其他的参数 --> <property name="HibernateProperties"> <dictionary> <!-- 方言 --> <entry key="dialect" value="NHibernate.Dialect.MsSql2008Dialect"/> <entry key="use_proxy_validator" value="false" /> <entry key="show_sql" value="true"/> </dictionary> </property> <!-- 与 Spring 的声明式事务集成 --> <property name="ExposeTransactionAwareSessionFactory" value="true" /> </object> <!-- 事务管理策略,本地数据库事务 --> <!----> <object id="transactionManager" type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate32"> <property name="DbProvider" ref="DbProvider"/> <property name="SessionFactory" ref="NHibernateSessionFactory"/> </object> <!--支持事务的特性--> <!----> <tx:attribute-driven transaction-manager="transactionManager"/> <!-- 持久化异常转换处理 --> <object type="Spring.Dao.Attributes.PersistenceExceptionTranslationPostProcessor, Spring.Data"/> </objects>
在代码中,通过事务的特性来声明需要的事务即可。这个特性定义在 Spring.Transaction.Interceptor 命名空间下,名为 Transaction。
可以通过 Transaction 声明事务的传播以及隔离性。
事务的传播行为有如下 7 种,定义在 Spring.Transaction.TransactionPropagation 枚举中,可以通过事务特性的 TransactionPropagation 属性进行声明。默认为 TransactionPropagation.Required。
隔离性有如下 7 种,可以通过事务标签的 IsolationLevel 进行声明。默认为 IsolationLevel.ReadCommitted。
ReadOnly属性用来设置事务是否是只读的,默认是假。为 read/write.
NoRollbackFor 和 RollbackFor 用来设置事务的回滚策略,分别用来设置对于哪些异常不需要回滚和哪些异常需要回滚。默认为任何异常都导致回滚。
使用方式如下。
public class FulfillmentService : IFulfillmentService { // fields and properties for dao object omitted, see above [Transaction(ReadOnly = false)] public void ProcessCustomer(string customerId) { //Find all orders for customer Customer customer = CustomerDao.FindById(customerId); foreach (Order order in customer.Orders) { //Validate Order Validate(order); //Ship with external shipping service ShippingService.ShipOrder(order); //Update shipping date order.ShippedDate = DateTime.Now; //Update shipment date OrderDao.SaveOrUpdate(order); //Other operations...Decrease product quantity... etc } } }
如果你不喜欢使用特性来标注事务,Spring.NET为NHibernate提供的事务代理是 TransactionProxyFactoryObject。也可以使用下面的配置方式来取代特性。
<object id="TxProxyConfigurationTemplate" abstract="true" type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data"> <property name="PlatformTransactionManager" ref="HibernateTransactionManager"/> <property name="TransactionAttributes"> <name-values> <!-- Add common methods across your services here --> <add key="Process*" value="PROPAGATION_REQUIRED"/> </name-values> </property> </object>
注意写法有些变化,对于事务的传播增加了前缀 PROPAGATION_