Spring.NET实用技巧3——NHibernate分布式事务(上)
在使用NHibernate作為持久層框架時,多數據庫操作是一個比較難解決的問題。并且很多網友在給我發的eamil中經常談到此問題。由于NHibernate是一種框架,不能像ADO.NET那樣直接用SQL語句操作數據庫,在動態改變DbConnection時比較麻煩,而且NHibernate目前并不完全支持多數據庫,所以實現多數據庫的操作是個棘手的問題。
回想一下,在使用ADO.NET實現多數據庫的時候,無非是增加多個DbConnection,以后在每次事務結束后提交事務。所以說多數據庫的實現難點在于實現分布式事務。那么,什么是分布式事務?分布式事務是指事務的參與者、支持事務的服務器、資源服務器以及事務管理器分別位于不同的分布式系統的不同節點之上。為了實現分布式事務,需要使用下面將介紹的兩階段提交協議。 階段一:開始向事務涉及到的全部資源發送提交前信息。此時,事務涉及到的資源還有最后一次機會來異常結束事務。如果任意一個資源決定異常結束事務,則整個事務取消,不會進行資源的更新。否則,事務將正常執行,除非發生災難性的失敗。為了防止會發生災難性的失敗,所有資源的更新都會寫入到日志中。這些日志是永久性的,因此,這些日志會幸免遇難并且在失敗之后可以重新對所有資源進行更新。? 階段二:只在階段一沒有異常結束的時候才會發生。此時,所有能被定位和單獨控制的資源管理器都將開始執行真正的數據更新。 在分布式事務兩階段提交協議中,有一個主事務管理器負責充當分布式事務協調器的角色。事務協調器負責整個事務并使之與網絡中的其他事務管理器協同工作。 為了實現分布式事務,必須使用一種協議在分布式事務的各個參與者之間傳遞事務上下文信息,IIOP便是這種協議。這就要求不同開發商開發的事務參與者必須支持一種標準協議,才能實現分布式的事務。
由于Spring.NET框架的出現,便很好的解決了這一點——分布式事務處理(查詢此博客)。TxScopePlatformTransactionManager由System.Transactions提供的本地/分布式的事務管理器。我們配置TxScopePlatformTransactionManager 則能夠實現分布式事務處理。
下面,我建立兩個數據庫:一個數據庫為Customer,用于存放客戶資料數據;另一個數據庫為Order,用于存放客戶的訂單數據。當某個客戶增加訂單成功時,則更新該客戶的訂金余額。我們做一個業務判斷,該客戶的余額不能超過3000,當超過3000時則拋出異常。
實現步驟如下:
一、啟動MSDTC服務。運行->cmd輸入->net start msdtc
?
?
? 二、代碼實現
?
1.Domain
?
①.Customer
public?class?CustomerInfo????{
????????public?virtual?int??ID?{?get;?set;?}
????????public?virtual?string?Name?{?get;?set;?}
????????public?virtual?decimal?Money?{?get;?set;?}
????}
?
?
?
CustomerInfo.hbm.xml <?xml?version="1.0"?encoding="utf-8"??><hibernate-mapping?xmlns="urn:nhibernate-mapping-2.2"?assembly="Customer.Domain"?namespace="Customer.Domain">
??<class?name="CustomerInfo"?table="T_Customer"?lazy="true"?>
????<id?name="ID"?column="id"?type="Int32"?>
??????<generator?class="native"?/>
????</id>
????<property?name="Name"?type="string">
??????<column?name="Name"?length="50"/>
????</property>
????<property?name="Money"?type="decimal">
??????<column?name="Money"?precision="16"?scale="2"/>
????</property>
??</class>
</hibernate-mapping>
?
?
②.Order
?
OrderInfo public?class?OrderInfo????{
????????public?virtual?int??ID?{?get;?set;?}
????????public?virtual?int?CustomerId?{?get;?set;?}
????????public?virtual?DateTime?OrderDate?{?get;?set;?}
????????public?virtual?string?Address?{?get;?set;?}
????}
?
?
?
OrderInfo.hbm.xml <?xml?version="1.0"?encoding="utf-8"??><hibernate-mapping?xmlns="urn:nhibernate-mapping-2.2"?assembly="Order.Domain"?namespace="Order.Domain">
??<class?name="OrderInfo"?table="T_Order"?lazy="true"?>
????<id?name="ID"?column="ID"?type="Int32"?>
??????<generator?class="native"?/>
????</id>
????<property?name="CustomerId"?type="int">
??????<column?name="CustomerId"/>
????</property>
????<property?name="OrderDate"?type="DateTime">
??????<column?name="OrderDate"/>
????</property>
????<property?name="Address"?type="string">
??????<column?name="Address"?length="200"/>
????</property>
??</class>
</hibernate-mapping>
?
?
? 2.Dao
①.Customer
?
CustomerDao public?interface?ICustomerDao????{
????????CustomerInfo?Get(object?id);
????????object?Save(CustomerInfo?entity);
????????void?Update(CustomerInfo?entity);
????}
public?class?CustomerDao?:?HibernateDaoSupport,?ICustomerDao
????{
????????public?virtual?object?Save(CustomerInfo?entity)
????????{
????????????return?this.HibernateTemplate.Save(entity);
????????}
????????public?virtual?CustomerInfo?Get(object?id)
????????{
????????????return?this.HibernateTemplate.Get<CustomerInfo>(id);
????????}
????????public?void?Update(CustomerInfo?entity)
????????{
????????????this.HibernateTemplate.Update(entity);
????????}
????}
?
?
?
?
CustomerDao.xml <?xml?version="1.0"?encoding="utf-8"??><objects?xmlns="http://www.springframework.net"
?????????xmlns:db="http://www.springframework.net/database">
?
??<object?type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer,?Spring.Core">
????<property?name="ConfigSections"?value="databaseSettings"/>
??</object>
??<db:provider?id="Customer.DbProvider"?provider="SqlServer-2.0"
???????????????connectionString="Server=.;database=Customer;uid=sa;pwd=;"/>
??<object?id="Customer.NHibernateSessionFactory"?type="Spring.Data.NHibernate.LocalSessionFactoryObject,?Spring.Data.NHibernate21">
????<property?name="DbProvider"?ref="Customer.DbProvider"/>
????<property?name="MappingAssemblies">
??????<list>
????????<value>Customer.Domain</value>
??????</list>
????</property>
????<property?name="HibernateProperties">
??????<dictionary>
????????<entry?key="hibernate.connection.provider"?value="NHibernate.Connection.DriverConnectionProvider"/>
????????<!--SqlServer連接-->
????????<entry?key="dialect"?value="NHibernate.Dialect.MsSql2000Dialect"/>
????????<entry?key="hibernate.connection.driver_class"?value="NHibernate.Driver.SqlClientDriver"/>
????????<entry?key="use_outer_join"?value="true"/>
????????<entry?key="show_sql"?value="true"/>
????????<!--自動建表(反向映射)-->
????????<entry?key="hbm2ddl.auto"?value="update"/>
????????<!--批量更新-->
????????<entry?key="adonet.batch_size"?value="0"/>
????????<!--超時時間-->
????????<entry?key="command_timeout"?value="60"/>
????????<!--啟用二級緩存-->
????????<entry?key="cache.use_second_level_cache"?value="false"/>
????????<!--啟動查詢緩存-->
????????<entry?key="cache.use_query_cache"?value="false"/>
????????<entry?key="query.substitutions"?value="true?1,?false?0,?yes?'Y',?no?'N'"/>
????????<entry?key="proxyfactory.factory_class"?value="NHibernate.ByteCode.LinFu.ProxyFactoryFactory,?NHibernate.ByteCode.LinFu"/>
??????</dictionary>
????</property>
????<property?name="ExposeTransactionAwareSessionFactory"?value="true"?/>
??</object>
??<object?id="Customer.HibernateTemplate"?type="Spring.Data.NHibernate.Generic.HibernateTemplate">
????<property?name="SessionFactory"?ref="Customer.NHibernateSessionFactory"?/>
????<property?name="TemplateFlushMode"?value="Auto"?/>
????<property?name="CacheQueries"?value="true"?/>
??</object>
??<!--?Dao?-->
??<object?id="Customer.CustomerDao"?type="Customer.Dao.Implement.CustomerDao,Customer.Dao">
????<property?name="HibernateTemplate"?ref="Customer.HibernateTemplate"/>
??</object>
</objects>
?
?
②.Order
?
OrderDao public?interface?IOrderDao????{
????????object?Save(OrderInfo?entity);
????}
?public?class?OrderDao?:?HibernateDaoSupport,?IOrderDao
????{
????????public?virtual?object?Save(OrderInfo?entity)
????????{
????????????return?this.HibernateTemplate.Save(entity);
????????}
????}
?
?
?
?
Order.xml <?xml?version="1.0"?encoding="utf-8"??><objects?xmlns="http://www.springframework.net"
?????????xmlns:db="http://www.springframework.net/database">
?
??<object?type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer,?Spring.Core">
????<property?name="ConfigSections"?value="databaseSettings"/>
??</object>
??<db:provider?id="Order.DbProvider"?provider="SqlServer-2.0"
???????????????connectionString="Server=.;database=Order;uid=sa;pwd=;"/>
??<object?id="Order.NHibernateSessionFactory"?type="Spring.Data.NHibernate.LocalSessionFactoryObject,?Spring.Data.NHibernate21">
????<property?name="DbProvider"?ref="Order.DbProvider"/>
????<property?name="MappingAssemblies">
??????<list>
????????<value>Order.Domain</value>
??????</list>
????</property>
????<property?name="HibernateProperties">
??????<dictionary>
????????<entry?key="hibernate.connection.provider"?value="NHibernate.Connection.DriverConnectionProvider"/>
????????<!--SqlServer連接-->
????????<entry?key="dialect"?value="NHibernate.Dialect.MsSql2000Dialect"/>
????????<entry?key="hibernate.connection.driver_class"?value="NHibernate.Driver.SqlClientDriver"/>
????????<entry?key="use_outer_join"?value="true"/>
????????<entry?key="show_sql"?value="true"/>
????????<!--自動建表(反向映射)-->
????????<entry?key="hbm2ddl.auto"?value="update"/>
????????<!--批量更新-->
????????<entry?key="adonet.batch_size"?value="0"/>
????????<!--超時時間-->
????????<entry?key="command_timeout"?value="60"/>
????????<!--啟用二級緩存-->
????????<entry?key="cache.use_second_level_cache"?value="false"/>
????????<!--啟動查詢緩存-->
????????<entry?key="cache.use_query_cache"?value="false"/>
????????<entry?key="query.substitutions"?value="true?1,?false?0,?yes?'Y',?no?'N'"/>
????????<entry?key="proxyfactory.factory_class"?value="NHibernate.ByteCode.LinFu.ProxyFactoryFactory,?NHibernate.ByteCode.LinFu"/>
??????</dictionary>
????</property>
????<property?name="ExposeTransactionAwareSessionFactory"?value="true"?/>
??</object>
??<object?id="Order.HibernateTemplate"?type="Spring.Data.NHibernate.Generic.HibernateTemplate">
????<property?name="SessionFactory"?ref="Order.NHibernateSessionFactory"?/>
????<property?name="TemplateFlushMode"?value="Auto"?/>
????<property?name="CacheQueries"?value="true"?/>
??</object>
??<!--?Dao?-->
??<object?id="Order.OrderDao"?type="Order.Dao.Implement.OrderDao,Order.Dao">
????<property?name="HibernateTemplate"?ref="Order.HibernateTemplate"/>
??</object>
</objects>
?
?
三、Service
OrderManager ????public?interface?IOrderManager
????{
????????void?CreateOrder(OrderInfo?order,?decimal?money);
????????object?SaveCustomer(CustomerInfo?customer);
????}
public?class?OrderManager?:?IOrderManager
????{
????????public?ICustomerDao?CustomerDao?{?get;?set;?}
????????public?IOrderDao?OrderDao?{?get;?set;?}
????????[Transaction]
????????public?void?CreateOrder(OrderInfo?order,decimal?money)
????????{
????????????CustomerInfo?customer?=?CustomerDao.Get(order.CustomerId);
????????????OrderDao.Save(order);
????????????
????????????if?(customer.Money?>=?3000)
????????????{
????????????????throw?new?Exception("訂金額度上限");
????????????} customer.Money?+=?money;
????????????CustomerDao.Update(customer);
????????}
????????[Transaction]
????????public?object?SaveCustomer(CustomerInfo?customer)
????????{
????????????return?CustomerDao.Save(customer);
????????}
????}
?
?
?
Service.xml <?xml?version="1.0"?encoding="utf-8"??><objects?xmlns="http://www.springframework.net"
?????????xmlns:db="http://www.springframework.net/database"
?????????xmlns:tx="http://www.springframework.net/tx">
??<object?id="transactionManager"
??????????type="Spring.Data.Core.TxScopeTransactionManager,?Spring.Data">
??</object>
??<!--?Service?-->
??<object?id="Service.OrderManager"?type="Service.Implement.OrderManager,Service">
????<property?name="CustomerDao"?ref="Customer.CustomerDao"/>
????<property?name="OrderDao"?ref="Order.OrderDao"/>
??</object>
??<tx:attribute-driven/>
</objects>
?
?
四、Test
?
Test ?[TestFixture]????public?class?ServiceTest
????{
????????private?IApplicationContext?applicationContext;
????????
????????[SetUp]
????????public?void?Init()
????????{
????????????log4net.Config.XmlConfigurator.Configure();
????????????applicationContext?=?ContextRegistry.GetContext();
????????}
????????[Test]
????????public?void?InitData()
????????{
????????????CustomerInfo?customer?=?new?CustomerInfo
????????????{
????????????????Name?=?"劉冬"
????????????};
????????????IOrderManager?manager?=?(IOrderManager)applicationContext.GetObject("Service.OrderManager");
????????????manager.SaveCustomer(customer);
????????}
????????[Test]
????????public?void?CreateOrderTest()
????????{
????????????IOrderManager?manager?=?(IOrderManager)applicationContext.GetObject("Service.OrderManager");
????????????manager.CreateOrder(new?OrderInfo
????????????{
????????????????Address?=?"中國北京",
????????????????CustomerId?=?1,
????????????????OrderDate?=?DateTime.Now
????????????},?1000);
????????}
????}
?
?
?
App.config <?xml?version="1.0"?><configuration>
??<configSections>
????<sectionGroup?name="spring">
??????<section?name="context"?type="Spring.Context.Support.ContextHandler,?Spring.Core"/>
??????<section?name="parsers"?type="Spring.Context.Support.NamespaceParsersSectionHandler,?Spring.Core"/>
??????<section?name="objects"?type="Spring.Context.Support.DefaultSectionHandler,?Spring.Core"/>
????</sectionGroup>
????<section?name="log4net"?type="log4net.Config.Log4NetConfigurationSectionHandler,?log4net"?/>
????<section?name="databaseSettings"?type="System.Configuration.NameValueSectionHandler"?/>
??</configSections>
??<!--log4net配置-->
??<log4net?debug="true">
????<appender?name="LogFileAppender"?type="log4net.Appender.FileAppender">
??????<param?name="File"?value="Logs\Log.log"?/>
??????<param?name="datePattern"?value="MM-dd?HH:mm"?/>
??????<param?name="AppendToFile"?value="true"?/>
??????<layout?type="log4net.Layout.PatternLayout">
????????<param?name="ConversionPattern"?value="%d?[%t]?%-5p?%c?[%x]?-?%m%n"?/>
??????</layout>
????</appender>
????<appender?name="HttpTraceAppender"?type="log4net.Appender.ASPNetTraceAppender">
??????<layout?type="log4net.Layout.PatternLayout">
????????<param?name="ConversionPattern"?value="%d?[%t]?%-5p?%c?[%x]?-?%m%n"?/>
??????</layout>
????</appender>
????<appender?name="EventLogAppender"?type="log4net.Appender.EventLogAppender">
??????<layout?type="log4net.Layout.PatternLayout">
????????<param?name="ConversionPattern"?value="%d?[%t]?%-5p?%c?[%x]?-?%m%n"?/>
??????</layout>
????</appender>
????<appender?name="RollingLogFileAppender"?type="log4net.Appender.RollingFileAppender">
??????<param?name="File"?value="Logs/Log.log"?/>
??????<param?name="AppendToFile"?value="true"?/>
??????<param?name="MaxSizeRollBackups"?value="10"?/>
??????<param?name="MaximumFileSize"?value="100K"?/>
??????<param?name="RollingStyle"?value="Size"?/>
??????<param?name="StaticLogFileName"?value="true"?/>
??????<layout?type="log4net.Layout.PatternLayout">
????????<param?name="ConversionPattern"?value="%d?[%t]?%-5p?%c?[%x]?-?%m%n"?/>
??????</layout>
????</appender>
????<root>
??????<level?value="ALL"?/>
??????<appender-ref?ref="RollingLogFileAppender"?/>
????</root>
??</log4net>
??<!--spring配置-->
??<spring?xmlns="http://www.springframework.net">
????<parsers>
??????<parser?type="Spring.Data.Config.DatabaseNamespaceParser,?Spring.Data"?/>
??????<parser?type="Spring.Transaction.Config.TxNamespaceParser,?Spring.Data"?/>
????</parsers>
????<context>
??????<resource?uri="config://spring/objects"?/>
??????<!--Dao-->
??????<resource?uri="assembly://Customer.Dao/Customer.Dao.Config/Dao.xml"?/>
??????<resource?uri="assembly://Order.Dao/Order.Dao.Config/Dao.xml"?/>
??????<!--Service-->
??????<resource?uri="assembly://Service/Service.Config/Service.xml"?/>
????</context>
????<objects?xmlns="http://www.springframework.net"/>
??</spring>
??<startup><supportedRuntime?version="v4.0"?sku=".NETFramework,Version=v4.0"/></startup></configuration>
?
?
?
運行結果如下:
一、初始化數據:
?
?
二、建立第一個訂單(插入第一次數據),訂金小于3000
?
三、建立第一個訂單(插入第二次數據),訂金小于3000
?
四、建立第一個訂單(插入第三次數據),訂金等于3000
?
五、建立第一個訂單(插入第四次數據),訂金超過3000
?
?
從運行結果上看到,當我們創建第四張訂單時,由于訂金超過3000后拋出異常,數據實現回滾。這樣分布式事務便實現了。
?
代碼下載
出處:http://www.cnblogs.com/GoodHelper/archive/2010/07/29/SpringNetDistributedTransaction1.html
歡迎轉載,但需保留版權。
轉載于:https://www.cnblogs.com/GoodHelper/archive/2010/07/29/SpringNetDistributedTransaction1.html
總結
以上是生活随笔為你收集整理的Spring.NET实用技巧3——NHibernate分布式事务(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多分辨率图像的快速查询
- 下一篇: ADO.NET常用对象