欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
第10章 Hibernate事務(wù)和并行(Transactions And Concurrency)

第 10 章 事務(wù)和并行(Transactions And Concurrency)

Hibernate本身并不是數據庫,它只是一個(gè)輕量級的對象-關(guān)系數據庫映射(object-relational)工具。它的事務(wù)交由底層的數據庫連接管理,如果數據庫連接有JTA的支持,那么在Session中進(jìn)行的操作將是整個(gè)原子性JTA事務(wù)的一部分。Hibernate可以看作是添加了面向對象語(yǔ)義的JDBC瘦適配器(thin adapter)。

10.1. 配置,會(huì )話(huà)和工廠(chǎng)(Configurations, Sessions and Factories)

SessionFactory的創(chuàng )建需要耗費大量資源,它是線(xiàn)程安全(threadsafe)的對象,在應用中它被所有線(xiàn)程共享。而Session的創(chuàng )建耗費資源很少,它不是線(xiàn)程安全的對象,對于一個(gè)簡(jiǎn)單商業(yè)過(guò)程(business process),它應該只被使用一次,然后被丟棄。舉例來(lái)說(shuō),當Hibernate在基于servlet的應用中,servlet能夠以下面的方式得到SessionFactory。

SessionFactory sf = (SessionFactory)getServletContext().getAttribute("my.session.factory");

每次調用SessionFactory的service方法能夠生成一個(gè)新的Session對象,然后調用Session的flush(),調用commit()提交它的連接,調用close()關(guān)閉它,最終丟棄它。(SessionFactory可能被保存在JNDI或者一個(gè)靜態(tài)的單例(Singleton)輔助變量中。)

在無(wú)狀態(tài)的session bean中,可以同樣使用類(lèi)似的方法。bean在setSessionContext()中得到SessionFactory的實(shí)例,每個(gè)商業(yè)方法會(huì )生成一個(gè)Session對象,調用它的flush()close(),當然,應用不應該commit()connection. (把它留給JTA.在容器管理的事務(wù)中,數據庫連接會(huì )自動(dòng)完成事務(wù)。)

我們用上述方法使用Hibernate 的Transaction API,對Transaction執行一次commit()會(huì )把所有狀態(tài)同步,把底層的數據庫連接提交(對JTA 事務(wù)會(huì )特殊處理。)

這里需要理解flush()的含義。 flush()將持久化存儲與內存中的變化進(jìn)行同步,但不是將內存的變化與持久化存儲進(jìn)行同步。注意對所有的Hibernate JDBD 連接/事務(wù)來(lái)說(shuō),其隔離級別將施加于所有的Hibernate執行的操作之上!

接下來(lái)的幾小節將討論利用版本化的方法來(lái)確保事務(wù)原子性,這些“高級”方法需要小心使用。

10.2. 線(xiàn)程和連接(Threads and connections)

在創(chuàng )建Hibernate會(huì )話(huà)(Session)時(shí),你應該留意以下的實(shí)踐(practices):

  • 對于一個(gè)數據庫連接,不要創(chuàng )建一個(gè)以上的SessionTransaction。

  • 在對于一個(gè)數據庫連接、一個(gè)事務(wù)使用多個(gè)Session時(shí),你尤其需要格外地小心。Session對象會(huì )記錄下調入數據更新的情況,所以另一個(gè)Session對象可能會(huì )遇到過(guò)時(shí)的數據。

  • Session不是線(xiàn)程安全的。決不要在兩個(gè)并發(fā)的線(xiàn)程中訪(fǎng)問(wèn)同一個(gè)Session。一個(gè)Session一般只對應一批需要一次性完成的單元操作!

10.3. 考慮對象辨別

程序可能在兩批單元操作中并發(fā)訪(fǎng)問(wèn)同一個(gè)對象的持久化狀態(tài)。不管怎樣,持久化類(lèi)的一個(gè)實(shí)例不可能在兩個(gè)Session中共享。所以有兩種不同的辨別方式:

數據庫辨別

foo.getId().equals( bar.getId() )

JVM 辨別

foo==bar

對于依附于某個(gè)特定Session的對象,兩種辨別方式是等價(jià)的。然而,當程序可能在兩個(gè)不同的session中并發(fā)訪(fǎng)問(wèn)“同一個(gè)”(持久化辨別)商業(yè)對象時(shí),兩個(gè)實(shí)例(對于JVM辨別來(lái)說(shuō))卻可能是“不同”的。

這種方式把關(guān)于并發(fā)的頭疼問(wèn)題留給了Hibernate和數據庫。程序不需要對任何商業(yè)對象進(jìn)行同步,只要程序堅持每個(gè)Session一個(gè)線(xiàn)程,或者對象辨別的策略(在一個(gè)Session重,程序可以安全的使用==來(lái)比較對象)。

10.4. 樂(lè )觀(guān)并發(fā)控制(Optimistic concurrency control)

許多商業(yè)過(guò)程需要一系列與用戶(hù)進(jìn)行交互的過(guò)程,數據庫訪(fǎng)問(wèn)穿插在這些過(guò)程中。對于web和企業(yè)應用來(lái)說(shuō),跨一個(gè)用戶(hù)交互過(guò)程的數據事務(wù)是不可接受的。

維護各商業(yè)事務(wù)間的隔離(isolocation)就成為應用層的部分責任,我們把這種過(guò)程稱(chēng)為長(cháng)時(shí)間運行的應用事務(wù)(application transaction)。單一的應用事務(wù)可能跨越多個(gè)數據庫事務(wù)。如果這些數據庫事務(wù)中只有一個(gè)(最后一個(gè))保存了被修改的數據,其他事務(wù)只是簡(jiǎn)單地讀數據,則這個(gè)應用事務(wù)就是原子性的。

唯一滿(mǎn)足高并發(fā)性以及高可擴展性的方法是使用帶有版本化的樂(lè )觀(guān)并發(fā)控制。Hibernate為使用樂(lè )觀(guān)并發(fā)控制的代碼提供了三種可能的方法。

10.4.1. 使用長(cháng)生命周期帶有自動(dòng)版本化的會(huì )話(huà)

在整個(gè)商業(yè)過(guò)程中使用一個(gè)單獨的Session實(shí)例以及它的持久化實(shí)例,這個(gè)Session使用帶有版本化的樂(lè )觀(guān)鎖定機制,來(lái)確保多個(gè)數據庫事務(wù)對于應用來(lái)說(shuō)只是一個(gè)邏輯上的事務(wù)。在等待用戶(hù)交互時(shí),Session斷開(kāi)與數據庫的連接。這個(gè)方法從數據庫訪(fǎng)問(wèn)方面來(lái)看是最有效的,應用不需要關(guān)心對自己的版本檢查或是重新與不需要序列化(transient)的實(shí)例進(jìn)行關(guān)聯(lián)。

在整個(gè)應用事務(wù)中,使用單一的Session 實(shí)例和它的持久化實(shí)例。

Session 使用帶有版本化的樂(lè )觀(guān)鎖定來(lái)保證多個(gè)數據庫事務(wù)對程序來(lái)說(shuō)就如同是單一的邏輯應用事務(wù)。在等待用戶(hù)交互的時(shí)候,Session 脫離所有的底層JDBC連接。對于數據庫訪(fǎng)問(wèn)來(lái)說(shuō),這種方法是最高效的。程序自己不需要關(guān)心版本檢查或者把已經(jīng)脫離session的實(shí)例重新關(guān)聯(lián)到session。

// foo is an instance loaded earlier by the Sessionsession.reconnect();foo.setProperty("bar");session.flush();session.connection().commit();session.disconnect();

foo對象仍然知道是哪個(gè)Session把自己裝載的。 只要Session 擁有一個(gè)JDBC連接,我們可以把對象的更改提交。

如果我們的 Session 太大,以至于在用戶(hù)思考的時(shí)間內無(wú)法保存住,這種模式就會(huì )出現問(wèn)題。比如,HttpSession應該保持盡量小。因為Session也持有(必須的)第一級緩存,包含所有被裝載的對象,我們只能在很少的request/response周期中使用這一策略。這種少用是被鼓勵的,因為Session 很快就會(huì )出現過(guò)時(shí)的數據。

10.4.2. 使用帶有自動(dòng)版本化的多個(gè)會(huì )話(huà)

每個(gè)與持久化存儲的交互出現在一個(gè)新的Session中,在每次與數據庫的交互中,使用相同的持久化實(shí)例。應用操作那些從其它Session調入的已經(jīng)脫離session的實(shí)例的狀態(tài),通過(guò)使用Session.update()或者Session.saveOrUpdate()來(lái)重新建立與它們的關(guān)聯(lián)。

// foo is an instance loaded by a previous Sessionfoo.setProperty("bar");session = factory.openSession();session.saveOrUpdate(foo);session.flush();session.connection().commit();session.close();

你也可以調用lock()而非update(),如果你確信對象沒(méi)有被修改過(guò),可以使用LockMode.READ(進(jìn)行一次版本檢查,而跳過(guò)所有的緩存)。

10.4.3. 應用程序自己進(jìn)行版本檢查

每當一個(gè)新的Session中與數據庫出現交互的時(shí)候,這個(gè)session會(huì )在操作持久化實(shí)例前重新把它們從數據庫中裝載進(jìn)來(lái)。我們現在所說(shuō)的方式就是你的應用程序自己使用版本檢查來(lái)確保應用事務(wù)的隔離性。(當然,Hibernate仍會(huì )為你更新版本號)。從數據庫訪(fǎng)問(wèn)方面來(lái)看,這種方法是最沒(méi)有效率的,與entity EJB方式類(lèi)似。

// foo is an instance loaded by a previous Sessionsession = factory.openSession();int oldVersion = foo.getVersion();session.load( foo, foo.getKey() );if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();foo.setProperty("bar");session.flush();session.connection().commit();session.close();

當然,如果在低數據并行(low-data-concurrency)的環(huán)境中,并不需要版本檢查,你仍可以使用這個(gè)方法,只需要忽略版本檢查。

10.5. 會(huì )話(huà)斷開(kāi)連接(Session disconnection)

The first approach described above is to maintain a single Session for a whole business process thats spans user think time. (For example, a servlet might keep a Session in the user‘s HttpSession.) For performance reasons you should

上面提到的第一種方法是對于對一個(gè)用戶(hù)的一次登錄產(chǎn)生的整個(gè)商業(yè)過(guò)程維護一個(gè)Session。(舉例來(lái)說(shuō),servlet有可能會(huì )在用戶(hù)的HttpSession中保留一個(gè)Session)。為性能考慮,你必須

  1. 提交Transaction(或者JDBC連接),然后

  2. (在等待用戶(hù)操作前,)斷開(kāi)Session與JDBC連接。

Session.disconnect()方法會(huì )斷開(kāi)會(huì )話(huà)與JDBC的連接,把連接返還給連接池(除非是你自己提供這個(gè)連接的)。

Session.reconnect()方法會(huì )得到一個(gè)新的連接(你也可以自己提供一個(gè)),重新開(kāi)始會(huì )話(huà)。在重新連接后,你可以通過(guò)對任何可能被其它事務(wù)更新的對象調用Session.lock()方法,來(lái)強迫對你沒(méi)有更新的數據進(jìn)行版本檢查。你不需要對正在更新的數據調用lock()。

這是一個(gè)例子:

SessionFactory sessions;List fooList;Bar bar;....Session s = sessions.openSession();Transaction tx = null;try {tx = s.beginTransaction();fooList = s.find("select foo from eg.Foo foo where foo.Date = current date"http:// uses db2 date function);bar = (Bar) s.create(Bar.class);tx.commit();}catch (Exception e) {if (tx!=null) tx.rollback();s.close();throw e;}s.disconnect();

接下來(lái):

s.reconnect();try {tx = s.beginTransaction();bar.setFooTable( new HashMap() );Iterator iter = fooList.iterator();while ( iter.hasNext() ) {Foo foo = (Foo) iter.next();s.lock(foo, LockMode.READ);    //check that foo isn‘t stalebar.getFooTable().put( foo.getName(), foo );}tx.commit();}catch (Exception e) {if (tx!=null) tx.rollback();throw e;}finally {s.close();}

從上面的例子可以看到TransactionSession之間是多對一的關(guān)系。一個(gè)Session表示了應用程序與數據庫之間的一個(gè)對話(huà),Transaction把這個(gè)對話(huà)分隔成一個(gè)個(gè)在數據庫級別具有原子性的單元。

10.6. 悲觀(guān)鎖定(Pessimistic Locking)

用戶(hù)不需要在鎖定策略上花費過(guò)多時(shí)間,通常我們可以對JDBC連接選定一種隔離級別(isolationn level),然后讓數據庫完成所有的工作。高級用戶(hù)可能希望得到悲觀(guān)鎖定或者在新的事務(wù)開(kāi)始時(shí)重新得到鎖。

Hibernate一直都會(huì )使用數據庫的鎖定機制,而不會(huì )在內存中鎖定對象。

LockMode類(lèi)定義了Hibernate需要的不同的鎖級別。鎖由以下的機制得到:

  • LockMode.WRITE在Hibernate更新或插入一行數據時(shí)自動(dòng)得到。

  • LockMode.UPGRADE在用戶(hù)通過(guò)SELECT ... FOR UPDATE這樣的特定請求得到,需要數據庫支持這種語(yǔ)法。

  • LockMode.UPGRADE_NOWAIT在用戶(hù)通過(guò)SELECT ... FOR UPDATE NOWAIT這樣的特定請求在Oracle數據庫環(huán)境下得到。

  • LockMode.READ在Hibernate在不斷讀(Repeatable Read)和序列化(Serializable)的隔離級別下讀取數據時(shí)得到。也可以通過(guò)用戶(hù)的明確請求重新獲得。

  • LockMode.NONE表示沒(méi)有鎖。所有對象在Transaction結束時(shí)會(huì )切換到這種鎖模式,通過(guò)調用update()或者saveOrUpdate()與會(huì )話(huà)進(jìn)行關(guān)聯(lián)的對象,開(kāi)始時(shí)也會(huì )在這種鎖模式。

“明確的用戶(hù)請求”會(huì )以下的幾種方式出現:

  • 調用Session.load(),指定一種LockMode。

  • 調用Session.lock()。

  • 調用Query.setLockMode()。

如果在調用Session.load()時(shí)指定了UPGRADE或者UPGRADE_NOWAIT,并且請求的對象還沒(méi)有被會(huì )話(huà)調入,那么這個(gè)對象會(huì )以SELECT ... FOR UPDATE的方式調入。如果調用load()在一個(gè)已經(jīng)調入的對象,并且這個(gè)對象調入時(shí)的鎖級別沒(méi)有請求時(shí)來(lái)得嚴格,Hibernate會(huì )對這個(gè)對象調用lock()。

Session.lock()會(huì )執行版本號檢查的特定的鎖模式是:READ,UPGRADE或者UPGRADE_NOWAIT。(在UPGRADE或者UPGRADE_NOWAIT,SELECT ... FOR UPGRADE使用的情況下。)

如果數據庫不支持所請求的鎖模式,Hibernate將會(huì )選擇一種合適的受支持的鎖模式替換(而不是拋出一個(gè)異常)。這確保了應用具有可移植性。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Hibernate4實(shí)戰 之第五部分:Hibernate的事務(wù)和并發(fā)
第?13?章?事務(wù)和并發(fā)
Hibernate的事務(wù)和并發(fā)(4)
hibernate3入門(mén)
Hibernate工作原理(圖解)
Hibernate的優(yōu)缺點(diǎn)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久