Spring.NET 1.3.2 集成 NHibernate 3.2 - 5 - 事务管理
对于数据访问当然会涉及到事务管理,对于 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。
- REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
- MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
- REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
隔离性有如下 7 种,可以通过事务标签的 IsolationLevel 进行声明。默认为 IsolationLevel.ReadCommitted。
- Chaos:无法覆盖隔离级别更高的事务中的挂起的更改。
- ReadCommitted:在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。
- ReadUncommitted:可以进行脏读,意思是说,不发布共享锁,也不接受独占锁。
- RepeatableRead:在查询中使用的所有数据上放置锁,以防止其他用户更新这些数据。防止不可重复的读取,但是仍可以有幻像行。
- Serializable:在 System.Data.DataSet 上放置范围锁,以防止在事务完成之前由其他用户更新行或向数据集中插入行。
- Snapshot:通过在一个应用程序正在修改数据时存储另一个应用程序可以读取的相同数据版本来减少阻止。表示您无法从一个事务中看到在其他事务中进行的更改,即便重新查询也是如此。
- Unspecified:正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。
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_