春天JDBC事務管理

  1. JDBC事務管理   
  2.   
  3.   
  4. 春天提供編程式的事務管理(編程式事務管理)與聲明式的事務管理(聲明式事務management),爲不同的事務實現提供了一致的編程模型,這節以JDBC事務爲例,介紹Spring的事務管理。   
  5.   
  6. 5.3   春天對事務的支持   
  7. 事務是一組原子(Atomic)操作的工作單元,以數據庫存取的實例來說,就是一組SQL指令,這一組SQL指令必須全部執行成功,若因爲某個原因未全部執行成功(例如其中一行SQL有錯誤),則先前所有執行過的SQL指令都會被撤消。   
  8.   
  9. 舉個簡單的例子,一個客戶從A銀行轉賬至B銀行,要作的動作爲從A銀行的賬戶扣款、在B銀行的賬戶加上轉賬的金額,兩個動作必須成功,如果有一個動作失敗,則此次轉賬失敗。   
  10.   
  11. 事務還必須保持所參與資源的一致性(Consistent),例如在銀行賬戶的例子中,兩個賬戶的轉賬金額,B賬戶取款的金額不能大於A賬戶的存款金額。每個事務彼此之間必須是隔離的(Isolated),例如在A賬戶中可能有兩筆事務,同時進行存款與提款的動作,兩個事務基本上不需意識到彼此的存在。事務還必須是可持續的(Durable),在某一筆事務之後,這筆事務必須是被記錄下來的。   
  12.   
  13. 在這裏將介紹JDBC如何使用事務管理。首先來看看事務的原子性實現,在JDBC中,可以操作Connection的setAutoCommit()方法,給定false 參數,在下達一連串的SQL語句後,自行執行Connection的commit()來送出變更,如果中間發生錯誤,則執行rollback()來撤消所有的執行,例如:   
  14.   
  15.   
  16. 在Spring中對JDBC的事務管理加以封裝,Spring事務管理的抽象關鍵在於org.springframework.transaction.PlatformTransactionManager接口的實現:   
  17.   
  18. ...   
  19.   
  20. 【JAVA]鑑於plaincopy  
  21. 公共 接口 的PlatformTransactionManager {    
  22.     
  23.     的TransactionStatus getTransaction(TransactionDefinition的     
  24.     
  25.                     定義)   拋出 TransactionException;    
  26.     
  27.     無效 提交(TransactionStatus對象的狀態)     
  28.     
  29.                                    拋出 TransactionException;    
  30.     
  31.     無效 回滾(TransactionStatus對象的狀態)     
  32.     
  33.                                    拋出 TransactionException;    
  34.     
  35. }    
  36.   
  37. PlatformTransactionManager接口有許多具體的事務實現類,例如DataSourceTransactionManager、HibernateTransactionManager、JdoTransaction- Manager、JtaTransactionManager等,通過依賴於PlatformTransactionManager接口及各種的技術實現,Spring在事務管理上可以讓開發人員使用一致的編程模型,即使所使用的是不同的事務管理技術。   
  38.   
  39. TransactionException是未選中Exception。事務的失敗通常都是致命的錯誤,Spring不強迫您一定要處理,而是讓您自行選擇是否要捕捉異常。   
  40.   
  41. getTransaction()級),傳播行爲(傳播   
  42.   
  43. ...   
  44.   
  45. 【JAVA]鑑於plaincopy  
  46. 公共 接口 的TransactionStatus {    
  47.     
  48.     布爾 isNewTransaction();    
  49.     
  50.     無效 的setRollbackOnly();    
  51.     
  52.     布爾 isRollbackOnly();    
  53.     
  54. }    
  55.   
  56. 春天提供編程式的事務管理(編程式事務管理)與聲明式的事務管理(聲明式事務管理):   
  57.   
  58. 升編程式的事務管理   
  59.   
  60. 編程式的事務管理可以清楚地控制事務的邊界,也就是讓您自行實現事務開始時間、撤消操作的時機、結束時間等,可以實現細粒度的事務控制。   
  61.   
  62. 升聲明式的事務管理   
  63.   
  64. 然而多數的情況下,事務並不需要細粒度的控制,而是採用聲明式的事務管理,好處是Spring事務管理的相關API可以不用介入程序之中,從對象的角度來看,它並不知道自己正被納入事務管理之中,在不需要事務管理的時候,只要在設置文件上修改一下設置,即可移去事務管理服務。   
  65.   
  66. 5.3   JDBC編程事務管理   
  67. 春天提供兩種方式實現編程式的事務管理,一是直接使用PlatformTransaction-經理實現,二是使用org.springframework.transaction.support.Transaction-模板。   
  68.   
  69. 先來看看如何使用PlatformTransactionManager,在這裏使用它的實現類DataSourceTransactionManager,可以改寫一下之前5.2 節中的JdbcTemplateDemo項目,讓它具有事務管理功能,修改一下UserDAO類的insert()方法來作示範:   
  70. ProgrammaticTransactionDemo UserDAO.java   
  71.   
  72. 【JAVA]鑑於plaincopy  
  73. 包裝 onlyfun.caterpillar;    
  74.     
  75. 進口 java.util.Iterator的;    
  76.     
  77. 進口 的java.util.List;    
  78.     
  79. 進口 的java.util.Map;    
  80.     
  81. 進口 javax.sql.DataSource的;    
  82.     
  83. 進口 org.springframework.dao.DataAccessException;    
  84.     
  85. 進口 org.springframework.jdbc.core.JdbcTemplate;    
  86.     
  87. 進口 org.springframework.jdbc。    
  88.     
  89.             datasource.DataSourceTransactionManager;    
  90.     
  91. 進口 org.springframework.transaction.TransactionDefinition;    
  92.     
  93. 進口 org.springframework.transaction.TransactionStatus;    
  94.     
  95. 進口 org.springframework.transaction。    
  96.     
  97.             support.DefaultTransactionDefinition;    
  98.     
  99. 公共  的UserDAO  實現 IUserDAO {    
  100.     
  101.     私人 的DataSourceTransactionManager transactionManager的;    
  102.     
  103.     私人 DefaultTransactionDefinition DEF;    
  104.     
  105.     私人 的JdbcTemplate JdbcTemplate的;    
  106.     
  107.         
  108.     
  109.     公共 無效 的setDataSource(數據源數據源){    
  110.     
  111.         的JdbcTemplate =   的JdbcTemplate(數據源);    
  112.     
  113.         transactionManager的=     
  114.     
  115.              的DataSourceTransactionManager(數據源);    
  116.     
  117.         //建立事務的定義    
  118.     
  119.         高清=   DefaultTransactionDefinition();    
  120.     
  121.         def.setPropagationBehavior(    
  122.     
  123.                 TransactionDefinition.PROPAGATION_REQUIRED);    
  124.     
  125.     }    
  126.     
  127.         
  128.     
  129.     公共 無效 插入(用戶用戶){    
  130.     
  131.        字符串名稱= user.getName();    
  132.     
  133.        INT  年齡= user.getAge()的intValue()。    
  134.     
  135.            
  136.     
  137.        TransactionStatus對象狀態=     
  138.     
  139.            transactionManager.getTransaction(DEF);    
  140.     
  141.        嘗試 {    
  142.     
  143.            jdbcTemplate.update(“INSERT INTO的用戶(姓名,年齡)”     
  144.     
  145.                    +  “VALUES('”  +名稱+  “',”  +年齡+  “)” );    
  146.     
  147.            //下面的SQL有錯誤,用以測試事務    
  148.     
  149.            jdbcTemplate.update(“INSER INTO用戶(姓名,年齡)”     
  150.     
  151.                    +  “VALUES('”  +名稱+  “',”  +年齡+  “)” );    
  152.     
  153.        }    
  154.     
  155.        (DataAccessException的E){    
  156.     
  157.            transactionManager.rollback(狀態);    
  158.     
  159.             é;     
  160.     
  161.        }    
  162.     
  163.        transactionManager.commit(狀態);    
  164.     
  165.     }    
  166.     
  167.     公衆 用戶發現(整數ID){    
  168.     
  169.         列表行= jdbcTemplate.queryForList(    
  170.     
  171.           “SELECT * FROM WHERE用戶ID =”  + id.intValue());    
  172.     
  173.             
  174.     
  175.         迭代它= rows.iterator();    
  176.     
  177.         如果(it.hasNext()){    
  178.     
  179.             地圖中userMap =(圖)it.next();    
  180.     
  181.             整數I =  新的 整數(    
  182.     
  183.                     userMap.get(“ID” )的ToString());    
  184.     
  185.             字符串名稱= userMap.get( “ 名” )的ToString();    
  186.     
  187.             整數年齡=  新的 整數(    
  188.     
  189.                     userMap.get( “ 時代” )的ToString());    
  190.     
  191.             用戶的用戶=   用戶();    
  192.     
  193.                 
  194.     
  195.             user.setId(ⅰ);    
  196.     
  197.             user.setName(名);    
  198.     
  199.             user.setAge(年齡);    
  200.     
  201.                 
  202.     
  203.             返回 用戶;    
  204.     
  205.         }    
  206.     
  207.         返回 空值;    
  208.     
  209.     }    
  210.     
  211. }    
  212.   
  213. 在insert()方法中使用了DataSourceTransactionManager來進行事務管理,如果發生了異常,則catch 區塊中會進行事務的Rollback,在insert()方法中故意寫入錯誤的SQL(注意INSERT方法少寫了一個T),因此實際上數據並不會被儲存至數據庫中。   
  214.   
  215. 要使用MySQL數據庫進行事務處理,必須建立支持事務的表格類型,例如InnoDB的表格類型,這裏用來建立表格的SQL如下所示:   
  216.   
  217. 【JAVA]鑑於plaincopy  
  218.  CREATE TABLE的用戶(    
  219.     
  220.     ID INT(11 )NOT NULL AUTO_INCREMENT PRIMARY KEY,    
  221.     
  222.     命名VARCHAR(100 )NOT NULL  默認 ,    
  223.     
  224.     年齡INT    
  225.     
  226. )TYPE = InnoDB的;    
  227.   
  228. 另一個實現編程式事務管理的方法是使用TransactionTemplate,它需要一個TransactionManager實例,如下所示:   
  229.   
  230. ...   
  231.   
  232. 【JAVA]鑑於plaincopy  
  233. TransactionTemplate的TransactionTemplate的=     
  234.     
  235.          TransactionTemplate的(transactionManager的);    
  236.     
  237. ...    
  238.     
  239. transactionTemplate.execute( TransactionCallback(){    
  240.     
  241.     公共 對象doInTransaction(TransactionStatus對象的狀態){    
  242.     
  243.          返回 jdbcTemplate.update(“INSERT INTO的用戶(姓名,年齡)”     
  244.     
  245.                +  “VALUES('”  +名稱+  “',”  +年齡+  “)” );    
  246.     
  247.     }    
  248.     
  249. });    
  250.   
  251. 如果發生了異常,則會進行Rollback,否則提交事務,如果沒有回傳值,則也可以使用TransactionCallbackWithoutResult:   
  252.   
  253. ...   
  254.   
  255. 【JAVA]鑑於plaincopy  
  256. transactionTemplate.execute(    
  257.     
  258.          TransactionCallbackWithoutResult(){    
  259.     
  260.                 公共 無效 doInTransactionWithoutResult(    
  261.     
  262.                                 TransactionStatus對象的狀態){    
  263.     
  264.             。...    
  265.     
  266.                 }    
  267.     
  268.             });    
  269.   
  270. 5.3   JDBC聲明事務管理   
  271. Spring聲明式的事務管理依賴它的AOP框架來完成。使用聲明事務管理的好處是,事務管理不能侵入您所開發的組件,具體來說,DAO對象不會意識到正在事務管理之中,事實上也應當如此,因爲事務管理是屬於系統層面的服務,而不是業務邏輯的一部分,如果想要改變事務管理策略的話,也只需要在定義文件中重新配置。   
  272.   
  273. 舉個例子來說,可以將5.2 節中的JdbcTemplateDemo項目修改一下,在不修改UserDAO類的情況下,可以爲它加入事務管理的服務,一個簡單的方法是使用TransactionProxyFactoryBean,指定要介入的事務管理對象及其方法,這需要在定義文件中修改,如下所示:   
  274.   
  275. DeclarativeTransactionDemo豆-config.xml中   
  276.   
  277. 【JAVA]鑑於plaincopy  
  278. <?XML版本= “1.0”  編碼= “UTF-8” ?>     
  279.     
  280. <豆的xmlns = “http://www.springframework.org/schema/beans”    
  281.     
  282.   XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”    
  283.     
  284.   XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans     
  285.     
  286.   HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd“>    
  287.     
  288.       
  289.     
  290.     <bean的ID = “數據源”     
  291.     
  292.           =“org.springframework.jdbc。    
  293.     
  294.                    →datasource.DriverManagerDataSource“    
  295.     
  296.           破壞法= “關閉” >      
  297.     
  298.         <屬性名= “driverClassName”     
  299.     
  300.                   值= “com.mysql.jdbc.Driver” />     
  301.     
  302.         <屬性名= “URL”    
  303.     
  304.                   值= “的jdbc:mysql的://本地主機:3306 /演示” />    
  305.     
  306.         <屬性名= “用戶名”  值= “毛毛蟲” />     
  307.     
  308.         <屬性名= “密碼”  值= “123456” />     
  309.     
  310.     </豆>     
  311.     
  312.         
  313.     
  314.     <bean的ID = “transactionManager的”     
  315.     
  316.           =“org.springframework.jdbc。    
  317.     
  318.                    →datasource.DataSourceTransactionManager“>     
  319.     
  320.         <屬性名= “數據源”  參考= “數據源” />     
  321.     
  322.     </豆>     
  323.     
  324.         
  325.     
  326.     <bean的ID = “userDAO的”     
  327.     
  328.           “onlyfun.caterpillar.UserDAO” >    
  329.     
  330.         <屬性名= “數據源”  參考= “數據源” />    
  331.     
  332.     </豆>    
  333.     
  334.         
  335.     
  336.     <bean的ID = “userDAOProxy”     
  337.     
  338.           =“org.springframework.transaction。    
  339.     
  340.                    →interceptor.TransactionProxyFactoryBean“>     
  341.     
  342.         <屬性名= “proxyInterfaces” >     
  343.     
  344.             <目錄>    
  345.     
  346.                 <值> onlyfun.caterpillar.IUserDAO </值>    
  347.     
  348.             </表>    
  349.     
  350.         </物業>     
  351.     
  352.         <屬性名= “目標”  參考= “userDAO的” />     
  353.     
  354.         <屬性名= “transactionManager的”     
  355.     
  356.                   REF = “transactionManager的” />     
  357.     
  358.         <屬性名= “transactionAttributes” >     
  359.     
  360.             <道具>     
  361.     
  362.                 <支撐鍵= “插入*” > PROPAGATION_REQUIRED </道具>     
  363.     
  364.             </道具>     
  365.     
  366.         </物業>            
  367.     
  368.     </豆>        
  369.     
  370. </豆>    
  371.   
  372. TransactionProxyFactoryBean需要一個TransactionManager,由於這裏使用的是JDBC,所以使用DataSourceTransactionManager,TransactionProxyFactoryBean是個代理對象,"target"  屬性指定要代理的對象,事務管理會自動介入指定的方法前後,這裏使用  "transactionAttributes"  屬性指定,"insert*"  表示指定方法名稱以insert開頭的都要納入事務管理,您也可以指定方法全名,如果在方法執行過程中發生錯誤,則所有先前的操作自動撤回,否則正常提交。   
  373.   
  374. "insert*"  等方法上指定了  "PROPAGATION_REQUIRED" ,表示在目前的事務中執行操作,如果事務不存在就建立一個新的,相關的常數意義都可以在API文件的TransactionDefinition接口中找到。您可以加上多個事務定義,中間使用逗號  ","  區隔,例如可以加上只讀,或者是指定某個異常發生時撤回操作:   
  375.   
  376. PROPAGATION_REQUIRED,只讀,-MyCheckedException   
  377.   
  378. MyCheckedException前面加上  "-"  時,表示發生指定異常時撤消操作,如果前面加上  "+" ,表示發生異常時立即提交。   
  379.   
  380. 由於"userDAO" "userDAOProxy" 代理了,所以要做的是取得"userDAOProxy" ,而不是"userDAO" ,例如:   
  381.   
  382. DeclarativeTransactionDemo SpringDAODemo.java   
  383.   
  384. 【JAVA]鑑於plaincopy  
  385. 包裝 onlyfun.caterpillar;    
  386.     
  387. 進口 org.springframework.context.ApplicationContext;    
  388.     
  389. 進口 org.springframework.context。    
  390.     
  391.               support.ClassPathXmlApplicationContext;    
  392.     
  393. 公共  SpringDAODemo {    
  394.     
  395.     公共 靜態 無效 的主要(字串[] args){    
  396.     
  397.         ApplicationContext的背景下=     
  398.     
  399.              的ClassPathXmlApplicationContext(    
  400.     
  401.                     “豆-config.xml文件” );    
  402.     
  403.             
  404.     
  405.         用戶的用戶=   用戶();    
  406.     
  407.             
  408.     
  409.         user.setName( “ 毛毛蟲” );    
  410.     
  411.         user.setAge(新的 整數(30 ));    
  412.     
  413.             
  414.     
  415.         IUserDAO userDAO的=     
  416.     
  417.             (IUserDAO)context.getBean(“userDAOProxy” );    
  418.     
  419.             
  420.     
  421.         userDAO.insert(用戶);    
  422.     
  423.             
  424.     
  425.         用戶= userDAO.find( 整型());    
  426.     
  427.             
  428.     
  429.         的System.out.println( “ 名”  + user.getName());    
  430.     
  431.     }    
  432.     
  433. }     
  434.   
  435. 您也可以設置不同的TransactionInterceptor來得到更多的管理細節,例如:   
  436.   
  437. 【JAVA]鑑於plaincopy  
  438. <?XML版本= “1.0”  編碼= “UTF-8” ?>     
  439.     
  440. <豆的xmlns = “http://www.springframework.org/schema/beans”    
  441.     
  442.   XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”    
  443.     
  444.   XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans     
  445.     
  446.   HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd“>    
  447.     
  448.       
  449.     
  450.     <bean的ID = “數據源”     
  451.     
  452.           =“org.springframework.jdbc。    
  453.     
  454.                    →datasource.DriverManagerDataSource“    
  455.     
  456.           破壞法= “關閉” >      
  457.     
  458.         <屬性名= “driverClassName”     
  459.     
  460.                   值= “com.mysql.jdbc.Driver” />     
  461.     
  462.         <屬性名= “URL”    
  463.     
  464.                   值= “的jdbc:mysql的://本地主機:3306 /演示” />    
  465.     
  466.         <屬性名= “用戶名”  值= “毛毛蟲” />     
  467.     
  468.         <屬性名= “密碼”  值= “123456” />     
  469.     
  470.     </豆>    
  471.     
  472.     <bean的ID = “transactionManager的”     
  473.     
  474.           =“org.springframework.jdbc。    
  475.     
  476.                    →datasource.DataSourceTransactionManager“>     
  477.     
  478.         <屬性名= “數據源”  參考= “數據源” />     
  479.     
  480.     </豆>     
  481.     
  482.         
  483.     
  484.     <bean的ID = “userDAO的”     
  485.     
  486.           “onlyfun.caterpillar.UserDAO” >    
  487.     
  488.         <屬性名= “數據源”  參考= “數據源” />    
  489.     
  490.     </豆>    
  491.     
  492.     <bean的ID = “transactionInterceptor”     
  493.     
  494.           =“org.springframework.transaction。    
  495.     
  496.                    →interceptor.TransactionInterceptor“>     
  497.     
  498.         <屬性名= “transactionManager的”  參考= “transactionManager的” />     
  499.     
  500.         <屬性名= “transactionAttributeSource”    
  501.     
  502.                   值=“onlyfun.caterpillar.UserDAO.insert * =     
  503.     
  504.                             →PROPAGATION_REQUIRED“/>     
  505.     
  506.     </豆>         
  507.     
  508.         
  509.     
  510.     <bean的ID = “userDAOProxy”     
  511.     
  512.           =“org.springframework.aop。    
  513.     
  514.                    →framework.ProxyFactoryBean“>     
  515.     
  516.         <屬性名= “proxyInterfaces” >     
  517.     
  518.             <目錄>    
  519.     
  520.                 <值> onlyfun.caterpillar.IUserDAO </值>    
  521.     
  522.             </表>    
  523.     
  524.         </物業>     
  525.     
  526.         <屬性名= “目標”  參考= “userDAO的” />     
  527.     
  528.         <屬性名= “interceptorNames” >    
  529.     
  530.             <目錄>    
  531.     
  532.                 <值> transactionInterceptor </值>     
  533.     
  534.             </表>    
  535.     
  536.         </物業>     
  537.     
  538.     </豆>       
  539.     
  540. </豆>    
  541.   
  542. 即使後來不再需要事務管理,也可以直接在Bean定義文件中修改配置,而不用修改程序重新進行編譯等動作。   
  543.   
  544. 聲明事務管理是利用彈簧AOP來達成的,所以執行以上的程序時,請記得您的Classpath設置中必須包括spring-aop.jar。   
  545.   
  546. 5.3   事務的屬性介紹   
  547. Spring使用AOP來完成聲明式的事務管理,因而聲明式事務是以方法爲邊界的,Spring的事務屬性(Transaction attribute)自然就在於描述事務應用至方法上的策略,在Spring中事務屬性分作以下的幾個參數:   
  548.   
  549. 升傳播行爲(傳播行爲)   
  550.   
  551. 傳播行爲定義了事務應用於方法上之邊界(Boundaries),它告知何時該開始一個新的事務,或何時事務該被暫停,或方法是否要在事務中進行。   
  552.   
  553. Spring定義了幾個傳播行爲,可以在TransactionDefinition的API文件說明上找到相對應的常數與說明,以下列出幾個:   
  554.   
  555. 5.1   事務傳播行爲說明   
  556.   
  557. 傳播行爲說明   
  558.   
  559. PROPAGATION_MANDATORY方法必須在一個現存的事務中進行,否則丟出異常   
  560.   
  561. PROPAGATION_NESTED在一個嵌入的事務中進行,如果不是,則同PROPAGATION_REQUIRED   
  562.   
  563. PROPAGATION_NEVER指出不應在事務中進行,如果有就丟出異常   
  564.   
  565. PROPAGATION_NOT_SUPPORTED指出不應在事務中進行,如果有就暫停現存的事務   
  566.   
  567. PROPAGATION_REQUIRED支持現在的事務,如果沒有就建立一個新的事務   
  568.   
  569. PROPAGATION_REQUIRES_NEW建立一個新的事務,如果現存一個事務就暫停它   
  570.   
  571. PROPAGATION_SUPPORTS支持現在的事務,如果沒有就以非事務的方式執行   
  572.   
  573.   
  574. 舉個例子來說,如果傳播行爲被聲明爲PROPAGATION_REQUIRED,則事務的邊界在開始第一個事務的方法呼叫及結束時,如果先前沒有事務被開始,則事務邊界即爲目前方法的執行前後。又如果傳播行爲被聲明爲PROPAGATION_REQUIRES_NEW,則事務的邊界即爲該方法執行的前後。   
  575.   
  576. 升隔離層級(隔離級別)   
  577.   
  578. 在一個應用程序中,可能有多個事務同時在進行,這些事務應當彼此之間互相不知道另一個事務的存在,好比現在整個應用程序就只有一個事務存在,由於事務彼此之間獨立,若讀取的是同一個數據的話,就容易發生問題,例如:   
  579.   
  580. ñ髒讀   
  581.   
  582. 某個事務已更新一份數據,另一個事務在此時讀取了同一份數據,由於某些原因,前一個Roll回來了操作,則後一個事務所讀取的數據就會是不正確的。   
  583.   
  584. n不重複讀   
  585.   
  586. 在一個事務的兩次查詢之中數據不一致,這可能是因爲兩次查詢過程中間插入了一個事務更新的原有的數據。   
  587.   
  588. ñ幻影讀   
  589.   
  590. 在一個事務的兩次查詢中數據筆數不一致,例如有一個事務查詢了幾列(Row)數據,而另一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。   
  591.   
  592. 爲了避免以上問題的方法之一,需要在某個事務進行過程中鎖定正在更新或查詢的數據字段,直到目前的事務完成,然而完全鎖定字段時,若另一個事務來查詢同一份數據就必須等待,直到前一個事務完成並解除鎖定爲止,因而會造成應用程序在查詢或更新數據時效率上的問題,而事實上根據需求的不同,並不用在事務進行時完全地鎖定數據,隔離層級可以讓您根據實際的需求,對數據的鎖定進行設置。   
  593.   
  594. Spring提供了幾種隔離層級設置,同類型的設置可以在TransactionDefinition的API文件說明上找到相對應的常數與說明,以下列出幾個:   
  595.   
  596. 5.2   事務隔離層級說明   
  597.   
  598.         隔離層級說明   
  599.   
  600. ISOLATION_DEFAULT使用底層數據庫預設的隔離層級   
  601.   
  602. ISOLATION_READ_COMMITTED允許事務讀取其他並行的事務已經送出(提交)的   
  603.                                  數據字段,可以防止髒讀問題   
  604.   
  605. ISOLATION_READ_UNCOMMITTED允許事務讀取其他並行的事務還沒送出的數據,會發   
  606.                                  生骯髒的,不可重複,幻影讀取等問題   
  607.   
  608.   
  609. 續表   
  610.   
  611.           隔離層級說明   
  612.   
  613. ISOLATION_REPEATABLE_READ要求多次讀取的數據必須相同,除非事務本身更新   
  614.                                    數據,可防止髒污,不可重複讀問題   
  615.   
  616. ISOLATION_SERIALIZABLE完整的隔離層級,可防止髒污,Nonrepeatabl   
  617.                                E,幻影讀取等問題,會鎖定對應的數據表   
  618.                                     格,因而有效率問題   
  619.   
  620.   
  621. 升只讀提示(只讀提示)   
  622.   
  623. 如果事務只進行讀取的動作,則可以利用底層數據庫在只讀操作時發生的一些最佳化動作,由於這個動作利用到數據庫在只讀的事務操作最佳化,因而必須在事務中才有效,也就是說要搭配傳播行爲PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED來設置。   
  624.   
  625. 升事務超時期間​​(交易超時時間)   
  626.   
  627. 有的事務操作可能延續很長一段的時間,事務本身可能關聯到數據表格的鎖定,因而長時間的事務操作會有效率上的問題,對於過長的事務操作,您要考慮Roll回事務並要求重新操作,而不是無限時的等待事務完成。   
  628.   
  629. 您可以設置事務超時期間,計時是從事務開始時,所以這個設置必須搭配傳播行爲PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED來設置。   
  630.   
  631. 5.3   TransactionAttributeSource,TransactionAttribute   
  632. 在TransactionProxyFactoryBean的上有setTransactionAttributeSource()與setTransaction屬性()方法,它們是用來設置事務屬性的策略實例。   
  633.   
  634. org.springframework.transaction.interceptor.TransactionAttributeSource接口上有一個getTransactionAttribute()方法,您可以根據傳遞給它的Method實例與Class實例,決定該回傳一個什麼內容的org.springframework.transaction. interceptor.TransactionAttribute實例,一個最簡單的TransactionAttributeSource實現是org.springframework.transaction.interceptor.MatchAlwaysTransaction- AttributeSource,對於每一個方法執行都會應用事務,它回傳的TransactionAttribute實例的默認傳播行爲是PROPAGATION_REQUIRED,隔離層級爲ISOLATION_DEFAULE。   
  635.   
  636. 一個應用的例子如下所示:   
  637.   
  638. ...   
  639.   
  640. 【JAVA]鑑於plaincopy  
  641. <bean的ID = “transactionAttributeSource”    
  642.     
  643.       =“org.springframework.transaction.interceptor。    
  644.     
  645.             →的MatchAlwaysTransactionAttributeSource“/>    
  646.     
  647. <bean的ID = “userDAOProxy”    
  648.     
  649.       =“org.springframework.transaction。    
  650.     
  651.             →interceptor.TransactionProxyFactoryBean“>    
  652.     
  653.     <屬性名= “proxyInterfaces” >    
  654.     
  655.         <目錄>    
  656.     
  657.             <值> onlyfun.caterpillar.IUserDAO </值>    
  658.     
  659.         </表>    
  660.     
  661.     </物業>    
  662.     
  663.     <屬性名= “目標”  參考= “userDAO的” />    
  664.     
  665.     <屬性名= “transactionManager的”  參考= “transactionManager的” />    
  666.     
  667.     <屬性名= “transactionAttributeSource”    
  668.     
  669.               REF = “transactionAttributeSource” />    
  670.     
  671. </豆>    
  672. ...   
  673.   
  674. 您可以使用org.springframework.transaction.interceptor.DefaultTransaction-屬性,並設置自己的事務策略,之後設置給TransactionAttributeSource,例如:   
  675.   
  676. ...   
  677.   
  678. 【JAVA]鑑於plaincopy  
  679. <bean的ID = “myTransactionAttribute”    
  680.     
  681.       =“org.springframework.transaction。    
  682.     
  683.          →interceptor.DefaultTransactionAttribute“>    
  684.     
  685.     <屬性名= “propagationBehaviorName”    
  686.     
  687.               值= “PROPAGATION_REQUIRES_NEW” />    
  688.     
  689.     <屬性名= “isolationLevelName”    
  690.     
  691.               值= “ISOLATION_REPEATABLE_READ” />    
  692.     
  693. </豆>    
  694.     
  695. <bean的ID = “transactionAttributeSource”    
  696.     
  697.       =“org.springframework.transaction。    
  698.     
  699.       →interceptor.MatchAlwaysTransactionAttributeSource“>    
  700.     
  701.     <屬性名= “transactionAttribute”    
  702.     
  703.               REF = “myTransactionAttribute” />    
  704.     
  705. </豆>    
  706.     
  707. <bean的ID = “userDAOProxy”    
  708.     
  709.       =“org.springframework.transaction。    
  710.     
  711.             →interceptor.TransactionProxyFactoryBean“>    
  712.     
  713.     <屬性名= “proxyInterfaces” >    
  714.     
  715.         <目錄>    
  716.     
  717.             <值> onlyfun.caterpillar.IUserDAO </值>    
  718.     
  719.         </表>    
  720.     
  721.     </物業>    
  722.     
  723.     <屬性名= “目標”  參考= “userDAO的” />    
  724.     
  725.     <屬性名= “transactionManager的”  參考= “transactionManager的” />    
  726.     
  727.     <屬性名= “transactionAttributeSource”    
  728.     
  729.               REF = “transactionAttributeSource” />    
  730.     
  731. </豆>    
  732.   
  733. ...   
  734.   
  735. 可以使用org.springframework.transaction.interceptor.NameMatchTransaction- AttributeSource來指定某些方法要應用事務,以及要應用的事務策略,例如:   
  736.   
  737. ...   
  738.   
  739. 【JAVA]鑑於plaincopy  
  740. <bean的ID = “transactionAttributeSource”    
  741.     
  742.       =“org.springframework.transaction。    
  743.     
  744.         →interceptor.NameMatchTransactionAttributeSource“>    
  745.     
  746.     <屬性名= “屬性” >    
  747.     
  748.         <道具>    
  749.     
  750.             <支撐鍵= “插入*” > PROPAGATION_REQUIRES_NEW </道具>    
  751.     
  752.         </道具>    
  753.     
  754.     </物業>    
  755.     
  756. </豆>    
  757.     
  758. <bean的ID = “userDAOProxy”    
  759.     
  760.       =“org.springframework.transaction。    
  761.     
  762.           →interceptor.TransactionProxyFactoryBean“>    
  763.     
  764.     <屬性名= “proxyInterfaces” >    
  765.     
  766.         <目錄>    
  767.     
  768.             <值> onlyfun.caterpillar.IUserDAO </值>    
  769.     
  770.         </表>    
  771.     
  772.     </物業>    
  773.     
  774.     <屬性名= “目標”  參考= “userDAO的” />    
  775.     
  776.     <屬性名= “transactionManager的”  參考= “transactionManager的” />    
  777.     
  778.     <屬性名= “transactionAttributeSource”    
  779.     
  780.               REF = “transactionAttributeSource” />    
  781.     
  782. </豆>    
  783.   
  784. ...   
  785.   
  786. 在NameMatchTransactionAttributeSource的  "properties" 屬性上,可以指定方法名稱與事務策略,方法名稱的指定可以指定全名,也可以使用Wildcard來指定,例如上面的指定中,只要方法名稱以insert爲開頭的都會應用相對應的事務策略。   
  787.   
  788. 在指定事務策略時,指定的格式如下:   
  789.   
  790. 傳播行爲,隔離層級,只讀,+異常 - 異常   
  791.   
  792. 除了傳播行爲一定要設置之外,其他都可選擇性的設置,中間以逗號區隔,例如:   
  793.   
  794. PROPAGATION_REQUIRED,只讀,-MyCheckedException   
  795.   
  796. MyCheckedException前面加上  "-"  時,表示發生指定異常時撤消操作,如果前面加上  "+" ,表示發生異常時立即提交。   
  797.   
  798. 在比較簡單的設置中,可以僅設置TransactionProxyFactoryBean,並在它的  "transactionAttributes"  屬性上直接設置要應用事務的方法及事務策略,例如:   
  799.   
  800. ...   
  801.   
  802. 【JAVA]鑑於plaincopy  
  803. <bean的ID = “userDAOProxy”    
  804.     
  805.       =“org.springframework.transaction。    
  806.     
  807.           →interceptor.TransactionProxyFactoryBean“>    
  808.     
  809.     <屬性名= “proxyInterfaces” >    
  810.     
  811.         <目錄>    
  812.     
  813.             <值> onlyfun.caterpillar.IUserDAO </值>    
  814.     
  815.         </表>    
  816.     
  817.     </物業>    
  818.     
  819.     <屬性名= “目標”  參考= “userDAO的” />    
  820.     
  821.     <屬性名= “transactionManager的”  參考= “transactionManager的” />    
  822.     
  823.     <屬性名= “transactionAttributes” >    
  824.     
  825.         <道具>    
  826.     
  827.             <支撐鍵= “插入*” > PROPAGATION_REQUIRED </道具>    
  828.     
  829.         </道具>    
  830.     
  831.     </物業>    
  832.     
  833. </豆>    
  834.   
  835. ...   
  836.   
  837. 甚至也可以直接指定TransactionInterceptor,以獲得更多的控制,例如:   
  838.   
  839. ...   
  840.   
  841. 【JAVA]鑑於plaincopy  
  842. <bean的ID = “transactionInterceptor”    
  843.     
  844.       =“org.springframework.transaction。    
  845.     
  846.               →interceptor.TransactionInterceptor“>    
  847.     
  848.     <屬性名= “transactionManager的” >    
  849.     
  850.               REF = “transactionManager的” />    
  851.     
  852.     <屬性名= “transactionAttributeSource”    
  853.     
  854.      值= “onlyfun.caterpillar.UserDAO.insert * =→PROPAGATION_REQUIRED” />    
  855.     
  856. </豆>    
  857.     
  858. <bean的ID = “userDAOProxy”     
  859.     
  860.       =“org.springframework.aop。    
  861.     
  862.           →framework.ProxyFactoryBean“>    
  863.     
  864.     <屬性名= “proxyInterfaces” >    
  865.     
  866.         <目錄>    
  867.     
  868.             <值> onlyfun.caterpillar.IUserDAO </值>    
  869.     
  870.         </表>    
  871.     
  872.     </物業>    
  873.     
  874.     <屬性名= “目標”  參考= “userDAO的” />    
  875.     
  876.     <屬性名= “interceptorNames”  值= “transactionInterceptor” />    
  877.     
  878. </豆>    
  879.   
  880. ...   
  881.   
  882. 選擇哪一種設置方式是需求的問題,您可以嘗試在DeclarativeTransactionDemo項目的Bean定義文件上設置以上所介紹的方式,基於篇幅的限制,以上僅列出部分的設置內容。   
  883.   
  884. 5.3   春季  2.0 聲明式事務管理:基於XML Schmea   
  885. 在Spring  2.0 中要設置聲明式事務管理,可以依賴於Spring  2.0 的<aop>與<tx>標籤,因而要記得加入相關的名稱空間聲明:   
  886.   
  887. 【JAVA]鑑於plaincopy  
  888. <?XML版本= “1.0”  編碼= “UTF-8” ?>     
  889.     
  890. <豆的xmlns = “http://www.springframework.org/schema/beans”    
  891.     
  892.   XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”    
  893.     
  894.   的xmlns:AOP = “http://www.springframework.org/schema/aop”    
  895.     
  896.   的xmlns:TX = “http://www.springframework.org/schema/tx”    
  897.     
  898.   XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans     
  899.     
  900.   HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd    
  901.     
  902.   HTTP://www.springframework.org/schema/aop     
  903.     
  904.   HTTP://www.springframework.org/schema/aop/spring-aop-2.0.xsd    
  905.     
  906.   HTTP://www.springframework.org/schema/tx     
  907.     
  908.   HTTP://www.springframework.org/schema/tx/spring-tx-2.0.xsd“>    
  909.     
  910.     ...     
  911.     
  912. </豆>    
  913.   
  914. 事務是系統層面的服務,也就是一個Aspect,其實具體來說就是一個Advice,您可以使用<tx:advice>標籤來提供這個Advice,它需要設置一個TransactionManager,並在當中使用<tx:attributes>來設置事務相關屬性。   
  915.   
  916. 可以將先前的DeclarativeTransactionDemo項目改寫,修改其beans-config.xml爲使用<aop>與<tx>標籤的方式:   
  917.   
  918. DeclarativeTransactionDemo2豆-config.xml中   
  919.   
  920. 【JAVA]鑑於plaincopy  
  921. <?XML版本= “1.0”  編碼= “UTF-8” ?>     
  922.     
  923. <豆的xmlns = “http://www.springframework.org/schema/beans”    
  924.     
  925.   XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”    
  926.     
  927.   的xmlns:AOP = “http://www.springframework.org/schema/aop”    
  928.     
  929.   的xmlns:TX = “http://www.springframework.org/schema/tx”    
  930.     
  931.   XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans     
  932.     
  933.   HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd    
  934.     
  935.   HTTP://www.springframework.org/schema/aop     
  936.     
  937.   HTTP://www.springframework.org/schema/aop/spring-aop-2.0.xsd    
  938.     
  939.   HTTP://www.springframework.org/schema/tx     
  940.     
  941.   HTTP://www.springframework.org/schema/tx/spring-tx-2.0.xsd“>    
  942.     
  943.       
  944.     
  945.     <bean的ID = “數據源”     
  946.     
  947.           =“org.springframework.jdbc。    
  948.     
  949.                    →datasource.DriverManagerDataSource“    
  950.     
  951.           破壞法= “關閉” >      
  952.     
  953.         <屬性名= “driverClassName”     
  954.     
  955.                   值= “com.mysql.jdbc.Driver” />     
  956.     
  957.         <屬性名= “URL”    
  958.     
  959.                   值= “的jdbc:mysql的://本地主機:3306 /演示” />    
  960.     
  961.         <屬性名= “用戶名”  值= “毛毛蟲” />     
  962.     
  963.         <屬性名= “密碼”  值= “123456” />     
  964.     
  965.     </豆>     
  966.     
  967.         
  968.     
  969.     <bean的ID = “transactionManager的”     
  970.     
  971.           =“org.springframework.jdbc。    
  972.     
  973.                    →datasource.DataSourceTransactionManager“>     
  974.     
  975.         <屬性名= “數據源”  參考= “數據源” />     
  976.     
  977.     </豆>     
  978.     
  979.         
  980.     
  981.     <bean的ID = “userDAO的”     
  982.     
  983.           “onlyfun.caterpillar.UserDAO” >    
  984.     
  985.         <屬性名= “數據源”  參考= “數據源” />    
  986.     
  987.     </豆>    
  988.     
  989.         
  990.     
  991.     <TX:建議ID = “txAdvice”     
  992.     
  993.                交易經理= “transactionManager的” >    
  994.     
  995.         <TX:屬性>    
  996.     
  997.             <TX:方法名= “插入*”  的傳播= “要求” />    
  998.     
  999.             <TX:方法名= “發現*”  只讀= “真” />    
  1000.     
  1001.         </ TX:屬性>    
  1002.     
  1003.     </ TX:建議>    
  1004.     
  1005.       
  1006.     
  1007.     <AOP:配置>    
  1008.     
  1009.         <AOP:切入點ID = “userDAOPointcut”     
  1010.     
  1011.       表達式= “執行(* onlyfun.caterpillar.IUserDAO。*(..))” />    
  1012.     
  1013.         <AOP:顧問諮詢-REF = “txAdvice”     
  1014.     
  1015.                      切入點-REF = “userDAOPointcut” />    
  1016.     
  1017.     </ AOP:配置>    
  1018.     
  1019. </豆>    
  1020.   
  1021. 注意到<tx:method>中的屬性設置,對於傳播行爲、隔離層級、只讀、超時、異常時撤回或提交,都有對應的"propagation" "isolation" "timeout" "read-only" "rollback-for" "no-rollback-for" 屬性可以設置,若不設置,"propagation" 屬性默認是"REQUIRE" "isolation" 屬性默認是"DEFAULT" "timeout" 屬性默認是"-1" (單位是秒)、"read-only" 屬性默認是"false" 。   
  1022.   
  1023. 與先前介紹春季  2.0 基於XML Schema的AOP設置相同,由於不再於設置文件中設置代理對象,所以直接取得"userDAO" 實例進行操作即可。   
  1024.   
  1025. 5.3   春天  2.0 聲明式事務管理:基於註解   
  1026. 聲明式事務管理在Spring  2.0 中,也支持使用Annotation的標示方式,方法是使用@Transactional 來標示,例如可以將DeclarativeTransactionDemo項目的UserDAO改寫,在上頭直接標示@Transactional ,並設置相關屬性:   
  1027.   
  1028. DeclarativeTransactionDemo3 UserDAO.java   
  1029.   
  1030. 【JAVA]鑑於plaincopy  
  1031. 包裝 onlyfun.caterpillar;    
  1032.     
  1033. 進口 java.util.Iterator的;    
  1034.     
  1035. 進口 的java.util.List;    
  1036.     
  1037. 進口 的java.util.Map;    
  1038.     
  1039. 進口 javax.sql.DataSource的;    
  1040.     
  1041. 進口 org.springframework.jdbc.core.JdbcTemplate;    
  1042.     
  1043. 進口 org.springframework.transaction.annotation.Propagation;    
  1044.     
  1045. 進口 org.springframework.transaction.annotation.Transactional;    
  1046.     
  1047. 公共  的UserDAO  實現 IUserDAO {    
  1048.     
  1049.     私人 的JdbcTemplate JdbcTemplate的;     
  1050.     
  1051.     公共 無效 的setDataSource(數據源數據源){    
  1052.     
  1053.         的JdbcTemplate =   的JdbcTemplate(數據源);    
  1054.     
  1055.     }    
  1056.     
  1057.     @Transactional (傳播= Propagation.REQUIRED)    
  1058.     
  1059.     公共 無效 插入(用戶用戶){    
  1060.     
  1061.        字符串名稱= user.getName();    
  1062.     
  1063.        INT  年齡= user.getAge()的intValue()。    
  1064.     
  1065.            
  1066.     
  1067.        jdbcTemplate.update(“INSERT INTO的用戶(姓名,年齡)”     
  1068.     
  1069.                +  “VALUES('”  +名稱+  “',”  +年齡+  “)” );    
  1070.     
  1071.     }    
  1072.     
  1073.         
  1074.     
  1075.     @Transactional (只讀= )    
  1076.     
  1077.     公衆 用戶發現(整數ID){    
  1078.     
  1079.         列表行= jdbcTemplate.queryForList(    
  1080.     
  1081.           “SELECT * FROM WHERE用戶ID =”  + id.intValue());    
  1082.     
  1083.             
  1084.     
  1085.         迭代它= rows.iterator();    
  1086.     
  1087.         如果(it.hasNext()){    
  1088.     
  1089.             地圖中userMap =(圖)it.next();    
  1090.     
  1091.             整數I =  新的 整數(userMap.get(“ID” )的ToString());    
  1092.     
  1093.             字符串名稱= userMap.get( “ 名” )的ToString();    
  1094.     
  1095.             整數年齡=     
  1096.     
  1097.                   新的 整數(userMap.get( “ 時代” )的ToString());    
  1098.     
  1099.             用戶的用戶=   用戶();    
  1100.     
  1101.             user.setId(ⅰ);    
  1102.     
  1103.             user.setName(名);    
  1104.     
  1105.             user.setAge(年齡);    
  1106.     
  1107.                 
  1108.     
  1109.             返回 用戶;    
  1110.     
  1111.         }    
  1112.     
  1113.         返回 空值;    
  1114.     
  1115.     }    
  1116.     
  1117. }    
  1118.   
  1119. 在使用@Transactional 時,相關的屬性設置爲"propagation" "isolation" "readOnly" "timeout" "rollbackFor" "noRollbackFor" 等,而在beans-config.xml中,則要使用<tx:annotation-driven>標籤,並指定TransactionManager,例如:   
  1120.   
  1121. DeclarativeTransactionDemo3豆-config.xml中   
  1122.   
  1123. 【JAVA]鑑於plaincopy  
  1124. <?XML版本= “1.0”  編碼= “UTF-8” ?>     
  1125.     
  1126. <豆的xmlns = “http://www.springframework.org/schema/beans”    
  1127.     
  1128.   XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”    
  1129.     
  1130.   的xmlns:TX = “http://www.springframework.org/schema/tx”    
  1131.     
  1132.   XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans     
  1133.     
  1134.   HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd    
  1135.     
  1136.   HTTP://www.springframework.org/schema/tx     
  1137.     
  1138.   HTTP://www.springframework.org/schema/tx/spring-tx-2.0.xsd“>    
  1139.     
  1140.       
  1141.     
  1142.     <bean的ID = “數據源”     
  1143.     
  1144.           =“org.springframework.jdbc。    
  1145.     
  1146.                    →datasource.DriverManagerDataSource“    
  1147.     
  1148.           破壞法= “關閉” >      
  1149.     
  1150.         <屬性名= “driverClassName”     
  1151.     
  1152.                   值= “com.mysql.jdbc.Driver” />     
  1153.     
  1154.         <屬性名= “URL”    
  1155.     
  1156.                   值= “的jdbc:mysql的://本地主機:3306 /演示” />    
  1157.     
  1158.         <屬性名= “用戶名”  值= “毛毛蟲” />     
  1159.     
  1160.         <屬性名= “密碼”  值= “123456” />     
  1161.     
  1162.     </豆>     
  1163.     
  1164.         
  1165.     
  1166.     <bean的ID = “transactionManager的”     
  1167.     
  1168.           =“org.springframework.jdbc。    
  1169.     
  1170.                    →datasource.DataSourceTransactionManager“>     
  1171.     
  1172.         <屬性名= “數據源”  參考= “數據源” />     
  1173.     
  1174.     </豆>     
  1175.     
  1176.         
  1177.     
  1178.     <bean的ID = “userDAO的”     
  1179.     
  1180.           “onlyfun.caterpillar.UserDAO” >    
  1181.     
  1182.         <屬性名= “數據源”  參考= “數據源” />    
  1183.     
  1184.     </豆>    
  1185.     
  1186.         
  1187.     
  1188.     <TX:註解驅動的事務管理器= “transactionManager的” />    
  1189.     
  1190. </豆>    
  1191.   
  1192. 同樣的,由於不再於設置文件中設置代理對象,所以直接取得"userDAO" 實例進行操作即可。   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章