標籤:c style class blog code java
Nhibernate 並發控制
【1】封閉式並行存取控制
正在使用資料的操作,加上鎖,使用完後解鎖釋放資源。
使用情境:資料競爭激烈,鎖的成本低於復原事務的成本
缺點:阻塞,可能死結
【2】開放式並行存取控制:
所謂樂觀,就是樂觀的認為其他人沒有在用該資源,資源的使用者不加鎖。
A 讀取資料後,如果該資料被別人B修改,產生錯誤,A復原事務並重新開始。
使用情境:資料競爭不激烈,復原事務的成本低於鎖的成本。
-----------------------------------------------------------------------------------------------------------
Nhibernate 支援開放式並行存取控制:
通過使用<version>或<timestamp>,節點配置。
注意: <version>要配置一定在<Id>節點之後。否則拋出配置錯誤。如下所示:
Customer.hbm.xmml
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model" assembly="Model" default-lazy="true"> <class name="Model.Customer, Model" table="Customer" discriminator-value="0" lazy="false"> <!--unsaved-value="0" 主鍵表中不需要定義,而是需要在子表中定義--> <id name="CustomerId" column="CustomerId" type="int" unsaved-value="0"> <generator class="native" /> <!-- unsaved-value used to be null and generator was increment in h2.0.3 --> </id> <!--version標籤必須放在Id後面,否則出錯--> <version name="Version"/>
......
Order.hbm.xml
<class name="Model.Order, Model" table ="[Order]" discriminator-value="0" lazy="true"> <id name="OrderId" column="OrderId" type="int" unsaved-value="0"> <!-- unsaved-value="0">--> <generator class="native" /> <!-- unsaved-value used to be null and generator was increment in h2.0.3 --> </id> <!--version標籤必須放在Id後面,否則出錯--> <version name="Version"/>
-------------------------------------------------------------------
使用<version>標籤 配置,實現並發控制。
原理:檢查資料庫的Version欄位的版本值:插入前檢查本身攜帶的Version是否等於現在資料庫的Version值,如果
【1】相等,插入成功,並且Vesion加儲存帶資料庫。
【2】不相等,插入失敗,並且拋出NHibernate.StaleObjectStateException類型異常,拋異常:所以並不需要Nhibernate事務的支援,用來復原事務,因為根本就沒插入。
-------------------------------------更新(Update)並發測試------------------------------------------
Customer更新(Update)並發測試:
[TestMethod] [ExpectedException(typeof(NHibernate.StaleObjectStateException))] public void TestVessionByUpdate() { CustomerService customerService = new CustomerService(); OrderService orderService = new OrderService(); Customer customer = new Customer() { FirstName = "Test", LastName = "TestVessionByUpdate", Age = 10 }; customerService.Add(customer); Customer customer1 = customerService.Get(customer.CustomerId); Customer customer2 = customerService.Get(customer.CustomerId); string customer1Name = "customer1"; customer1.FirstName = customer1Name; customer2.FirstName = "customer2Test"; customerService.Update(customer2); //能儲存到資料庫,Customer的version加1 customerService.Update(customer1); //拋出異常NHibernate.StaleObjectStateException,更新失敗。
}
Order更新(Update)並發測試:
[TestMethod] [ExpectedException(typeof(NHibernate.StaleObjectStateException))] public void TestVessionOrderByUpdateCustomer() { CustomerService customerService = new CustomerService(); OrderService orderService = new OrderService(); Customer customer = new Customer() { FirstName = "Test", LastName = "TestVessionOrderByUpdateCustomer", Age = 10 }; Order order1 = new Order() { OrderDate = DateTime.Now.AddMinutes(1), Customer = customer }; customer.Orders.Add(order1); customerService.Add(customer); Customer customer1 = customerService.Get(customer.CustomerId); Customer customer2 = customerService.Get(customer.CustomerId); customer1.Orders.First<Order>().OrderDate = customer1.Orders.First<Order>().OrderDate.AddDays(1); customer2.Orders.First<Order>().OrderDate = customer2.Orders.First<Order>().OrderDate.AddYears(1);
customerService.Update(customer2); //Customer和Order都能儲存到資料庫,Order的version加1 customerService.Update(customer1); //拋出異常NHibernate.StaleObjectStateException,更新失敗。
}
注意:
注意已經把已經事務的相關代碼注釋掉了是為說明上面的並發控制並不需要事務的支援。Upadate的代碼如下:
public void Update(Customer customer) { ISession session = _sessionManager.GetSession(); //ITransaction transaction = session.BeginTransaction(); try { session.Update(customer); session.Flush(); //transaction.Commit(); } catch (Exception) { //transaction.Rollback(); throw; } finally { session.Close(); } }
-------------------------------------刪除(Update)並發測試------------------------------------------
如果啟用了並發(即配置中添加了<version>標籤屬性),
那麼刪除的時候產生的SQL的Where語句會額外添加一個判斷條件
where customer.Version = 資料庫裡.vesesion
測試代碼:
[TestMethod] [ExpectedException(typeof(NHibernate.StaleObjectStateException))] public void TestVessionDeleteCustomer() { CustomerService customerService = new CustomerService(); OrderService orderService = new OrderService(); Customer customer = new Customer() { FirstName = "Test", LastName = "TestVessionDeleteCustomer", Age = 10 }; customerService.Add(customer); Assert.IsNotNull(customerService.Get(customer.CustomerId)); Customer customer1 = customerService.Get(customer.CustomerId); Customer customer2 = customerService.Get(customer.CustomerId); customerService.Delete(customer1); customerService.Delete(customer2); }
如所示:
如果並發刪除同一條記錄,會拋出NHibernate.StaleObjectStateException 類型的異常。