Spring事务管理的实现方式:编程式事务与声明式事务
1.上篇文章讲解了Spring事务的传播级别与隔离级别,以及分布式事务的简单配置,点击回看上篇文章
2.编程式事务:编码方式实现事务管理(代码演示为JDBC事务管理)
事务管理器配置<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="jdbcUrl" value="${db.jdbcUrl}" /> <property name="user" value="${user}" /> <property name="password" value="${password}" /> <property name="driverClass" value="${db.driverClass}" /> <!--连接池中保留的最小连接数。 --> <property name="minPoolSize"> <value>5</value> </property> <!--连接池中保留的最大连接数。Default: 15 --> <property name="maxPoolSize"> <value>30</value> </property> <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> <property name="initialPoolSize"> <value>10</value> </property> <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --> <property name="maxIdleTime"> <value>60</value> </property> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> <property name="acquireIncrement"> <value>5</value> </property> <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --> <property name="maxStatements"> <value>0</value> </property> <!--每60秒检查所有连接池中的空闲连接。Default: 0 --> <property name="idleConnectionTestPeriod"> <value>60</value> </property> <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 --> <property name="acquireRetryAttempts"> <value>30</value> </property> <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false --> <property name="breakAfterAcquireFailure"> <value>true</value> </property> <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能。Default: false --> <property name="testConnectionOnCheckout"> <value>false</value> </property> </bean> <!--DataSourceTransactionManager位于org.springframework.jdbc.datasource包下,数据源事务管理类,提供对单个javax.sql.DataSource数据源的事务管理,主要用于JDBC,Mybatis框架事务管理。 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>业务中使用代码(以测试类展示)
import java.util.Map; import javax.annotation.Resource; import javax.sql.DataSource; import org.apache.log4j.Logger; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:spring-public.xml" }) public class test { @Resource private PlatformTransactionManager txManager; @Resource private DataSource dataSource; private static JdbcTemplate jdbcTemplate; Logger logger=Logger.getLogger(test.class); private static final String INSERT_SQL = "insert into testtranstation(sd) values(?)"; private static final String COUNT_SQL = "select count(*) from testtranstation"; @Test public void testdelivery(){ //定义事务隔离级别,传播行为, DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //事务状态类,通过PlatformTransactionManager的getTransaction方法根据事务定义获取;获取事务状态后,Spring根据传播行为来决定如何开启事务 TransactionStatus status = txManager.getTransaction(def); jdbcTemplate = new JdbcTemplate(dataSource); int i = jdbcTemplate.queryForInt(COUNT_SQL); System.out.println("表中记录总数:"+i); try { jdbcTemplate.update(INSERT_SQL, "1"); txManager.commit(status); //提交status中绑定的事务 } catch (RuntimeException e) { txManager.rollback(status); //回滚 } i = jdbcTemplate.queryForInt(COUNT_SQL); System.out.println("表中记录总数:"+i); } }
2)使用TransactionTemplate,该类继承了接口DefaultTransactionDefinition,用于简化事务管理,事务管理由模板类定义,主要是通过TransactionCallback回调接口或TransactionCallbackWithoutResult回调接口指定,通过调用模板类的参数类型为TransactionCallback或TransactionCallbackWithoutResult的execute方法来自动享受事务管理。
TransactionTemplate模板类使用的回调接口:
- TransactionCallback:通过实现该接口的“T doInTransaction(TransactionStatus status) ”方法来定义需要事务管理的操作代码;
- TransactionCallbackWithoutResult:继承TransactionCallback接口,提供“void doInTransactionWithoutResult(TransactionStatus status)”便利接口用于方便那些不需要返回值的事务操作代码。
还是以测试类方式展示如何实现
@Test
public void testTransactionTemplate(){
jdbcTemplate = new JdbcTemplate(dataSource);
int i = jdbcTemplate.queryForInt(COUNT_SQL);
System.out.println("表中记录总数:"+i);
//构造函数初始化TransactionTemplate
TransactionTemplate template = new TransactionTemplate(txManager);
template.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
//重写execute方法实现事务管理
template.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
jdbcTemplate.update(INSERT_SQL, "饿死"); //字段sd为int型,所以插入肯定失败报异常,自动回滚,代表TransactionTemplate自动管理事务
}}
);
i = jdbcTemplate.queryForInt(COUNT_SQL);
System.out.println("表中记录总数:"+i);
}
3.声明式事务:可知编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现。
<!--
<tx:advice>定义事务通知,用于指定事务属性,其中“transaction-manager”属性指定事务管理器,并通过<tx:attributes>指定具体需要拦截的方法
<tx:method>拦截方法,其中参数有:
name:方法名称,将匹配的方法注入事务管理,可用通配符
propagation:事务传播行为,
isolation:事务隔离级别定义;默认为“DEFAULT”
timeout:事务超时时间设置,单位为秒,默认-1,表示事务超时将依赖于底层事务系统;
read-only:事务只读设置,默认为false,表示不是只读;
rollback-for:需要触发回滚的异常定义,可定义多个,以“,”分割,默认任何RuntimeException都将导致事务回滚,而任何Checked Exception将不导致事务回滚;
no-rollback-for:不被触发进行回滚的 Exception(s);可定义多个,以“,”分割;
-->
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 拦截save开头的方法,事务传播行为为:REQUIRED:必须要有事务, 如果没有就在上下文创建一个 -->
<tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED" timeout="" read-only="false" no-rollback-for="" rollback-for=""/>
<!-- 支持,如果有就有,没有就没有 -->
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!-- 定义切入点,expression为切人点表达式,如下是指定impl包下的所有方法,具体以自身实际要求自定义 -->
<aop:config>
<aop:pointcut expression="execution(* com.kaizhi.*.service.impl.*.*(..))" id="pointcut"/>
<!--<aop:advisor>定义切入点,与通知,把tx与aop的配置关联,才是完整的声明事务配置 -->
<aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
</aop:config>
- 事务回滚异常只能为RuntimeException异常,而Checked Exception异常不回滚,捕获异常不抛出也不会回滚,但可以强制事务回滚:TransactionAspectSupport.currentTransactionStatus().isRollbackOnly();
- 解决“自我调用”而导致的不能设置正确的事务属性问题,可参考http://www.iteye.com/topic/1122740
2)方式二通过@Transactional实现事务管理
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/> //开启事务注解
使用@Transactional注意点:
- 如果在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口;
- 建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是因为如果使用JDK代理机制(基于接口的代理)是没问题;而使用使用CGLIB代理(继承)机制时就会遇到问题,因为其使用基于类的代理而不是接口,这是因为接口上的@Transactional注解是“不能继承的”;
Spring事务管理的实现方式:编程式事务与声明式事务的更多相关文章
- Spring事务的介绍,以及基于注解@Transactional的声明式事务
前言 事务是一个非常重要的知识点,前面的文章已经有介绍了关于SpringAOP代理的实现过程:事务管理也是AOP的一个重要的功能. 事务的基本介绍 数据库事务特性: 原子性 一致性 隔离性 持久性 事 ...
- 解决 spring mvc 3.0 结合 hibernate3.2 使用<tx:annotation-driven>声明式事务无法提交的问题(转载)
1.问题复现 spring 3.0 + hibernate 3.2 spring mvc使用注解方式:service使用@service注解 事务使用@Transactional 事务配置使用 < ...
- spring笔记--事务管理之声明式事务
事务简介: 事务管理是企业级应用开发中必不可少的技术,主要用来确保数据的完整性和一致性, 事务:就是一系列动作,它们被当作一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. Spring中使 ...
- 全面分析 Spring 的编程式事务管理及声明式事务管理
开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...
- 全面分析 Spring 的编程式事务管理及声明式事务管理--转
开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...
- spring事务管理——编程式事务、声明式事务
本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本教程假定您已经掌握了 ...
- Spring编程式事务管理及声明式事务管理
本文将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. Spring 事务属性分析 事务管理 ...
- Spring 声明式事务与编程式事务详解
本文转载自IBM开发者论坛:https://developer.ibm.com/zh/articles/os-cn-spring-trans 根据自己的学习理解有所调整,用于学习备查. 事务管理对于企 ...
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
http://blog.csdn.net/bao19901210/article/details/41724355 http://www.cnblogs.com/leiOOlei/p/3725911. ...
- spring事务配置,声明式事务管理和基于@Transactional注解的使用(转载)
原文地址:http://blog.csdn.net/bao19901210/article/details/41724355 事务管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的 ...
随机推荐
- Java 内部类详解
什么 定义在一个类内部的类,称为内部类(累不累),如下: public class A { private int c = 1; public class C { public void test() ...
- 阿里云开发之OSS数据迁移
最近由于项目需求,需要将一个aliyun账号下的oss数据导入到两一个aliyun账号下的oss,经过一番坎坷,最终搞定. 1.查看oss数据迁移官方文档,我是在本地windows电脑上进行操作的,先 ...
- .net程序员必知必会
1.C#,.Net和ASP.Net的区别: C#(Csharp): .net平台下的一种语言:注:(其他语言也可以开发.Net程序) .net : ...
- 自学html5要花多长时间
自学html5培训课程对于没有基础的那么就需要从头开始学,主要包括以下几方面 1. PC端网页制作基础,包括css,html 2. Javascript.jquery 主要是写一些动效 3. 学习UI ...
- Hadoop伪分布安装配置
安装环境: 系统:Ubuntu 14.10 64bit hadoop:2.5.1 jdk:1.8.0_11 安装步骤: 一.安装JDK 安装 jdk,并且配置环境以及设置成默认 sudo gedi ...
- 在.NET项目中使用PostSharp,使用MemoryCache实现缓存的处理(转)
在之前一篇随笔<在.NET项目中使用PostSharp,实现AOP面向切面编程处理>介绍了PostSharp框架的使用,试用PostSharp能给我带来很多便利和优势,减少代码冗余,提高可 ...
- 【Ruby on Rails】Model中关于保存之前的原值和修改状态
今天在Rails的Model中遇到了一个问题—— 当我从Model类中获取了一个ActiveRecord对象,对其进行了一系列修改(尚未保存),我该如何确定究竟哪些修改了呢? (设Model为Opti ...
- 1121: [POI2008]激光发射器SZK
1121: [POI2008]激光发射器SZK Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 574 Solved: 475[Submit][Sta ...
- iOS截屏保存至相册
#pragma mark 截屏并保存至相册 -(void)screenShotsComplete:(void(^)(UIImage * img)) complete { CGSize imageSiz ...
- 求助,如何干掉这个不要脸的“流氓”
问题 chrome 第一次打开时,被一个加"7654 导航"的网站捆绑. 查看设置中启动页中,被设置如下: 解决 域名查看,阿里竟然为这样的网站搞隐私保护 尝试 安 ...