我在面試中經(jīng)常會(huì)問(wèn)到這樣的一個(gè)問(wèn)題,假如有一個(gè)全局變量,在一個(gè)事務(wù)中修改了這個(gè)變量的值,而后這個(gè)事務(wù)因?yàn)閯e的原因回滾了,那這個(gè)變量的值會(huì)回滾到更改之前的值么?
其實(shí)事務(wù)只能對(duì)它所管理的資源進(jìn)行提交和回滾,這些資源就是事務(wù)源,它通常包括數(shù)據(jù)庫(kù)連接資源,JMS隊(duì)列資源等。事務(wù)的ACID(原子性,一致性,隔離性,持久性)屬性也是針對(duì)它所管理的資源而言的。前面問(wèn)題中的一個(gè)全局變量,可以說(shuō)是內(nèi)存中的一塊存儲(chǔ)空間,那么內(nèi)存中的數(shù)據(jù)如何能具備事務(wù)屬性中的持久性呢?很顯然它不在事務(wù)的管轄范圍之內(nèi),也就不會(huì)跟著事務(wù)的回滾而回滾了。
二、何時(shí)回滾事務(wù)
在JDBC事務(wù)和EJB的Bean管理事務(wù)中,我們通常會(huì)按下面這種方式控制事務(wù)的回滾。在出現(xiàn)某種的異常情況下,我們可以控制讓事務(wù)回滾,當(dāng)然也可以提交這個(gè)事務(wù)。
Connection cn = ... cn.setAutoCommit(false); Statement stmt = cn.createStatement(); try{ stmt.executeUpdate("update Order..."); cn.commit(); }catch(Exception e) { cn.rollback(); //出現(xiàn)異常,回滾當(dāng)前事務(wù) }finally{ stmt.close(); cn.close(); } |
但是對(duì)于EJB的容器管理事務(wù)或者Spring的聲明式事務(wù),就不大一樣了。例如:
Connection cn = ... cn.setAutoCommit(false); Statement stmt = cn.createStatement(); try{ stmt.executeUpdate("update Order..."); cn.commit(); }catch(Exception e) { cn.rollback(); //出現(xiàn)異常,回滾當(dāng)前事務(wù) }finally{ stmt.close(); cn.close(); } |
我們只告訴EJB容器這個(gè)方法需要事務(wù)控制,容器會(huì)在方法的開(kāi)始處啟動(dòng)一個(gè)事務(wù),在方法返回之前提交這個(gè)事務(wù)。那如果中間處理過(guò)程中出現(xiàn)異常該怎么辦?默認(rèn)情況下只有在RuntimeException和標(biāo)注為ApplicationException的異常發(fā)成時(shí)會(huì)回滾事務(wù),而在其他的情況下,事務(wù)都會(huì)提交。也就是說(shuō),在異常發(fā)生之前所有的操作都會(huì)被提交。這就有可能會(huì)出現(xiàn)部分提交的問(wèn)題。有時(shí)為了確保一個(gè)方法所有的操作都被提交或者回滾,通常會(huì)這樣做:
@TransactionAttribute(TransactionAttributeType.Required) public void updateOrder(Order order) { try{ ... }catch(Exception e) { throw new EJBException(e); } } |
在有異常發(fā)生時(shí),捕獲這個(gè)異常,并把它包裝成一個(gè)EJBException,并重新拋出它。因?yàn)镋JBException繼承了RuntimeException,所以這里拋出一個(gè)EJBException告訴EJB容器回滾當(dāng)前的事務(wù)。
另外需要注意的是另外一個(gè)方法:setRollbackOnly(),它與EJBException不同的是,它僅僅標(biāo)記當(dāng)前事務(wù)需要回滾,在方法執(zhí)行完成之后容器會(huì)檢查它并回滾事務(wù),它并不拋出任何異常。
相比較EJB,Spring的聲明式事務(wù)好像控制的更細(xì)致一些。來(lái)看下面的例子
@Transactional(rollbackFor={Exception.class}) public void updateOrder(Order order) { ... } |
我們可以告訴Spring哪種類(lèi)型的異常需要回滾,當(dāng)然默認(rèn)的還是只有在發(fā)生RuntimeException時(shí)事務(wù)會(huì)回滾。如果大家也在使用這種事務(wù)控制方式的話(huà),還是主動(dòng)告訴容器何時(shí)回滾,何時(shí)提交事務(wù)吧,采用默認(rèn)值并不是一個(gè)好的辦法
新聞熱點(diǎn)
疑難解答
圖片精選