1.编程式事务:编码方式实现事务管理(代码演示为JDBC事务管理)

Spring实现编程式事务,依赖于2大类,分别是上篇文章提到的PlatformTransactionManager,与模版类TransactionTemplate(推荐使用)。下面分别详细介绍Spring是如何通过该类实现事务管理。
1)PlatformTransactionManager,上篇文章已经详情解说了该类所拥有的方法,不记得可以回看上篇文章。
  1. 事务管理器配置
  2. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  3. <property name="jdbcUrl" value="${db.jdbcUrl}" />
  4. <property name="user" value="${user}" />
  5. <property name="password" value="${password}" />
  6. <property name="driverClass" value="${db.driverClass}" />
  7. <!--连接池中保留的最小连接数。 -->
  8. <property name="minPoolSize">
  9. <value>5</value>
  10. </property>
  11. <!--连接池中保留的最大连接数。Default: 15 -->
  12. <property name="maxPoolSize">
  13. <value>30</value>
  14. </property>
  15. <!--初始化时获取的连接数,取值应在minPoolSizemaxPoolSize之间。Default: 3 -->
  16. <property name="initialPoolSize">
  17. <value>10</value>
  18. </property>
  19. <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
  20. <property name="maxIdleTime">
  21. <value>60</value>
  22. </property>
  23. <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
  24. <property name="acquireIncrement">
  25. <value>5</value>
  26. </property>
  27. <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 如果maxStatementsmaxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
  28. <property name="maxStatements">
  29. <value>0</value>
  30. </property>
  31. <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
  32. <property name="idleConnectionTestPeriod">
  33. <value>60</value>
  34. </property>
  35. <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
  36. <property name="acquireRetryAttempts">
  37. <value>30</value>
  38. </property>
  39. <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
  40. <property name="breakAfterAcquireFailure">
  41. <value>true</value>
  42. </property>
  43. <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriodautomaticTestTable等方法来提升连接测试的性能。Default: false -->
  44. <property name="testConnectionOnCheckout">
  45. <value>false</value>
  46. </property>
  47. </bean>
  48. <!--DataSourceTransactionManager位于org.springframework.jdbc.datasource包下,数据源事务管理类,提供对单个javax.sql.DataSource数据源的事务管理,主要用于JDBCMybatis框架事务管理。 -->
  49. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  50. <property name="dataSource" ref="dataSource" />
  51. </bean>
  1. 业务中使用代码(以测试类展示)
  2. import java.util.Map;
  3. import javax.annotation.Resource;
  4. import javax.sql.DataSource;
  5. import org.apache.log4j.Logger;
  6. import org.junit.Test;
  7. import org.junit.runner.RunWith;
  8. import org.springframework.jdbc.core.JdbcTemplate;
  9. import org.springframework.test.context.ContextConfiguration;
  10. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  11. import org.springframework.transaction.PlatformTransactionManager;
  12. import org.springframework.transaction.TransactionDefinition;
  13. import org.springframework.transaction.TransactionStatus;
  14. import org.springframework.transaction.support.DefaultTransactionDefinition;
  15.  
  16. @RunWith(SpringJUnit4ClassRunner.class)
  17. @ContextConfiguration(locations = { "classpath:spring-public.xml" })
  18. public class test {
  19. @Resource
  20. private PlatformTransactionManager txManager;
  21. @Resource
  22. private DataSource dataSource;
  23. private static JdbcTemplate jdbcTemplate;
  24. Logger logger=Logger.getLogger(test.class);
  25. private static final String INSERT_SQL = "insert into testtranstation(sd) values(?)";
  26. private static final String COUNT_SQL = "select count(*) from testtranstation";
  27. @Test
  28. public void testdelivery(){
  29. //定义事务隔离级别,传播行为,
  30. DefaultTransactionDefinition def = new DefaultTransactionDefinition();
  31. def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
  32. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
  33. //事务状态类,通过PlatformTransactionManager的getTransaction方法根据事务定义获取;获取事务状态后,Spring根据传播行为来决定如何开启事务
  34. TransactionStatus status = txManager.getTransaction(def);
  35. jdbcTemplate = new JdbcTemplate(dataSource);
  36. int i = jdbcTemplate.queryForInt(COUNT_SQL);
  37. System.out.println("表中记录总数:"+i);
  38. try {
  39. jdbcTemplate.update(INSERT_SQL, "1");
  40. txManager.commit(status); //提交status中绑定的事务
  41. } catch (RuntimeException e) {
  42. txManager.rollback(status); //回滚
  43. }
  44. i = jdbcTemplate.queryForInt(COUNT_SQL);
  45. System.out.println("表中记录总数:"+i);
  46. }
  47.  
  48. }

2)使用TransactionTemplate,该类继承了接口DefaultTransactionDefinition,用于简化事务管理,事务管理由模板类定义,主要是通过TransactionCallback回调接口或TransactionCallbackWithoutResult回调接口指定,通过调用模板类的参数类型为TransactionCallback或TransactionCallbackWithoutResult的execute方法来自动享受事务管理。

TransactionTemplate模板类使用的回调接口:

  • TransactionCallback:通过实现该接口的“T doInTransaction(TransactionStatus status) ”方法来定义需要事务管理的操作代码;
  • TransactionCallbackWithoutResult:继承TransactionCallback接口,提供“void doInTransactionWithoutResult(TransactionStatus status)”便利接口用于方便那些不需要返回值的事务操作代码。

还是以测试类方式展示如何实现

  1. @Test
  2. public void testTransactionTemplate(){
  3. jdbcTemplate = new JdbcTemplate(dataSource);
  4. int i = jdbcTemplate.queryForInt(COUNT_SQL);
  5. System.out.println("表中记录总数:"+i);
  6. //构造函数初始化TransactionTemplate
  7. TransactionTemplate template = new TransactionTemplate(txManager);
  8. template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
  9. //重写execute方法实现事务管理
  10. template.execute(new TransactionCallbackWithoutResult() {
  11. @Override
  12. protected void doInTransactionWithoutResult(TransactionStatus status) {
  13. jdbcTemplate.update(INSERT_SQL, "饿死"); //字段sd为int型,所以插入肯定失败报异常,自动回滚,代表TransactionTemplate自动管理事务
  14. }}
  15. );
  16. i = jdbcTemplate.queryForInt(COUNT_SQL);
  17. System.out.println("表中记录总数:"+i);
  18. }

2.声明式事务:可知编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现。

声明式事务实现方式主要有2种,一种为通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现,另为一种通过@Transactional实现事务管理实现,下面详细说明2种方法如何配置,已经相关注意点
1)方式一,配置文件如下
  1. <!--
  2. <tx:advice>定义事务通知,用于指定事务属性,其中“transaction-manager”属性指定事务管理器,并通过<tx:attributes>指定具体需要拦截的方法
  3. <tx:method>拦截方法,其中参数有:
  4. name:方法名称,将匹配的方法注入事务管理,可用通配符
  5. propagation:事务传播行为,
  6. isolation:事务隔离级别定义;默认为“DEFAULT”
  7. timeout:事务超时时间设置,单位为秒,默认-1,表示事务超时将依赖于底层事务系统;
  8. read-only:事务只读设置,默认为false,表示不是只读;
  9. rollback-for:需要触发回滚的异常定义,可定义多个,以“,”分割,默认任何RuntimeException都将导致事务回滚,而任何Checked Exception将不导致事务回滚;
  10. no-rollback-for:不被触发进行回滚的 Exception(s);可定义多个,以“,”分割;
  11. -->
  12. <tx:advice id="advice" transaction-manager="transactionManager">
  13. <tx:attributes>
  14. <!-- 拦截save开头的方法,事务传播行为为:REQUIRED:必须要有事务, 如果没有就在上下文创建一个 -->
  15. <tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="" read-only="false" no-rollback-for="" rollback-for=""/>
  16. <!-- 支持,如果有就有,没有就没有 -->
  17. <tx:method name="*" propagation="SUPPORTS"/>
  18. </tx:attributes>
  19. </tx:advice>
  20. <!-- 定义切入点,expression为切人点表达式,如下是指定impl包下的所有方法,具体以自身实际要求自定义 -->
  21. <aop:config>
  22. <aop:pointcut expression="execution(* com.kaizhi.*.service.impl.*.*(..))" id="pointcut"/>
  23. <!--<aop:advisor>定义切入点,与通知,把tx与aop的配置关联,才是完整的声明事务配置 -->
  24. <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
  25. </aop:config>
关于事务传播行为与隔离级别,可参考http://blog.csdn.net/liaohaojian/article/details/68488150
注意点:
  1. 事务回滚异常只能为RuntimeException异常,而Checked Exception异常不回滚,捕获异常不抛出也不会回滚,但可以强制事务回滚:TransactionAspectSupport.currentTransactionStatus().isRollbackOnly();
  2. 解决“自我调用”而导致的不能设置正确的事务属性问题,可参考http://www.iteye.com/topic/1122740

2)方式二通过@Transactional实现事务管理

  1. <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  2. <property name="dataSource" ref="dataSource"/>
  3. </bean>
  4. <tx:annotation-driven transaction-manager="txManager"/> //开启事务注解
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED),具体参数跟上面<tx:method>中一样
Spring提供的@Transaction注解事务管理,内部同样是利用环绕通知TransactionInterceptor实现事务的开启及关闭。
使用@Transactional注意点:
    1. 如果在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口;
    2. 建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是因为如果使用JDK代理机制(基于接口的代理)是没问题;而使用使用CGLIB代理(继承)机制时就会遇到问题,因为其使用基于类的代理而不是接口,这是因为接口上的@Transactional注解是“不能继承的”;
 

spring事务的开启方式(编程式和声明式)的更多相关文章

  1. Spring框架——事务处理(编程式和声明式)

     一. 事务概述 ●在JavaEE企业级开发的应用领域,为了保证数据的完整性和一致性,必须引入数据库事务的概念,所以事务管理是企业级应用程序开发中必不可少的技术. ●事务就是一组由于逻辑上紧密关联而合 ...

  2. Spring编程式和声明式事务实例讲解

    Java面试通关手册(Java学习指南):https://github.com/Snailclimb/Java_Guide 历史回顾: 可能是最漂亮的Spring事务管理详解 Spring事务管理 S ...

  3. Spring事务:一种编程式事务,三种声明式事务

    事务隔离级别 隔离级别是指若干个并发的事务之间的隔离程度.TransactionDefinition 接口中定义了五个表示隔离级别的常量: TransactionDefinition.ISOLATIO ...

  4. Spring事务的开启方式

    1.通过注解方式@Transactional @Transactional(rollbackForClassName = { "Exception", "RuntimeE ...

  5. 二十 Spring的事务管理及其API&事务的传播行为,编程式&声明式(xml式&注解式,底层AOP),转账案例

    Spring提供两种事务方式:编程式和声明式(重点) 前者需要手写代码,后者通过配置实现. 事务的回顾: 事务:逻辑上的一组操作,组成这组事务的各个单元,要么全部成功,要么全部失败 事务的特性:ACI ...

  6. 开涛spring3(9.3) - Spring的事务 之 9.3 编程式事务

    9.3  编程式事务 9.3.1  编程式事务概述 所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理. Spring框架提供一致的事务抽象,因此对于JDBC还是JTA事务都是 ...

  7. 玩转Spring全家桶笔记 04 Spring的事务抽象、事务传播特性、编程式事务、申明式事务

    1.Spring 的事务抽象 Spring提供了一致的事务模型 JDBC/Hibernate/Mybatis 操作数据 DataSource/JTA 事务 2.事务抽象的核心接口 PlatformTr ...

  8. 春天的事务之9.3编程式事务 - 跟我学spring3

    9.3编程式事务 9.3.1编程式事务概述 所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理. Spring框架提供一致的事务抽象,因此对于JDBC还是JTA事务都是采用相同 ...

  9. 一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)

    这里是参考B站上的大佬做的面试题笔记.大家也可以去看视频讲解!!! 文章目录 31.线程池复用的原理 32.spring是什么? 33.对Aop的理解 34.对IOC的理解 35.BeanFactor ...

随机推荐

  1. poj2584T-Shirt——网络最大流

    题目:http://poj.org/problem?id=2584 以人和衣服作为点,建立超级源点和超级汇点,人连边权为1的边,衣服对源点连边权为件数的边(别弄乱顺序): 试图写构造函数,但CE了,最 ...

  2. RT-Thread的线程(任务)处理 rt_thread_create/rt_thread_init区别

    RT-Thread中使用线程这个概念,而不是任务.两者相似,我在这里把他的线程当作任务来理解了 1.任务处理: 动态任务相关API 创建任务:rt_thread_create函数,创建任务之后会返回r ...

  3. POJ2553( 有向图缩点)

    The Bottom of a Graph Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 9779   Accepted:  ...

  4. tomcat 开机自启方法

    1.把下面的代码保存为tomcat文件,并让它成为可执行文件 chmod 755 tomcat. #!/bin/bash # # /etc/rc.d/init.d/tomcat # init scri ...

  5. Linux命令总结_文件的输入与 输出

    1.echo命令 例子:echo string 解释:echo命令用于显示文本或变量,或者把字符串输入到文件,常用的几个特殊字符有以下几个 \c 不换行 \f 进纸 \t 调格 \n 换行 例子:ec ...

  6. wpf RenderTargetBitmap保存控件为图片时图片尺寸不对的问题

    使用RenderTargetBitmap渲染图片时,必须在需要渲染的控件外层包含一个border控件,不然渲染的图片返回就会出现问题. 如下: <Grid> <Grid.RowDef ...

  7. c/c++语言实现tesseract ocr引擎编程实例

    编译下面的程序操作系统必须在安装了tesseract库和leptonica库才可以 Basic example c++ code: #include <tesseract/baseapi.h&g ...

  8. 第二课2、ROS

    1.ROS框架 分为以下三个级别: 1)文件系统级 2)计算图级 计算图级是ROS处理数据的一种点对点的网络形式,描述程序是如何运行的. 基本的计算图级概念包括:节点,参数服务器,消息,服务,主题和包 ...

  9. ARP欺骗(完全版)

    在讲ARP欺骗之前先讲讲什么是ARP以及ARP欺骗的原理吧. 一.  什么是ARP? arp英文全称: address resolution  protocol   中文:地址解析协议 它的作用:是根 ...

  10. 6. webshell文件上传分析溯源

    这道题也是借助大佬的帮助才成功,具体我们来看: 既然人家扫描发现后台目录有文件上传,我们也不能落后,顺便拿出了传说中的御剑,并进行一波扫描: 发现了几个比较有用的目录,特别是upload1.php跟u ...