Spring.NET实用技巧3——NHibernate分布式事务(上)
在使用NHibernate作為持久層框架時(shí),多數(shù)據(jù)庫(kù)操作是一個(gè)比較難解決的問(wèn)題。并且很多網(wǎng)友在給我發(fā)的eamil中經(jīng)常談到此問(wèn)題。由于NHibernate是一種框架,不能像ADO.NET那樣直接用SQL語(yǔ)句操作數(shù)據(jù)庫(kù),在動(dòng)態(tài)改變DbConnection時(shí)比較麻煩,而且NHibernate目前并不完全支持多數(shù)據(jù)庫(kù),所以實(shí)現(xiàn)多數(shù)據(jù)庫(kù)的操作是個(gè)棘手的問(wèn)題。
回想一下,在使用ADO.NET實(shí)現(xiàn)多數(shù)據(jù)庫(kù)的時(shí)候,無(wú)非是增加多個(gè)DbConnection,以后在每次事務(wù)結(jié)束后提交事務(wù)。所以說(shuō)多數(shù)據(jù)庫(kù)的實(shí)現(xiàn)難點(diǎn)在于實(shí)現(xiàn)分布式事務(wù)。那么,什么是分布式事務(wù)?分布式事務(wù)是指事務(wù)的參與者、支持事務(wù)的服務(wù)器、資源服務(wù)器以及事務(wù)管理器分別位于不同的分布式系統(tǒng)的不同節(jié)點(diǎn)之上。為了實(shí)現(xiàn)分布式事務(wù),需要使用下面將介紹的兩階段提交協(xié)議。 階段一:開(kāi)始向事務(wù)涉及到的全部資源發(fā)送提交前信息。此時(shí),事務(wù)涉及到的資源還有最后一次機(jī)會(huì)來(lái)異常結(jié)束事務(wù)。如果任意一個(gè)資源決定異常結(jié)束事務(wù),則整個(gè)事務(wù)取消,不會(huì)進(jìn)行資源的更新。否則,事務(wù)將正常執(zhí)行,除非發(fā)生災(zāi)難性的失敗。為了防止會(huì)發(fā)生災(zāi)難性的失敗,所有資源的更新都會(huì)寫(xiě)入到日志中。這些日志是永久性的,因此,這些日志會(huì)幸免遇難并且在失敗之后可以重新對(duì)所有資源進(jìn)行更新。? 階段二:只在階段一沒(méi)有異常結(jié)束的時(shí)候才會(huì)發(fā)生。此時(shí),所有能被定位和單獨(dú)控制的資源管理器都將開(kāi)始執(zhí)行真正的數(shù)據(jù)更新。 在分布式事務(wù)兩階段提交協(xié)議中,有一個(gè)主事務(wù)管理器負(fù)責(zé)充當(dāng)分布式事務(wù)協(xié)調(diào)器的角色。事務(wù)協(xié)調(diào)器負(fù)責(zé)整個(gè)事務(wù)并使之與網(wǎng)絡(luò)中的其他事務(wù)管理器協(xié)同工作。 為了實(shí)現(xiàn)分布式事務(wù),必須使用一種協(xié)議在分布式事務(wù)的各個(gè)參與者之間傳遞事務(wù)上下文信息,IIOP便是這種協(xié)議。這就要求不同開(kāi)發(fā)商開(kāi)發(fā)的事務(wù)參與者必須支持一種標(biāo)準(zhǔn)協(xié)議,才能實(shí)現(xiàn)分布式的事務(wù)。
由于Spring.NET框架的出現(xiàn),便很好的解決了這一點(diǎn)——分布式事務(wù)處理(查詢此博客)。TxScopePlatformTransactionManager由System.Transactions提供的本地/分布式的事務(wù)管理器。我們配置TxScopePlatformTransactionManager 則能夠?qū)崿F(xiàn)分布式事務(wù)處理。
下面,我建立兩個(gè)數(shù)據(jù)庫(kù):一個(gè)數(shù)據(jù)庫(kù)為Customer,用于存放客戶資料數(shù)據(jù);另一個(gè)數(shù)據(jù)庫(kù)為Order,用于存放客戶的訂單數(shù)據(jù)。當(dāng)某個(gè)客戶增加訂單成功時(shí),則更新該客戶的訂金余額。我們做一個(gè)業(yè)務(wù)判斷,該客戶的余額不能超過(guò)3000,當(dāng)超過(guò)3000時(shí)則拋出異常。
實(shí)現(xiàn)步驟如下:
一、啟動(dòng)MSDTC服務(wù)。運(yùn)行->cmd輸入->net start msdtc
?
?
? 二、代碼實(shí)現(xiàn)
?
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"/>
????????<!--自動(dòng)建表(反向映射)-->
????????<entry?key="hbm2ddl.auto"?value="update"/>
????????<!--批量更新-->
????????<entry?key="adonet.batch_size"?value="0"/>
????????<!--超時(shí)時(shí)間-->
????????<entry?key="command_timeout"?value="60"/>
????????<!--啟用二級(jí)緩存-->
????????<entry?key="cache.use_second_level_cache"?value="false"/>
????????<!--啟動(dòng)查詢緩存-->
????????<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"/>
????????<!--自動(dòng)建表(反向映射)-->
????????<entry?key="hbm2ddl.auto"?value="update"/>
????????<!--批量更新-->
????????<entry?key="adonet.batch_size"?value="0"/>
????????<!--超時(shí)時(shí)間-->
????????<entry?key="command_timeout"?value="60"/>
????????<!--啟用二級(jí)緩存-->
????????<entry?key="cache.use_second_level_cache"?value="false"/>
????????<!--啟動(dòng)查詢緩存-->
????????<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?=?"中國(guó)北京",
????????????????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>
?
?
?
運(yùn)行結(jié)果如下:
一、初始化數(shù)據(jù):
?
?
二、建立第一個(gè)訂單(插入第一次數(shù)據(jù)),訂金小于3000
?
三、建立第一個(gè)訂單(插入第二次數(shù)據(jù)),訂金小于3000
?
四、建立第一個(gè)訂單(插入第三次數(shù)據(jù)),訂金等于3000
?
五、建立第一個(gè)訂單(插入第四次數(shù)據(jù)),訂金超過(guò)3000
?
?
從運(yùn)行結(jié)果上看到,當(dāng)我們創(chuàng)建第四張訂單時(shí),由于訂金超過(guò)3000后拋出異常,數(shù)據(jù)實(shí)現(xiàn)回滾。這樣分布式事務(wù)便實(shí)現(xiàn)了。
?
代碼下載
出處:http://www.cnblogs.com/GoodHelper/archive/2010/07/29/SpringNetDistributedTransaction1.html
歡迎轉(zhuǎn)載,但需保留版權(quán)。
轉(zhuǎn)載于:https://www.cnblogs.com/GoodHelper/archive/2010/07/29/SpringNetDistributedTransaction1.html
總結(jié)
以上是生活随笔為你收集整理的Spring.NET实用技巧3——NHibernate分布式事务(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 多分辨率图像的快速查询
- 下一篇: 将数据文件附加到数据库