春天JDBC事务管理

时间:2023-12-22 23:18:02
  1. JDBC事务管理
  2. 春天提供编程式的事务管理(编程式事务管理)与声明式的事务管理(声明式事务management),为不同的事务实现提供了一致的编程模型,这节以JDBC事务为例,介绍Spring的事务管理。
  3. 5.3 。1   春天对事务的支持
  4. 事务是一组原子(Atomic)操作的工作单元,以数据库存取的实例来说,就是一组SQL指令,这一组SQL指令必须全部执行成功,若因为某个原因未全部执行成功(例如其中一行SQL有错误),则先前所有执行过的SQL指令都会被撤消。
  5. 举个简单的例子,一个客户从A银行转账至B银行,要作的动作为从A银行的账户扣款、在B银行的账户加上转账的金额,两个动作必须成功,如果有一个动作失败,则此次转账失败。
  6. 事务还必须保持所参与资源的一致性(Consistent),例如在银行账户的例子中,两个账户的转账金额,B账户取款的金额不能大于A账户的存款金额。每个事务彼此之间必须是隔离的(Isolated),例如在A账户中可能有两笔事务,同时进行存款与提款的动作,两个事务基本上不需意识到彼此的存在。事务还必须是可持续的(Durable),在某一笔事务之后,这笔事务必须是被记录下来的。
  7. 在这里将介绍JDBC如何使用事务管理。首先来看看事务的原子性实现,在JDBC中,可以操作Connection的setAutoCommit()方法,给定false 参数,在下达一连串的SQL语句后,自行执行Connection的commit()来送出变更,如果中间发生错误,则执行rollback()来撤消所有的执行,例如:
  8. 在Spring中对JDBC的事务管理加以封装,Spring事务管理的抽象关键在于org.springframework.transaction.PlatformTransactionManager接口的实现:
  9. ...
  10. 【JAVA]鉴于plaincopy
  11. 公共 接口 的PlatformTransactionManager {
  12. 的TransactionStatus getTransaction(TransactionDefinition的
  13. 定义)   抛出 TransactionException;
  14. 无效 提交(TransactionStatus对象的状态)
  15. 抛出 TransactionException;
  16. 无效 回滚(TransactionStatus对象的状态)
  17. 抛出 TransactionException;
  18. }
  19. PlatformTransactionManager接口有许多具体的事务实现类,例如DataSourceTransactionManager、HibernateTransactionManager、JdoTransaction- Manager、JtaTransactionManager等,通过依赖于PlatformTransactionManager接口及各种的技术实现,Spring在事务管理上可以让开发人员使用一致的编程模型,即使所使用的是不同的事务管理技术。
  20. TransactionException是未选中Exception。事务的失败通常都是致命的错误,Spring不强迫您一定要处理,而是让您自行选择是否要捕捉异常。
  21. getTransaction()级),传播行为(传播
  22. ...
  23. 【JAVA]鉴于plaincopy
  24. 公共 接口 的TransactionStatus {
  25. 布尔 isNewTransaction();
  26. 无效 的setRollbackOnly();
  27. 布尔 isRollbackOnly();
  28. }
  29. 春天提供编程式的事务管理(编程式事务管理)与声明式的事务管理(声明式事务管理):
  30. 升编程式的事务管理
  31. 编程式的事务管理可以清楚地控制事务的边界,也就是让您自行实现事务开始时间、撤消操作的时机、结束时间等,可以实现细粒度的事务控制。
  32. 升声明式的事务管理
  33. 然而多数的情况下,事务并不需要细粒度的控制,而是采用声明式的事务管理,好处是Spring事务管理的相关API可以不用介入程序之中,从对象的角度来看,它并不知道自己正被纳入事务管理之中,在不需要事务管理的时候,只要在设置文件上修改一下设置,即可移去事务管理服务。
  34. 5.3 。2   JDBC编程事务管理
  35. 春天提供两种方式实现编程式的事务管理,一是直接使用PlatformTransaction-经理实现,二是使用org.springframework.transaction.support.Transaction-模板。
  36. 先来看看如何使用PlatformTransactionManager,在这里使用它的实现类DataSourceTransactionManager,可以改写一下之前5.2 . 1 节中的JdbcTemplateDemo项目,让它具有事务管理功能,修改一下UserDAO类的insert()方法来作示范:
  37. ProgrammaticTransactionDemo UserDAO.java
  38. 【JAVA]鉴于plaincopy
  39. 包装 onlyfun.caterpillar;
  40. 进口 java.util.Iterator的;
  41. 进口 的java.util.List;
  42. 进口 的java.util.Map;
  43. 进口 javax.sql.DataSource的;
  44. 进口 org.springframework.dao.DataAccessException;
  45. 进口 org.springframework.jdbc.core.JdbcTemplate;
  46. 进口 org.springframework.jdbc。
  47. datasource.DataSourceTransactionManager;
  48. 进口 org.springframework.transaction.TransactionDefinition;
  49. 进口 org.springframework.transaction.TransactionStatus;
  50. 进口 org.springframework.transaction。
  51. support.DefaultTransactionDefinition;
  52. 公共 类 的UserDAO  实现 IUserDAO
    {
  53. 私人 的DataSourceTransactionManager transactionManager的;
  54. 私人 DefaultTransactionDefinition DEF;
  55. 私人 的JdbcTemplate JdbcTemplate的;
  56. 公共 无效 的setDataSource(数据源数据源){
  57. 的JdbcTemplate =  新 的JdbcTemplate(数据源);
  58. transactionManager的=
  59. 新 的DataSourceTransactionManager(数据源);
  60. //建立事务的定义
  61. 高清=  新 DefaultTransactionDefinition();
  62. def.setPropagationBehavior(
  63. TransactionDefinition.PROPAGATION_REQUIRED);
  64. }
  65. 公共 无效 插入(用户用户){
  66. 字符串名称= user.getName();
  67. INT  年龄= user.getAge()的intValue()。
  68. TransactionStatus对象状态=
  69. transactionManager.getTransaction(DEF);
  70. 尝试 {
  71. jdbcTemplate.update(“INSERT INTO的用户(姓名,年龄)”
  72. +  “VALUES('”  +名称+  “',”  +年龄+  “)” );
  73. //下面的SQL有错误,用以测试事务
  74. jdbcTemplate.update(“INSER INTO用户(姓名,年龄)”
  75. +  “VALUES('”  +名称+  “',”  +年龄+  “)” );
  76. }
  77. 抓(DataAccessException的E){
  78. transactionManager.rollback(状态);
  79. 扔 é;
  80. }
  81. transactionManager.commit(状态);
  82. }
  83. 公众 用户发现(整数ID){
  84. 列表行= jdbcTemplate.queryForList(
  85. “SELECT * FROM WHERE用户ID =”  + id.intValue());
  86. 迭代它= rows.iterator();
  87. 如果(it.hasNext()){
  88. 地图中userMap =(图)it.next();
  89. 整数I =  新的 整数(
  90. userMap.get(“ID” )的ToString());
  91. 字符串名称= userMap.get( “ 名” )的ToString();
  92. 整数年龄=  新的 整数(
  93. userMap.get( “ 时代” )的ToString());
  94. 用户的用户=  新 用户();
  95. user.setId(ⅰ);
  96. user.setName(名);
  97. user.setAge(年龄);
  98. 返回 用户;
  99. }
  100. 返回 空值;
  101. }
  102. }
  103. 在insert()方法中使用了DataSourceTransactionManager来进行事务管理,如果发生了异常,则catch 区块中会进行事务的Rollback,在insert()方法中故意写入错误的SQL(注意INSERT方法少写了一个T),因此实际上数据并不会被储存至数据库中。
  104. 要使用MySQL数据库进行事务处理,必须建立支持事务的表格类型,例如InnoDB的表格类型,这里用来建立表格的SQL如下所示:
  105. 【JAVA]鉴于plaincopy
  106. CREATE TABLE的用户(
  107. ID INT(11 )NOT NULL AUTO_INCREMENT PRIMARY KEY,
  108. 命名VARCHAR(100 )NOT NULL  默认 ' ,
  109. 年龄INT
  110. )TYPE = InnoDB的;
  111. 另一个实现编程式事务管理的方法是使用TransactionTemplate,它需要一个TransactionManager实例,如下所示:
  112. ...
  113. 【JAVA]鉴于plaincopy
  114. TransactionTemplate的TransactionTemplate的=
  115. 新 TransactionTemplate的(transactionManager的);
  116. ...
  117. transactionTemplate.execute(新 TransactionCallback(){
  118. 公共 对象doInTransaction(TransactionStatus对象的状态){
  119. 返回 jdbcTemplate.update(“INSERT INTO的用户(姓名,年龄)”
  120. +  “VALUES('”  +名称+  “',”  +年龄+  “)” );
  121. }
  122. });
  123. 如果发生了异常,则会进行Rollback,否则提交事务,如果没有回传值,则也可以使用TransactionCallbackWithoutResult:
  124. ...
  125. 【JAVA]鉴于plaincopy
  126. transactionTemplate.execute(
  127. 新 TransactionCallbackWithoutResult(){
  128. 公共 无效 doInTransactionWithoutResult(
  129. TransactionStatus对象的状态){
  130. 。...
  131. }
  132. });
  133. 5.3 。3   JDBC声明事务管理
  134. Spring声明式的事务管理依赖它的AOP框架来完成。使用声明事务管理的好处是,事务管理不能侵入您所开发的组件,具体来说,DAO对象不会意识到正在事务管理之中,事实上也应当如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策略的话,也只需要在定义文件中重新配置。
  135. 举个例子来说,可以将5.2 . 1 节中的JdbcTemplateDemo项目修改一下,在不修改UserDAO类的情况下,可以为它加入事务管理的服务,一个简单的方法是使用TransactionProxyFactoryBean,指定要介入的事务管理对象及其方法,这需要在定义文件中修改,如下所示:
  136. DeclarativeTransactionDemo豆-config.xml中
  137. 【JAVA]鉴于plaincopy
  138. <?XML版本= “1.0”  编码= “UTF-8” ?>
  139. <豆的xmlns = “http://www.springframework.org/schema/beans”
  140. XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”
  141. XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans
  142. HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd“>
  143. <bean的ID = “数据源”
  144. 类=“org.springframework.jdbc。
  145. →datasource.DriverManagerDataSource“
  146. 破坏法= “关闭” >
  147. <属性名= “driverClassName”
  148. 值= “com.mysql.jdbc.Driver” />
  149. <属性名= “URL”
  150. 值= “的jdbc:mysql的://本地主机:3306 /演示” />
  151. <属性名= “用户名”  值= “毛毛虫” />
  152. <属性名= “密码”  值= “123456” />
  153. </豆>
  154. <bean的ID = “transactionManager的”
  155. 类=“org.springframework.jdbc。
  156. →datasource.DataSourceTransactionManager“>
  157. <属性名= “数据源”  参考= “数据源” />
  158. </豆>
  159. <bean的ID = “userDAO的”
  160. 类= “onlyfun.caterpillar.UserDAO” >
  161. <属性名= “数据源”  参考= “数据源” />
  162. </豆>
  163. <bean的ID = “userDAOProxy”
  164. 类=“org.springframework.transaction。
  165. →interceptor.TransactionProxyFactoryBean“>
  166. <属性名= “proxyInterfaces” >
  167. <目录>
  168. <值> onlyfun.caterpillar.IUserDAO </值>
  169. </表>
  170. </物业>
  171. <属性名= “目标”  参考= “userDAO的” />
  172. <属性名= “transactionManager的”
  173. REF = “transactionManager的” />
  174. <属性名= “transactionAttributes” >
  175. <道具>
  176. <支撑键= “插入*” > PROPAGATION_REQUIRED </道具>
  177. </道具>
  178. </物业>
  179. </豆>
  180. </豆>
  181. TransactionProxyFactoryBean需要一个TransactionManager,由于这里使用的是JDBC,所以使用DataSourceTransactionManager,TransactionProxyFactoryBean是个代理对象,"target"  属性指定要代理的对象,事务管理会自动介入指定的方法前后,这里使用  "transactionAttributes"  属性指定,"insert*"  表示指定方法名称以insert开头的都要纳入事务管理,您也可以指定方法全名,如果在方法执行过程中发生错误,则所有先前的操作自动撤回,否则正常提交。
  182. 在"insert*"  等方法上指定了  "PROPAGATION_REQUIRED" ,表示在目前的事务中执行操作,如果事务不存在就建立一个新的,相关的常数意义都可以在API文件的TransactionDefinition接口中找到。您可以加上多个事务定义,中间使用逗号  ","  区隔,例如可以加上只读,或者是指定某个异常发生时撤回操作:
  183. PROPAGATION_REQUIRED,只读,-MyCheckedException
  184. MyCheckedException前面加上  "-"  时,表示发生指定异常时撤消操作,如果前面加上  "+" ,表示发生异常时立即提交。
  185. 由于"userDAO" 被"userDAOProxy" 代理了,所以要做的是取得"userDAOProxy" ,而不是"userDAO" ,例如:
  186. DeclarativeTransactionDemo SpringDAODemo.java
  187. 【JAVA]鉴于plaincopy
  188. 包装 onlyfun.caterpillar;
  189. 进口 org.springframework.context.ApplicationContext;
  190. 进口 org.springframework.context。
  191. support.ClassPathXmlApplicationContext;
  192. 公共 类 SpringDAODemo {
  193. 公共 静态 无效 的主要(字串[]
    args){
  194. ApplicationContext的背景下=
  195. 新 的ClassPathXmlApplicationContext(
  196. “豆-config.xml文件” );
  197. 用户的用户=  新 用户();
  198. user.setName( “ 毛毛虫” );
  199. user.setAge(新的 整数(30 ));
  200. IUserDAO userDAO的=
  201. (IUserDAO)context.getBean(“userDAOProxy” );
  202. userDAO.insert(用户);
  203. 用户= userDAO.find(新 整型(1 ));
  204. 的System.out.println( “ 名”  + user.getName());
  205. }
  206. }
  207. 您也可以设置不同的TransactionInterceptor来得到更多的管理细节,例如:
  208. 【JAVA]鉴于plaincopy
  209. <?XML版本= “1.0”  编码= “UTF-8” ?>
  210. <豆的xmlns = “http://www.springframework.org/schema/beans”
  211. XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”
  212. XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans
  213. HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd“>
  214. <bean的ID = “数据源”
  215. 类=“org.springframework.jdbc。
  216. →datasource.DriverManagerDataSource“
  217. 破坏法= “关闭” >
  218. <属性名= “driverClassName”
  219. 值= “com.mysql.jdbc.Driver” />
  220. <属性名= “URL”
  221. 值= “的jdbc:mysql的://本地主机:3306 /演示” />
  222. <属性名= “用户名”  值= “毛毛虫” />
  223. <属性名= “密码”  值= “123456” />
  224. </豆>
  225. <bean的ID = “transactionManager的”
  226. 类=“org.springframework.jdbc。
  227. →datasource.DataSourceTransactionManager“>
  228. <属性名= “数据源”  参考= “数据源” />
  229. </豆>
  230. <bean的ID = “userDAO的”
  231. 类= “onlyfun.caterpillar.UserDAO” >
  232. <属性名= “数据源”  参考= “数据源” />
  233. </豆>
  234. <bean的ID = “transactionInterceptor”
  235. 类=“org.springframework.transaction。
  236. →interceptor.TransactionInterceptor“>
  237. <属性名= “transactionManager的”  参考= “transactionManager的” />
  238. <属性名= “transactionAttributeSource”
  239. 值=“onlyfun.caterpillar.UserDAO.insert * =
  240. →PROPAGATION_REQUIRED“/>
  241. </豆>
  242. <bean的ID = “userDAOProxy”
  243. 类=“org.springframework.aop。
  244. →framework.ProxyFactoryBean“>
  245. <属性名= “proxyInterfaces” >
  246. <目录>
  247. <值> onlyfun.caterpillar.IUserDAO </值>
  248. </表>
  249. </物业>
  250. <属性名= “目标”  参考= “userDAO的” />
  251. <属性名= “interceptorNames” >
  252. <目录>
  253. <值> transactionInterceptor </值>
  254. </表>
  255. </物业>
  256. </豆>
  257. </豆>
  258. 即使后来不再需要事务管理,也可以直接在Bean定义文件中修改配置,而不用修改程序重新进行编译等动作。
  259. 声明事务管理是利用弹簧AOP来达成的,所以执行以上的程序时,请记得您的Classpath设置中必须包括spring-aop.jar。
  260. 5.3 。4   事务的属性介绍
  261. Spring使用AOP来完成声明式的事务管理,因而声明式事务是以方法为边界的,Spring的事务属性(Transaction attribute)自然就在于描述事务应用至方法上的策略,在Spring中事务属性分作以下的几个参数:
  262. 升传播行为(传播行为)
  263. 传播行为定义了事务应用于方法上之边界(Boundaries),它告知何时该开始一个新的事务,或何时事务该被暂停,或方法是否要在事务中进行。
  264. Spring定义了几个传播行为,可以在TransactionDefinition的API文件说明上找到相对应的常数与说明,以下列出几个:
  265. 表5.1   事务传播行为说明
  266. 传播行为说明
  267. PROPAGATION_MANDATORY方法必须在一个现存的事务中进行,否则丢出异常
  268. PROPAGATION_NESTED在一个嵌入的事务中进行,如果不是,则同PROPAGATION_REQUIRED
  269. PROPAGATION_NEVER指出不应在事务中进行,如果有就丢出异常
  270. PROPAGATION_NOT_SUPPORTED指出不应在事务中进行,如果有就暂停现存的事务
  271. PROPAGATION_REQUIRED支持现在的事务,如果没有就建立一个新的事务
  272. PROPAGATION_REQUIRES_NEW建立一个新的事务,如果现存一个事务就暂停它
  273. PROPAGATION_SUPPORTS支持现在的事务,如果没有就以非事务的方式执行
  274. 举个例子来说,如果传播行为被声明为PROPAGATION_REQUIRED,则事务的边界在开始第一个事务的方法呼叫及结束时,如果先前没有事务被开始,则事务边界即为目前方法的执行前后。又如果传播行为被声明为PROPAGATION_REQUIRES_NEW,则事务的边界即为该方法执行的前后。
  275. 升隔离层级(隔离级别)
  276. 在一个应用程序中,可能有多个事务同时在进行,这些事务应当彼此之间互相不知道另一个事务的存在,好比现在整个应用程序就只有一个事务存在,由于事务彼此之间独立,若读取的是同一个数据的话,就容易发生问题,例如:
  277. ñ脏读
  278. 某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个Roll回来了操作,则后一个事务所读取的数据就会是不正确的。
  279. n不重复读
  280. 在一个事务的两次查询之中数据不一致,这可能是因为两次查询过程中间插入了一个事务更新的原有的数据。
  281. ñ幻影读
  282. 在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
  283. 为了避免以上问题的方法之一,需要在某个事务进行过程中锁定正在更新或查询的数据字段,直到目前的事务完成,然而完全锁定字段时,若另一个事务来查询同一份数据就必须等待,直到前一个事务完成并解除锁定为止,因而会造成应用程序在查询或更新数据时效率上的问题,而事实上根据需求的不同,并不用在事务进行时完全地锁定数据,隔离层级可以让您根据实际的需求,对数据的锁定进行设置。
  284. Spring提供了几种隔离层级设置,同类型的设置可以在TransactionDefinition的API文件说明上找到相对应的常数与说明,以下列出几个:
  285. 表5.2   事务隔离层级说明
  286. 隔离层级说明
  287. ISOLATION_DEFAULT使用底层数据库预设的隔离层级
  288. ISOLATION_READ_COMMITTED允许事务读取其他并行的事务已经送出(提交)的
  289. 数据字段,可以防止脏读问题
  290. ISOLATION_READ_UNCOMMITTED允许事务读取其他并行的事务还没送出的数据,会发
  291. 生肮脏的,不可重复,幻影读取等问题
  292. 续表
  293. 隔离层级说明
  294. ISOLATION_REPEATABLE_READ要求多次读取的数据必须相同,除非事务本身更新
  295. 数据,可防止脏污,不可重复读问题
  296. ISOLATION_SERIALIZABLE完整的隔离层级,可防止脏污,Nonrepeatabl
  297. E,幻影读取等问题,会锁定对应的数据表
  298. 格,因而有效率问题
  299. 升只读提示(只读提示)
  300. 如果事务只进行读取的动作,则可以利用底层数据库在只读操作时发生的一些最佳化动作,由于这个动作利用到数据库在只读的事务操作最佳化,因而必须在事务中才有效,也就是说要搭配传播行为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED来设置。
  301. 升事务超时期间​​(交易超时时间)
  302. 有的事务操作可能延续很长一段的时间,事务本身可能关联到数据表格的锁定,因而长时间的事务操作会有效率上的问题,对于过长的事务操作,您要考虑Roll回事务并要求重新操作,而不是无限时的等待事务完成。
  303. 您可以设置事务超时期间,计时是从事务开始时,所以这个设置必须搭配传播行为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED来设置。
  304. 5.3 。5   TransactionAttributeSource,TransactionAttribute
  305. 在TransactionProxyFactoryBean的上有setTransactionAttributeSource()与setTransaction属性()方法,它们是用来设置事务属性的策略实例。
  306. 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。
  307. 一个应用的例子如下所示:
  308. ...
  309. 【JAVA]鉴于plaincopy
  310. <bean的ID = “transactionAttributeSource”
  311. 类=“org.springframework.transaction.interceptor。
  312. →的MatchAlwaysTransactionAttributeSource“/>
  313. <bean的ID = “userDAOProxy”
  314. 类=“org.springframework.transaction。
  315. →interceptor.TransactionProxyFactoryBean“>
  316. <属性名= “proxyInterfaces” >
  317. <目录>
  318. <值> onlyfun.caterpillar.IUserDAO </值>
  319. </表>
  320. </物业>
  321. <属性名= “目标”  参考= “userDAO的” />
  322. <属性名= “transactionManager的”  参考= “transactionManager的” />
  323. <属性名= “transactionAttributeSource”
  324. REF = “transactionAttributeSource” />
  325. </豆>
  326. ...
  327. 您可以使用org.springframework.transaction.interceptor.DefaultTransaction-属性,并设置自己的事务策略,之后设置给TransactionAttributeSource,例如:
  328. ...
  329. 【JAVA]鉴于plaincopy
  330. <bean的ID = “myTransactionAttribute”
  331. 类=“org.springframework.transaction。
  332. →interceptor.DefaultTransactionAttribute“>
  333. <属性名= “propagationBehaviorName”
  334. 值= “PROPAGATION_REQUIRES_NEW” />
  335. <属性名= “isolationLevelName”
  336. 值= “ISOLATION_REPEATABLE_READ” />
  337. </豆>
  338. <bean的ID = “transactionAttributeSource”
  339. 类=“org.springframework.transaction。
  340. →interceptor.MatchAlwaysTransactionAttributeSource“>
  341. <属性名= “transactionAttribute”
  342. REF = “myTransactionAttribute” />
  343. </豆>
  344. <bean的ID = “userDAOProxy”
  345. 类=“org.springframework.transaction。
  346. →interceptor.TransactionProxyFactoryBean“>
  347. <属性名= “proxyInterfaces” >
  348. <目录>
  349. <值> onlyfun.caterpillar.IUserDAO </值>
  350. </表>
  351. </物业>
  352. <属性名= “目标”  参考= “userDAO的” />
  353. <属性名= “transactionManager的”  参考= “transactionManager的” />
  354. <属性名= “transactionAttributeSource”
  355. REF = “transactionAttributeSource” />
  356. </豆>
  357. ...
  358. 可以使用org.springframework.transaction.interceptor.NameMatchTransaction- AttributeSource来指定某些方法要应用事务,以及要应用的事务策略,例如:
  359. ...
  360. 【JAVA]鉴于plaincopy
  361. <bean的ID = “transactionAttributeSource”
  362. 类=“org.springframework.transaction。
  363. →interceptor.NameMatchTransactionAttributeSource“>
  364. <属性名= “属性” >
  365. <道具>
  366. <支撑键= “插入*” > PROPAGATION_REQUIRES_NEW </道具>
  367. </道具>
  368. </物业>
  369. </豆>
  370. <bean的ID = “userDAOProxy”
  371. 类=“org.springframework.transaction。
  372. →interceptor.TransactionProxyFactoryBean“>
  373. <属性名= “proxyInterfaces” >
  374. <目录>
  375. <值> onlyfun.caterpillar.IUserDAO </值>
  376. </表>
  377. </物业>
  378. <属性名= “目标”  参考= “userDAO的” />
  379. <属性名= “transactionManager的”  参考= “transactionManager的” />
  380. <属性名= “transactionAttributeSource”
  381. REF = “transactionAttributeSource” />
  382. </豆>
  383. ...
  384. 在NameMatchTransactionAttributeSource的  "properties" 属性上,可以指定方法名称与事务策略,方法名称的指定可以指定全名,也可以使用Wildcard来指定,例如上面的指定中,只要方法名称以insert为开头的都会应用相对应的事务策略。
  385. 在指定事务策略时,指定的格式如下:
  386. 传播行为,隔离层级,只读,+异常 - 异常
  387. 除了传播行为一定要设置之外,其他都可选择性的设置,中间以逗号区隔,例如:
  388. PROPAGATION_REQUIRED,只读,-MyCheckedException
  389. MyCheckedException前面加上  "-"  时,表示发生指定异常时撤消操作,如果前面加上  "+" ,表示发生异常时立即提交。
  390. 在比较简单的设置中,可以仅设置TransactionProxyFactoryBean,并在它的  "transactionAttributes"  属性上直接设置要应用事务的方法及事务策略,例如:
  391. ...
  392. 【JAVA]鉴于plaincopy
  393. <bean的ID = “userDAOProxy”
  394. 类=“org.springframework.transaction。
  395. →interceptor.TransactionProxyFactoryBean“>
  396. <属性名= “proxyInterfaces” >
  397. <目录>
  398. <值> onlyfun.caterpillar.IUserDAO </值>
  399. </表>
  400. </物业>
  401. <属性名= “目标”  参考= “userDAO的” />
  402. <属性名= “transactionManager的”  参考= “transactionManager的” />
  403. <属性名= “transactionAttributes” >
  404. <道具>
  405. <支撑键= “插入*” > PROPAGATION_REQUIRED </道具>
  406. </道具>
  407. </物业>
  408. </豆>
  409. ...
  410. 甚至也可以直接指定TransactionInterceptor,以获得更多的控制,例如:
  411. ...
  412. 【JAVA]鉴于plaincopy
  413. <bean的ID = “transactionInterceptor”
  414. 类=“org.springframework.transaction。
  415. →interceptor.TransactionInterceptor“>
  416. <属性名= “transactionManager的” >
  417. REF = “transactionManager的” />
  418. <属性名= “transactionAttributeSource”
  419. 值= “onlyfun.caterpillar.UserDAO.insert * =→PROPAGATION_REQUIRED” />
  420. </豆>
  421. <bean的ID = “userDAOProxy”
  422. 类=“org.springframework.aop。
  423. →framework.ProxyFactoryBean“>
  424. <属性名= “proxyInterfaces” >
  425. <目录>
  426. <值> onlyfun.caterpillar.IUserDAO </值>
  427. </表>
  428. </物业>
  429. <属性名= “目标”  参考= “userDAO的” />
  430. <属性名= “interceptorNames”  值= “transactionInterceptor” />
  431. </豆>
  432. ...
  433. 选择哪一种设置方式是需求的问题,您可以尝试在DeclarativeTransactionDemo项目的Bean定义文件上设置以上所介绍的方式,基于篇幅的限制,以上仅列出部分的设置内容。
  434. 5.3 。6   春季  2.0 声明式事务管理:基于XML Schmea
  435. 在Spring  2.0 中要设置声明式事务管理,可以依赖于Spring  2.0 的<aop>与<tx>标签,因而要记得加入相关的名称空间声明:
  436. 【JAVA]鉴于plaincopy
  437. <?XML版本= “1.0”  编码= “UTF-8” ?>
  438. <豆的xmlns = “http://www.springframework.org/schema/beans”
  439. XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”
  440. 的xmlns:AOP = “http://www.springframework.org/schema/aop”
  441. 的xmlns:TX = “http://www.springframework.org/schema/tx”
  442. XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans
  443. HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  444. HTTP://www.springframework.org/schema/aop
  445. HTTP://www.springframework.org/schema/aop/spring-aop-2.0.xsd
  446. HTTP://www.springframework.org/schema/tx
  447. HTTP://www.springframework.org/schema/tx/spring-tx-2.0.xsd“>
  448. ...
  449. </豆>
  450. 事务是系统层面的服务,也就是一个Aspect,其实具体来说就是一个Advice,您可以使用<tx:advice>标签来提供这个Advice,它需要设置一个TransactionManager,并在当中使用<tx:attributes>来设置事务相关属性。
  451. 可以将先前的DeclarativeTransactionDemo项目改写,修改其beans-config.xml为使用<aop>与<tx>标签的方式:
  452. DeclarativeTransactionDemo2豆-config.xml中
  453. 【JAVA]鉴于plaincopy
  454. <?XML版本= “1.0”  编码= “UTF-8” ?>
  455. <豆的xmlns = “http://www.springframework.org/schema/beans”
  456. XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”
  457. 的xmlns:AOP = “http://www.springframework.org/schema/aop”
  458. 的xmlns:TX = “http://www.springframework.org/schema/tx”
  459. XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans
  460. HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  461. HTTP://www.springframework.org/schema/aop
  462. HTTP://www.springframework.org/schema/aop/spring-aop-2.0.xsd
  463. HTTP://www.springframework.org/schema/tx
  464. HTTP://www.springframework.org/schema/tx/spring-tx-2.0.xsd“>
  465. <bean的ID = “数据源”
  466. 类=“org.springframework.jdbc。
  467. →datasource.DriverManagerDataSource“
  468. 破坏法= “关闭” >
  469. <属性名= “driverClassName”
  470. 值= “com.mysql.jdbc.Driver” />
  471. <属性名= “URL”
  472. 值= “的jdbc:mysql的://本地主机:3306 /演示” />
  473. <属性名= “用户名”  值= “毛毛虫” />
  474. <属性名= “密码”  值= “123456” />
  475. </豆>
  476. <bean的ID = “transactionManager的”
  477. 类=“org.springframework.jdbc。
  478. →datasource.DataSourceTransactionManager“>
  479. <属性名= “数据源”  参考= “数据源” />
  480. </豆>
  481. <bean的ID = “userDAO的”
  482. 类= “onlyfun.caterpillar.UserDAO” >
  483. <属性名= “数据源”  参考= “数据源” />
  484. </豆>
  485. <TX:建议ID = “txAdvice”
  486. 交易经理= “transactionManager的” >
  487. <TX:属性>
  488. <TX:方法名= “插入*”  的传播= “要求” />
  489. <TX:方法名= “发现*”  只读= “真” />
  490. </ TX:属性>
  491. </ TX:建议>
  492. <AOP:配置>
  493. <AOP:切入点ID = “userDAOPointcut”
  494. 表达式= “执行(* onlyfun.caterpillar.IUserDAO。*(..))” />
  495. <AOP:顾问咨询-REF = “txAdvice”
  496. 切入点-REF = “userDAOPointcut” />
  497. </ AOP:配置>
  498. </豆>
  499. 注意到<tx:method>中的属性设置,对于传播行为、隔离层级、只读、超时、异常时撤回或提交,都有对应的"propagation" 、"isolation" 、"timeout" 、"read-only" 、"rollback-for" 、"no-rollback-for" 属性可以设置,若不设置,"propagation" 属性默认是"REQUIRE" ,"isolation" 属性默认是"DEFAULT" 、"timeout" 属性默认是"-1" (单位是秒)、"read-only" 属性默认是"false" 。
  500. 与先前介绍春季  2.0 基于XML Schema的AOP设置相同,由于不再于设置文件中设置代理对象,所以直接取得"userDAO" 实例进行操作即可。
  501. 5.3 。7   春天  2.0 声明式事务管理:基于注解
  502. 声明式事务管理在Spring  2.0 中,也支持使用Annotation的标示方式,方法是使用@Transactional 来标示,例如可以将DeclarativeTransactionDemo项目的UserDAO改写,在上头直接标示@Transactional ,并设置相关属性:
  503. DeclarativeTransactionDemo3 UserDAO.java
  504. 【JAVA]鉴于plaincopy
  505. 包装 onlyfun.caterpillar;
  506. 进口 java.util.Iterator的;
  507. 进口 的java.util.List;
  508. 进口 的java.util.Map;
  509. 进口 javax.sql.DataSource的;
  510. 进口 org.springframework.jdbc.core.JdbcTemplate;
  511. 进口 org.springframework.transaction.annotation.Propagation;
  512. 进口 org.springframework.transaction.annotation.Transactional;
  513. 公共 类 的UserDAO  实现 IUserDAO
    {
  514. 私人 的JdbcTemplate JdbcTemplate的;
  515. 公共 无效 的setDataSource(数据源数据源){
  516. 的JdbcTemplate =  新 的JdbcTemplate(数据源);
  517. }
  518. @Transactional (传播= Propagation.REQUIRED)
  519. 公共 无效 插入(用户用户){
  520. 字符串名称= user.getName();
  521. INT  年龄= user.getAge()的intValue()。
  522. jdbcTemplate.update(“INSERT INTO的用户(姓名,年龄)”
  523. +  “VALUES('”  +名称+  “',”  +年龄+  “)” );
  524. }
  525. @Transactional (只读= 真)
  526. 公众 用户发现(整数ID){
  527. 列表行= jdbcTemplate.queryForList(
  528. “SELECT * FROM WHERE用户ID =”  + id.intValue());
  529. 迭代它= rows.iterator();
  530. 如果(it.hasNext()){
  531. 地图中userMap =(图)it.next();
  532. 整数I =  新的 整数(userMap.get(“ID” )的ToString());
  533. 字符串名称= userMap.get( “ 名” )的ToString();
  534. 整数年龄=
  535. 新的 整数(userMap.get( “ 时代” )的ToString());
  536. 用户的用户=  新 用户();
  537. user.setId(ⅰ);
  538. user.setName(名);
  539. user.setAge(年龄);
  540. 返回 用户;
  541. }
  542. 返回 空值;
  543. }
  544. }
  545. 在使用@Transactional 时,相关的属性设置为"propagation" 、"isolation" 、"readOnly" 、"timeout" 、"rollbackFor" 、"noRollbackFor" 等,而在beans-config.xml中,则要使用<tx:annotation-driven>标签,并指定TransactionManager,例如:
  546. DeclarativeTransactionDemo3豆-config.xml中
  547. 【JAVA]鉴于plaincopy
  548. <?XML版本= “1.0”  编码= “UTF-8” ?>
  549. <豆的xmlns = “http://www.springframework.org/schema/beans”
  550. XMLNS:XSI = “http://www.w3.org/2001/XMLSchema-instance”
  551. 的xmlns:TX = “http://www.springframework.org/schema/tx”
  552. XSI:的schemaLocation =“HTTP://www.springframework.org/schema/beans
  553. HTTP://www.springframework.org/schema/beans/spring-beans-2.0.xsd
  554. HTTP://www.springframework.org/schema/tx
  555. HTTP://www.springframework.org/schema/tx/spring-tx-2.0.xsd“>
  556. <bean的ID = “数据源”
  557. 类=“org.springframework.jdbc。
  558. →datasource.DriverManagerDataSource“
  559. 破坏法= “关闭” >
  560. <属性名= “driverClassName”
  561. 值= “com.mysql.jdbc.Driver” />
  562. <属性名= “URL”
  563. 值= “的jdbc:mysql的://本地主机:3306 /演示” />
  564. <属性名= “用户名”  值= “毛毛虫” />
  565. <属性名= “密码”  值= “123456” />
  566. </豆>
  567. <bean的ID = “transactionManager的”
  568. 类=“org.springframework.jdbc。
  569. →datasource.DataSourceTransactionManager“>
  570. <属性名= “数据源”  参考= “数据源” />
  571. </豆>
  572. <bean的ID = “userDAO的”
  573. 类= “onlyfun.caterpillar.UserDAO” >
  574. <属性名= “数据源”  参考= “数据源” />
  575. </豆>
  576. <TX:注解驱动的事务管理器= “transactionManager的” />
  577. </豆>
  578. 同样的,由于不再于设置文件中设置代理对象,所以直接取得"userDAO" 实例进行操作即可。