春天JDBC事务管理

来源:互联网 发布:农村淘宝的运营模式 编辑:程序博客网 时间:2024/05/21 00:56
  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" 实例进行操作即可。   
0 0
原创粉丝点击