• 春天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" 实例进行操作即可。   
  • 相关阅读:
    Windows 7 语音识别和屏幕录像
    用户体验研究乱谈后台导航
    安装VS2010
    lucene.net搜索索引详解
    网站秒杀那点破事
    初次给鼠标手术
    网站页面回车和鼠标焦点
    利用C语言的部分初始化特性进行字符串的全部初始化。
    QoS的各个方面
    指针和数组错用的问题汇总
  • 原文地址:https://www.cnblogs.com/baiduligang/p/4246989.html
Copyright © 2020-2023  润新知