文档章节

spring中的事务

A__17
 A__17
发布于 2017/08/03 01:08
字数 1696
阅读 4
收藏 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
博文 100
码字总数 117532
作品 0
朝阳
私信 提问
Spring 事务管理高级应用难点剖析: 第 1 部分

Spring 最成功,最吸引人的地方莫过于轻量级的声明式事务管理,仅此一点,它就宣告了重量级 EJB 容器的覆灭。Spring 声明式事务管理将开发者从繁复的事务管理代码中解脱出来,专注于业务逻辑...

红薯
2010/03/28
1K
2
Spring的事务管理难点剖析(3):事务方法嵌套调用的迷茫

Spring事务传播机制回顾 Spring事务一个被讹传很广说法是:一个事务方法不应该调用另一个事务方法,否则将产生两个事务。结果造成开发人员在设计事务方法时束手束脚,生怕一不小心就踩到地雷...

icheer
2012/07/17
0
0
day35_Spring学习笔记_03

一、事务管理 1.1、回顾事务 事务:一组业务操作ABCD,要么全部成功,要么全部不成功。 特性:ACID 原子性:整体 一致性:完成 隔离性:并发 持久性:结果 隔离问题: 脏读:一个事务读到另一...

黑泽明军
08/08
0
0
Spring AOP 日志拦截器的事务管理

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

哲别0
05/18
0
0
Spring的事务管理实现原理初探

这里主要是通过分析部分源码进行剖析Spring事务管理的实现原理。 再分析源码前,现从理论上大概分析哈: 纯JDBC操作数据库的基本步骤: 1. 获取连接 Connection conn = DriverManager.getCon...

rockypeng
2014/01/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

BigDecimal 比较大小

通过BigDecimal的compareTo方法来进行比较。 返回的结果是int类型: -1表示小于,0是等于,1是大于

嘴角轻扬30
1分钟前
0
0
PHP实现excel导出

1:前端代码 <div id=‘export’>导出excel表单</div> // //导入excel文件 $("#export").on('click', function(){ $.ajax({ url:"importexcel.php", type:'POST', dataType:'json', data:{}......

葬-花
2分钟前
0
0
内存性能的正确解读

一台服务器,不管是物理机还是虚拟机,必不可少的就是内存,内存的性能又是如何来衡量呢。 1. 内存与缓存 现在比较新的CPU一般都有三级缓存,L1 Cache(32KB-256KB),L2 Cache(128KB-2MB)...

阿里云官方博客
4分钟前
0
0
《边缘云计算技术及标准化白皮书》

12月12日,第八届中国云计算标准和应用大会在北京隆重召开,工业和信息化部党组成员,总工程师张峰先生,中国工程院副院长陈左宁女士,中国工程院院士沈昌祥先生,中国电子技术标准化研究院院...

阿里云云栖社区
5分钟前
0
0
iOS 官方文档

https://developer.apple.com/library/prerelease/content/navigation/#section=Platforms&topic=iOS...

walking_yxf
19分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部