8.6.2 使用XML Schema配置事务策略

        Spring 同时支持编程式事务策略和声明式事务策略,通常都推荐采用声明式事务策略。

        ⊙ 声明式事务能大大降低开发者的代码书写量,而且声明式事务几乎不影响应用的代码。因此,无论底层事务策略如何变化,应用程序都无须任何改变。

        ⊙ 应用程序代码无须任何事务处理代码,可以更专注于业务逻辑的实现。

        ⊙ Spring则可对任何POJO的方法提供事务管理,而且Spring的声明式事务管理无须容器的支持,可在任何环境下使用。

        ⊙ EJB的CMT无法提供声明式回滚规则:而通过配置文件,Spring可指定事务在遇到特定异常时自动回滚。

        ⊙ 由于Spring采用AOP的方式管理事务,因此,可以在事务回滚动作中插入用户自己的动作,而不仅仅是执行系统默认的回滚。

        Spring 2.x 的XML Schema方式提供了简洁的事务配置策略,Spring 2.x提供了 tx:命名空间 来配置事务管理,tx:命名空间下提供了<tx:advice.../>元素来配置事务增强处理,一旦使用该元素配置了事务增强处理,就可直接使用<aop:advisor.../>元素启用自动代理了。

        配置<tx:advice.../>元素时除了需要transaction-manager属性指定事务管理器之外,还需要配置一个<attributes.../>子元素,该子元素里又可包含多个<method.../>子元素。

        配置<tx:advice.../>元素的重点就是配置<method.../>子元素,实际上每个<method.../>子元素都为一批方法指定了所需的事务定义,包括事务传播属性、事务隔离属性、事务超时属性、只读事务、对指定异常回滚、对指定异常不回滚等。

        配置<method.../>子元素可以指定如下属性:

          ⊙ name : 必选属性,与该事务语义关联的方法名。该属性支持使用通配符,例如:‘add*’、‘delete*’、‘get*byId’、‘update*’等。

          ⊙ propagation : 指定事务传播行为,该属性值可为Propagation枚举类的任一枚举值。该属性的默认值为Propagation.REQUIRED。

          ⊙ isolation : 指定事务隔离级别,该属性值可为Isolation枚举类的任一枚举值。默认值为Isolation.DEFAULT。

          ⊙ timeout : 指定事务超时的时间(以秒为单位),指定-1意味着不超时,该属性默认值是-1.

          ⊙ read-only : 指定事务是否只读。该属性的默认值是false。

          ⊙ rollback-for : 指定触发事务回滚的异常类(应使用全限定类名),该属性可指定多个异常类,多个异常类之间以英文逗号隔开。

          ⊙ no-rollback-for : 指定不触发事务回滚的异常类(应使用全限定类名),该属性可指定多个异常类,多个异常类之间以英文逗号隔开。

        <method.../>子元素的propagation属性用于指定事务传播行为,Spring支持的事务传播行为如下:

          ⊙ PROPAGATION_MANDATORY(强制的) : 要求调用方法的线程必须处于事务环境中,否则抛出异常。

          ⊙ PROPAGATION_NEVER(决不) : 不允许调用该方法的线程处于事务中,如果调用该方法的线程处于事务环境中,则抛出异常。

          ⊙ PROPAGATION_SUPPORTS(支持) : 如果当前执行线程处于事务环境中,则使用当前事务,否则不使用事务。          

          ⊙ PROPAGATION_NOT_SUPPORED (被支持的): 如果调用该方法的线程处于事务环境中,则先暂停当前事务,然后执行该方法。

          ⊙ PROPAGATION_NESTED(嵌套的) : 即使执行该方法的线程已处于事务环境中,也依然启动新的事务,方法在嵌套的事务里执行;即使执行该方法的线程并未处于事务环境中,也启动新的事务,然后执行该方法,此时与PROPAGATION_REQUIRED相同。

          ⊙ PROPAGATION_REQUIRED(必需的) : 要求在事务环境中执行该方法,如果当前执行线程已处于事务环境中,则直接调用;如果当前执行线程不处于事务环境中,则启动新的事务后执行该方法。

          ⊙ PROPAGATION_REQUIES_NEW (需求): 该方法要求在新的事务环境中执行,如果当前执行线程已处于事务环境中,则先暂停当前事务,启动新事物后执行该方法;如果当前调用线程不处于事务环境中,则启动新的事务后执行方法。

        Class : NewsDaoImpl

package edu.pri.lime._8_6_2.dao;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;

public class NewsDaoImpl implements NewsDao {

    private DataSource ds;

    public void setDs(DataSource ds) {
this.ds = ds;
} @Override
public void insert(String title, String content) {
JdbcTemplate jt = new JdbcTemplate(ds);
jt.update("insert into news_inf values(null,?,?)", title, content);
// 两次插入的数据违反唯一键约束
jt.update("insert into news_inf values(null,?,?)", title, content);
// 如果没有事务控制,则第一条记录可以被插入
// 如果增加事务控制,将发现第一条记录也插不进去
} }

        XML :

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 扫描Spring的组件 -->
<context:component-scan base-package="edu.pri.lime._8_6_2.dao"/> <!-- 定义数据源Bean,使用C3P0数据源实现,并注入数据源的必要信息 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost/spring"/>
<property name="user" value="root"/>
<property name="password" value="System"/>
<property name="maxPoolSize" value="40"/>
<property name="minPoolSize" value="2"/>
<property name="initialPoolSize" value="2"/>
<property name="maxIdleTime" value="30"/>
</bean> <!-- 配置JDBC数据源的局部事务管理器,使用DataSourceTransactionManager类 -->
<!-- 该类实现了PlatformTransactionManager接口,是针对采用数据源连接的特定实现 -->
<!-- 配置DataSourceTransactionmanager时需要依赖注入DataSource的引用 -->
<bean id="transactionManager" class="org.spring.framework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean> <!-- 配置一个业务逻辑Bean -->
<bean id="newsDao" class="edu.pri.lime._8_6_2.dao.NewsDaoImpl">
<property name="ds" ref="dataSource"/>
</bean> <!-- 配置事务增强处理Bean,指定事务管理器 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 用于配置详细的事务定义 -->
<tx:attributes>
<!-- 所有以get开头的方法是只读的 -->
<tx:method name="get*" read-only="true"/>
<!-- 其他方法使用默认的事务设置,指定超时时长为5秒 -->
<tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="5"/>
</tx:attributes>
</tx:advice> <!-- AOP配置的元素 -->
<aop:config>
<!-- 配置一个切入点,匹配edu.pri.lime._8_6_2.dao包下所有以Impl结尾的类里所有方法的执行 -->
<aop:pointcut expression="execution(* edu.pri.lime._8_6_2.dao.*Impl.*(..))" id="myPointcut"/>
<!-- 指定在myPointcut切入点应用txAdvice事务增强处理 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
</aop:config>
</beans>

        Class : SpringTest

package edu.pri.lime._8_6_2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._8_6_2.dao.NewsDao;
import edu.pri.lime._8_6_2.dao.NewsDaoImpl; public class SpringTest { public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_8_6_2_tx.xml");
// 获取事务代理Bean
NewsDao dao = ctx.getBean("newsDao", NewsDaoImpl.class);
// 执行插入操作
dao.insert("lime", "Oracle");
}
}

        当使用<tx:advisor.../>为目标Bean生成事务代理之后,SpringAOP将会把负责事务操作的增强处理织入目标Bean的业务方法中。

        Spring 不仅支持对接口的代理,而且也可对具体类生成代理,只要设置proxytargetClass属性为true既可以了。如果目标Bean没有实现热河接口,proxyTargetClass属性默认被设为true,此时Spring会对具体类生成代理。当然,通常建议面向接口编程,而不要面向具体的实现类编程。

        当采用<aop:advisor.../>元素将Advice和切入点绑定时,实际上是由Spring提供的Bean后处理器完成的。Spring提供了BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator两个Bean后处理器,它们都可以对容器中的Bean执行后处理(为他们织入切面中包含的增强处理)。当配置<aop:advisor.../>元素时传入一个txAdvice事务增强处理,所以Bean后处理器将为所有Bean实例里匹配切入点的方法织入事务操作的增强处理。

        在这种声明式事务策略下,Spring也允许为不同的业务逻辑方法指定不同的事务策略:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 扫描Spring的组件 -->
<context:component-scan base-package="edu.pri.lime._8_6_2.dao"/> <!-- 定义数据源Bean,使用C3P0数据源实现,并注入数据源的必要信息 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost/spring"/>
<property name="user" value="root"/>
<property name="password" value="System"/>
<property name="maxPoolSize" value="40"/>
<property name="minPoolSize" value="2"/>
<property name="initialPoolSize" value="2"/>
<property name="maxIdleTime" value="30"/>
</bean> <!-- 配置JDBC数据源的局部事务管理器,使用DataSourceTransactionManager类 -->
<!-- 该类实现了PlatformTransactionManager接口,是针对采用数据源连接的特定实现 -->
<!-- 配置DataSourceTransactionmanager时需要依赖注入DataSource的引用 -->
<bean id="transactionManager" class="org.spring.framework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean> <!-- 配置一个业务逻辑Bean -->
<bean id="newsDao" class="edu.pri.lime._8_6_2.dao.NewsDaoImpl">
<property name="ds" ref="dataSource"/>
</bean> <!-- 配置两个事务增强处理 -->
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice> <tx:advice id="noTxAdvice">
<tx:attributes>
<tx:method name="*" propagation="NEVER"/>
</tx:attributes>
</tx:advice> <aop:config>
<!-- 配置一个切入点,匹配userService Bean 中所有方法的执行 -->
<aop:pointcut expression="bean(userService)" id="txOperation"/>
<!-- 配置一个切入点,匹配包下所有以Impl结尾的类中所有方法的执行 -->
<aop:pointcut expression="execution(* edu.pri.lime._8_6_2.dao.*Impl.*(..))" id="noTxOperation"/>
<!-- 将txOperation切入点和defaultTxAdvice切面绑定在一起 -->
<aop:advisor advice-ref="defaultTxAdvice" pointcut-ref="txOperation"/>
<!-- 将noTxOperation切入点和noTxAdvice切面绑定在一起 -->
<aop:advisor advice-ref="noTxAdvice" pointcut-ref="noTxOperation"/>
</aop:config> <!-- 配置第一个业务逻辑Bean,该Bean的名字为userService,匹配txOperation切入点将被织入defaultTxAdvice切面里的增强处理 -->
<bean id="userService" class=""></bean>
<!-- 配置第二个业务逻辑Bean,实现类位于包下,将被织入noTxAdvice切面里的增强处理 -->
<bean id="anotherFooService" class=""/>
</beans>

        如果想让事务在遇到特定的cheched异常时自动回滚,则可借助于rollback-for属性。

        在默认情况下,只有当方法引发运行时异常和unchecked异常时,Spring事务机制才会自动回滚事务。也就是说,只有当抛出一个RuntimeException或其子类实例,或Error对象时,Spring才会自动回滚事务。如果事务方法抛出checked异常,则事务不会自动回滚。

        通过使用rollback-for属性可强制Spring遇到特定checked异常时自动回滚事务:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"
rollback-for="exception.NoItemException" />
<tx:method name="*" />
</tx:attributes>
</tx:advice> </beans>

        如果想让Spring遇到特定runtime异常时强制不会滚事务,则可通过no-rollback-for属性来指定:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"
no-rollback-for="exception.AuctionException" />
<tx:method name="*" />
</tx:attributes>
</tx:advice> </beans>

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦

啦啦啦

8 -- 深入使用Spring -- 6...2 Spring支持的事务策略的更多相关文章

  1. 8 -- 深入使用Spring -- 6...1 Spring支持的事务策略

    8.6.1 Spring支持的事务策略 JTA.JDBC.Hibernate Java EE应用的传统事务有两种策略:全局事务和局部事务.全局事务由应用服务器管理,需要底层服务器的JTA(Java T ...

  2. 8.Spring对JDBC的支持和事务

    1.Spring对JDBC的支持 DAO : Spring中对数据访问对象(DAO)的支持旨在简化Spring与数据访问技术的操作,使JDBC.Hibernate.JPA和JDO等采用统一的方式访问 ...

  3. java 利用spring JavaMailSenderImpl发送邮件,支持普通文本、附件、html、velocity模板

    java 利用spring JavaMailSenderImpl发送邮件,支持普通文本.附件.html.velocity模板 博客分类: Java Spring   本文主要介绍利用JavaMailS ...

  4. Spring AOP和AspectJ支持

    学了Spring之后发现我都不知道java为何物-- 在这一章中有好几节,讲的切面编程 第一节:在项目中启用Spring的AspectJ注解支持 第二节:用AspectJ注解声明aspect 第三节: ...

  5. Spring使用拦截器支持国际化(转)

    Spring使用拦截器支持国际化很方便,使用时只需要两个步骤: 一.spring配置 具体配置方式如下: <!-- 资源文件绑定器,文件名称:messages.properties(没有找到时的 ...

  6. Spring对远程服务的支持

    Java程序有以下的远程调用技术选择: 远程过程调用(RPC)是同步的,客户端在服务器端返回结果之前将一直被阻塞. 各种技术适用的场景如下: 典型的RMI开发的过程如下: 定义一个接口,用于客户端和服 ...

  7. 1.Spring对JDBC整合支持

    1.Spring对JDBC整合支持 Spring对DAO提供哪些支持 1)Spring对DAO异常提供统一处理 2)Spring对DAO编写提供支持的抽象类 3)提高编程效率,减少DAO编码量 Spr ...

  8. [Spring学习笔记 7 ] Spring中的数据库支持 RowMapper,JdbcDaoSupport 和 事务处理Transaction

    1.Spring中的数据库支持 把具有相同功能的代码模板抽取到一个工具类中.2.关于jdbc template的应用 jdbcTemplate模板操作类,把访问jdbc的模板抽取到template中, ...

  9. Spring Boot 添加JSP支持【转】

    Spring Boot 添加JSP支持 大体步骤: (1)            创建Maven web project: (2)            在pom.xml文件添加依赖: (3)     ...

随机推荐

  1. HTML 5 断点续上传

    断点上传,java里面比较靠谱一点的,一般都会选用Flex.我承认,Flex只是摸了一下,不精通.HTML 5 有个Blob对象(File对象继承它),这个对象有个方法slice方法,可以对一个文件进 ...

  2. AngularJS中使用$http对MongoLab数据表进行增删改查

    本篇体验使用AngularJS中的$http对MongoLab数据表进行增删改查. 主页面: <button ng-click="loadCourse()">Load ...

  3. windows环境下面批量移动文件到指定文件夹里面

    move D:批量新建文件夹\upload\20171225173033565_2052.jpg D:批量新建文件夹\1623 move D:批量新建文件夹\upload\20171225174344 ...

  4. leetcode344 反转字符串 c++实现

    编写一个函数,其作用是将输入的字符串反转过来. 示例 1: 输入: "hello" 输出: "olleh" 示例 2: 输入: "A man, a p ...

  5. angular default project (angular.json的解读)

    Change the default Angular project Understanding it's purpose and limits Klaus KazlauskasFollow Nov ...

  6. Chrome网页性能分析工具

    performance-analyser https://chrome.google.com/webstore/detail/performance-analyser/djgfmlohefpomchf ...

  7. 深入理解JVM(一)——JVM内存模型

    JVM内存模型 Java虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是: 1. 程序计数器 2. Java虚拟机栈 3. 本地方法栈 4. 堆 5. 方法区. ...

  8. Redis更新的正确方法

    原文(缓存更新的套路):看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中.然而,这个是逻辑是错误的.试想,两个并发操作,一个是更新操作,另一个是查询操 ...

  9. MDX Cookbook 10 - 计算 Year To Date 的 Running Total(YTD 与 PeriodsToDate 的区别)

    在这个小节中我们将计算度量值的 Year To Date 的值,也就是计算从年开始到当前时间成员为止的度量值的累加结果. 下面的这个查询显示了所有以周为单位的 Reseller Sales Amoun ...

  10. C++11 lambda表达式是如何实现的?

    lambda表达式是如何实现的呢? 其实是编译器为我们了创建了一个类,这个类重载了(),让我们可以像调用函数一样使用.所以,你写的lambda表达式和真正的实现,是这个样子的: 而对于捕获变量的lam ...