Spring事务管理实现方式之编程式事务与声明式事务详解(转)
原文:https://blog.csdn.net/liaohaojian/article/details/70139151
编程式事务
编码方式实现事务管理(代码演示为JDBC事务管理)
Spring实现编程式事务,依赖于2大类,分别是上篇文章提到的PlatformTransactionManager,与模版类TransactionTemplate(推荐使用)。下面分别详细介绍Spring是如何通过该类实现事务管理。
1)PlatformTransactionManager,上篇文章已经详情解说了该类所拥有的方法,不记得可以回看上篇文章。
事务管理器配置
<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);
}
声明式事务
可知编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现。
声明式事务实现方式主要有2种,一种为通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现,另为一种通过@Transactional实现事务管理实现,下面详细说明2种方法如何配置,已经相关注意点
1)方式一,配置文件如下
<!--
<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>
2)方式二通过@Transactional实现事务管理
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/> //开启事务注解
Spring提供的@Transaction注解事务管理,内部同样是利用环绕通知TransactionInterceptor实现事务的开启及关闭。
使用@Transactional注意点:
如果在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口;
建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是因为如果使用JDK代理机制(基于接口的代理)是没问题;而使用使用CGLIB代理(继承)机制时就会遇到问题,因为其使用基于类的代理而不是接口,这是因为接口上的@Transactional注解是“不能继承的”;
Spring事务管理实现方式之编程式事务与声明式事务详解(转)的更多相关文章
- spring事务的开启方式(编程式和声明式)
1.编程式事务:编码方式实现事务管理(代码演示为JDBC事务管理) Spring实现编程式事务,依赖于2大类,分别是上篇文章提到的PlatformTransactionManager,与模版类Tran ...
- 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 根据自己的学习理解有所调整,用于学习备查. 事务管理对于企 ...
随机推荐
- [Algorithm] Trie data structure
For example we have an array of words: [car, done, try, cat, trie, do] What is the best data structu ...
- [React] Simplify and Convert a Traditional React Form to Formik
Forms in React are not easy. T render() { return ( <React.Fragment> <h2>Regular Maintena ...
- SMTP 协议系列一
解说一下DOS下telnet命令发送邮件 步骤,以我的163邮箱为例 1.開始-->cmd 进入到dos里面 2.输入telnet smtp.163.com 25 C: \Users \Ad ...
- Discuz常见小问题-如何修改favourite图标
1做好一个ico图标之后,直接替换目录下的对应文件即可, 如果没效果刷新浏览器或更新后台CSS缓存.
- CAD批量合并文件
要求:将整饰完成504幅单独的宗地图合并成一张总图,合并后,去掉其他要素,只保留毕合的权属线. 解决: 1.合并dwg文件,除了手工粘贴复制外,最先想到的是插入块,即用Insert命令插入,测试结果可 ...
- 简单通俗讲解DOM
在开始之前先说一点,DOM是非常容易理解的,但是大家说的太官方,让人很是难于理解,我们就用非常简单的语言翻译一遍.加深对DOM的理解,从而对它有一个全面的认识. 什么是DOM DOM的全称是Docum ...
- Oracle多行记录合并自定义函数
在oracle数据库中,进行字段合并,可以使用wm_concat(column)函数,但是在这种方法不被Oracle所推荐,因为WMSYS用户用于Workspace Manager,其函数对象可能因版 ...
- Java从零开始学二十三(集合Map接口)
一.Map接口 Collection.Set.List接口都属于单值的操作,即:每次只能操作一个对象,而Map与它们不同的是,每次操作的是一对对象,即二元偶对象,Map中的每个元素都使用key à v ...
- 利用Session完成用户的登录和注销
用户的登录和注销是最常见的Web应用案例,当一个应用的客户登录了以后,其他所有的会话都得知道这个用户已经登录还很有可能得提取用户的昵称予以显示等等,所以,只有把登录成功的用户的信息放入到Session ...
- iOS 推断设备为iPhone还是iPad
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { self.viewControlle ...