文档章节

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
码字总数 117418
作品 0
朝阳
day35_Spring学习笔记_03

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

黑泽明军
08/08
0
0
Spring的事务管理难点剖析(3):事务方法嵌套调用的迷茫

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

icheer
2012/07/17
0
0
Struts2+Spring+Hibernate3集成

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hxdeng/article/details/52278238 1. 加入Struts2,Hibernate3.3,Spring3.3 和数据库驱动包 注意:当有包重复...

降龙十八腿
2016/08/22
0
0
Spring 声明式注解事务实现机制

Spring中注解事务实现机制 在使用@Transactional 注解管理事务时步骤很简单。但是如果对@Transactional理解不够透彻,很容易出现事务不起作用的情况。所以,在对@Transactional的实现机制要有...

狂奔的熊二
09/21
0
0
Spring的事务管理实现原理初探

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

rockypeng
2014/01/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

初级开发-编程题

` public static void main(String[] args) { System.out.println(changeStrToUpperCase("user_name_abc")); System.out.println(changeStrToLowerCase(changeStrToUpperCase("user_name_abc......

小池仔
今天
6
0
现场看路演了!

HiBlock
昨天
18
0
Rabbit MQ基本概念介绍

RabbitMQ介绍 • RabbitMQ是一个消息中间件,是一个很好用的消息队列框架。 • ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。Connection是RabbitMQ的s...

寰宇01
昨天
10
0
官方精简版Windows10:微软自己都看不过去了

微软宣布,该公司正在寻求解决方案,以减轻企业客户的Windows 10规模。该公司声称,企业客户下载整个Windows 10文件以更新设备既费钱又费时。 微软宣布,该公司正在寻求解决方案,以减轻企业...

linux-tao
昨天
19
0
TypeScript基础入门之JSX(二)

转发 TypeScript基础入门之JSX(二) 属性类型检查 键入检查属性的第一步是确定元素属性类型。 内在元素和基于价值的元素之间略有不同。 对于内部元素,它是JSX.IntrinsicElements上的属性类型...

durban
昨天
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部