文档章节

spring中的事务

A__17
 A__17
发布于 2017/08/03 01:08
字数 1696
阅读 4
收藏 0
点赞 0
评论 0

1)spring的事务管理器:

package org.springframework.transaction;

public interface PlatformTransactionManager {

	TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;

	void commit(TransactionStatus status) throws TransactionException;

	void rollback(TransactionStatus status) throws TransactionException;
}

2)spring的事务定义类:

package org.springframework.transaction;
import java.sql.Connection;

public interface TransactionDefinition {

	// 事务的传播行为
	int PROPAGATION_REQUIRED = 0;		// 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。											
	int PROPAGATION_SUPPORTS = 1;		// 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
	int PROPAGATION_MANDATORY = 2;		// 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
	int PROPAGATION_REQUIRES_NEW = 3;	// 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
	int PROPAGATION_NOT_SUPPORTED = 4;	// 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
	int PROPAGATION_NEVER = 5;			// 以非事务方式运行,如果当前存在事务,则抛出异常。
	int PROPAGATION_NESTED = 6;			// 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则等价于PROPAGATION_REQUIRED。

	
	// 事务的隔离级别
	int ISOLATION_DEFAULT = -1;			// 使用底层数据库的默认隔离级别。
	int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
	int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
	int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
	int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;

	/**
	 * Use the default timeout of the underlying transaction system, or none if timeouts are not supported.
	 */
	// 事务超时:指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。
	// 默认为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。
	int TIMEOUT_DEFAULT = -1;

	int getPropagationBehavior();

	int getIsolationLevel();

	int getTimeout();

	boolean isReadOnly();

	String getName();
}

3)spring中事务的回滚:

1)spring推荐以抛出异常的方式来回滚一个事务。
2)spring事务管理器会捕捉任何未处理的异常,然后根据相应的配置来判断是否回滚抛出异常的事务。
	1>默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。
	2>可以配置在抛出哪些异常时回滚事务,包括checked异常;也可以明确设置哪些异常抛出时不回滚事务。

4)@Transactional注解

属性					类型							描述
value					String				可选的限定描述符,指定使用的事务管理器
propagation				enum 				可选的事务传播行为设置
isolation				enum 				可选的事务隔离级别设置
readOnly				boolean				读写或只读事务,默认读写
timeout					int 				(in seconds granularity)事务超时时间设置

rollbackFor				(继承Throwable的)Class数组		导致事务回滚的异常类数组
rollbackForClassName	(继承Throwable的)类名数组		导致事务回滚的异常类名字数组
noRollbackFor			(继承Throwable的)Class数组		不会导致事务回滚的异常类数组
noRollbackForClassName	(继承Throwable的)类名数组		不会导致事务回滚的异常类名字数组

用法:可以写在类(接口)上,也可以方法上。
	1)当作用于类上时,该类的所有public方法将都具有该类型的事务属性。
	2)可以在方法上使用该注解来覆盖类级别上的设置。
	3)Spring建议不要在接口或接口方法上使用该注解,因为只有在使用基于接口的代理时它才会生效。
	4)在private、protected、default的方法上使用该注解,则该注解将被忽略,也不会抛出任何异常。
	5)默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是说:类内部方法调用本类内部的其它方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰!

5)原理:

1)spring的事务管理是通过spring的AOP(动态代理)来实现的。

	spring中事务生效的一个前提:调用的方法必须被TransactionInterceptor拦截。
		说明:只有通过TransactionInterceptor拦截的方法才会被加入到spring的事务管理中。
		举例:
			在方法A中调用@Transactional修饰的方法B时,如果方法A与方法B在同一个类TestClass中,则加在方法B上的@Transactional注解不起作用,因为此时方法A对方法B的调用是不会被拦截器拦截的!
			解决办法:在方法A中,使用当前的代理对象来调用方法B。eg:((TestClass)AopContext.currentProxy()).B();

2)对于正常的事务管理,必须关闭数据库的自动提交模式,spring会将底层连接的自动提交特性设置为false。

	package org.springframework.jdbc.datasource;
	public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {

		private DataSource dataSource;

		/**
		 * This implementation sets the isolation level but ignores the timeout.
		 */
		[@Override](https://my.oschina.net/u/1162528)
		protected void doBegin(Object transaction, TransactionDefinition definition) {
			DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
			Connection con = null;

			try {
				if (txObject.getConnectionHolder() == null || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
					Connection newCon = this.dataSource.getConnection();
					if (logger.isDebugEnabled()) {
						logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
					}
					txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
				}

				txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
				con = txObject.getConnectionHolder().getConnection();

				Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
				txObject.setPreviousIsolationLevel(previousIsolationLevel);

				// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
				// so we don't want to do it unnecessarily (for example if we've explicitly
				// configured the connection pool to set it already).
				if (con.getAutoCommit()) {
					txObject.setMustRestoreAutoCommit(true);
					if (logger.isDebugEnabled()) {
						logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
					}
					con.setAutoCommit(false); // 【spring将底层连接的自动提交设置为false】
				}
				txObject.getConnectionHolder().setTransactionActive(true);

				int timeout = determineTimeout(definition);
				if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
					txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
				}

				// Bind the session holder to the thread.
				if (txObject.isNewConnectionHolder()) {
					TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
				}
			}

			catch (Throwable ex) {
				DataSourceUtils.releaseConnection(con, this.dataSource);
				throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
			}
		}
	}

6)配置文件:

1)注解的形式:
	spring + mybatis:
		说明:mybatis会自动参与到spring事务的管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理不起作用。
	
		<!-- 定义事务管理器 -->  
		<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="dataSource" />
		</bean> 
		<!-- 使用注解的形式管理事务 -->  
		<tx:annotation-driven transaction-manager="transactionManager" /> 
	
		<!-- 定义SqlSessionFactory -->
		<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
			<property name="dataSource" ref="dataSource" />
			<property name="configLocation" value="classpath:/mybatis_advertise.xml" />
		</bean>

	spring + hibernate:
		<!-- 事务管理器 -->
		<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
			<property name="sessionFactory" ref="sessionFactory" />
		</bean>
		<!-- 使用注解的形式管理事务 -->
		<tx:annotation-driven transaction-manager="transactionManager"/>

		<!-- 定义SessionFactory -->  
        <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
			<property name="dataSource" ref="dataSource" />
            <property name="configLocation" value="classpath:hibernate.cfg.xml" /> 
        </bean>  


2)切面的形式:

	<!-- 定义事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 事务的处理策略:相当于注解形式中的@Transactional注解 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- 设置事务的属性,相当于@Transactional注解的属性 -->
			<tx:method name="query*" read-only="true" />
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="*" /> 
		</tx:attributes>
	</tx:advice>

	<aop:config>
		<!--定义需要使用事务的切入点 -->
		<aop:pointcut id="myPointcut" expression="execution(* com.jxn.mybatis.service.*.*(..))" />
		<!--将事务的处理策略应用到指定的切入点 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" />
	</aop:config>

© 著作权归作者所有

共有 人打赏支持
A__17
粉丝 2
博文 91
码字总数 102581
作品 0
朝阳
Spring AOP 日志拦截器的事务管理

如果要在方法执行前或后或抛出异常后加上一个自己的拦截器,或者一个环绕拦截器,在拦截器中执行一些操作,比如执行一些数据库操作,记录一些信 息,这些操作通过调用一个服务类的方法来执行...

哲别0 ⋅ 05/18 ⋅ 0

@Transaction必知必会

1. Spring事务的基本原理 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式...

maskwang520 ⋅ 04/15 ⋅ 0

spring事务和jdbc事务

Spring事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行: 获取...

TonyStarkSir ⋅ 04/16 ⋅ 0

Spring编程式和声明式事务

1.编程式事务 1.1 编程式和声明式事务的区别 Spring提供了对编程式事务和声明式事务的支持,编程式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP)有助于用户将操作与事务...

梨加橙 ⋅ 06/19 ⋅ 0

Spring 中常用的两种事务配置方式以及事务的传播性、隔离级别

一、注解式事务 1、注解式事务在平时的开发中使用的挺多,工作的两个公司中看到很多项目使用了这种方式,下面看看具体的配置demo。 2、事务配置实例 (1)、spring+mybatis 事务配置 (2)、...

哲别0 ⋅ 04/20 ⋅ 0

基于可靠消息方案的分布式事务(二):Java中的事务

前言:在上一篇文章 基于可靠消息方案的分布式事务:Lottor介绍 中介绍了常见的分布式事务的解决方案以及笔者基于可靠消息方案实现的分布式事务组件Lottor的原理,并展示了应用的控制台管理。...

aoho ⋅ 06/01 ⋅ 0

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

Java面试通关手册(Java学习指南):https://github.com/Snailclimb/JavaGuide 历史回顾: 可能是最漂亮的Spring事务管理详解 Spring事务管理 Spring支持两种方式的事务管理: 编程式事务管理...

snailclimb ⋅ 05/23 ⋅ 0

SpringMVC+Spring事物失效问题

1、spring扫描配置 springmvc扫描配置导致事物失效 一个项目中既有SpringMVC又有Spring 的时候,会发生事物失效问题 原因:使用的spring注解+springMVC注解,默认情况下spring应该先加载appli...

宿小帅 ⋅ 2016/10/12 ⋅ 0

spring声明式事务@Transactional后置,前置处理

想必不少人遇到过这样子的场景,希望在spring的事务完成后do something... 前言: --------------------------------------------------------------------------------------------- 我遇到...

虾几把写 ⋅ 06/12 ⋅ 0

简化SSM搭建详细分析配置

一直使用SSH2 和 spring boot,最近换工作,使用新框架SpringMVC,带着SSH2的思路学习SpringMVC还是挺容易的,下面分享一下SSM的搭建 总体来说搭建SSM分五步 一:创建maven工程 这里是创建m...

红尾巴的猪 ⋅ 2017/11/10 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

行政区划代码转为字典形式

原数据为: http://www.mca.gov.cn/article/sj/xzqh/2018/201804-12/201804-06041553.html 手动替换了一下格式,并使用下面的代码处理. # 输入格式s = """110000:北京市110101:东城区1101...

漫步海边小路 ⋅ 22分钟前 ⋅ 0

android apk 签名

创建key,需要用到keytool.exe (位于C:\Program Files\Java\jdk1.6.0_10\bin目录下),使用产生的key对apk签名用到的是jarsigner.exe (位于C:\Program Files\Java\jdk1.6.0_10\bin目录下),把...

国仔饼 ⋅ 31分钟前 ⋅ 0

springcloud+jps+mybatis多数据库配置

多数据库配置 配置我们目录结构设置: config ---datasource ----jpa ----mybatis ----redis Datasource中是数据的相关配置 Jap中是springDatajpa的相关配置 Mybatis中是mybatis的相关配置 ...

大-智-若-愚 ⋅ 38分钟前 ⋅ 0

Spring mvc HandlerMapping 实现机制

概述 当DispatcherServlet接受到客户端的请求后,SpringMVC 通过 HandlerMapping 找到请求的Controller。 HandlerMapping 在这里起到路由的作用,负责找到请求的Controller。 Spring MVC 默认...

轨迹_ ⋅ 41分钟前 ⋅ 0

JavaScript零基础入门——(十)JavaScript的DOM基础

JavaScript零基础入门——(十)JavaScript的DOM基础 欢迎大家回到我们的JavaScript零基础入门,上一节课,我们了解了JavaScript中的函数,这一节课,我们来了解一下JavaScript的DOM。 第一节...

JandenMa ⋅ 今天 ⋅ 0

Weex起步

本教程假设你已经在你的本地环境安装了node 其实weex起步教程在 https://github.com/lilugirl/incubator-weex 项目说明文件中都已经有了,但为了有些同学看到英文秒变文盲,所以这里我重新写...

lilugirl ⋅ 今天 ⋅ 0

Jenkins实践1 之安装

1 下载 http://mirrors.jenkins.io/war/latest/jenkins.war 2 启动 java -jar jenkins.war 前提:安装jdk并配置环境变量 启动结果节选: ************************************************......

晨猫 ⋅ 今天 ⋅ 0

组合数学 1-2000 中,能被6或10整除的数的个数

1--2000 中,能被6或10整除的数的个数 利用集合的性质 能被6整除的个数 2000/6 = 333 能被10整除的个数 2000/10 = 200 能被6和10整除的个数 2000/30 = 66 能被6或10整除的个数 333+200-66 =...

阿豪boy ⋅ 今天 ⋅ 0

一篇文章学懂Shell脚本

Shell脚本,就是利用Shell的命令解释的功能,对一个纯文本的文件进行解析,然后执行这些功能,也可以说Shell脚本就是一系列命令的集合。 Shell可以直接使用在win/Unix/Linux上面,并且可以调用...

Jake_xun ⋅ 今天 ⋅ 0

大数据工程师需要精通算法吗,要达到一个什么程度呢?

机器学习是人工智能的一个重要分支,而机器学习下最重要的就是算法,本文讲述归纳了入门级的几个机器学习算法,加大数据学习群:716581014一起加入AI技术大本营。 1、监督学习算法 这个算法由...

董黎明 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部