赞
踩
有很多人觉得我们有了Spring,就再也不需要去处理获得连接、事务提交、回滚和关闭连接等这些操作了,其实并不是这样的,事实上Spring并不是直接管理事务的,只是提供了多种事务管理器,让持久化机制所提供的平台框架的事务来实现事务管理。
Spring事务管理的三大接口底层的实现关系如图所示:
三者的关系非常清晰,TransactionDefinition 将 Transaction 传给 PlatformTransactionManager ,TransactionStatus 又从PlatformTransactionManager 得到Transaction 。
具体的PlatformTransactionManager实现类又有4种,它们是针对不同的数据库或者框架而定制的。包括:
Spring事务管理主要包括3个接口,Spring的事务主要是由他们三个共同完成的,分别是:PlatformTransactionManager,TransactionDefinition,TransactionStatus。其中的PlatformTransactionManager是Spring事务管理的核心接口!这三个事务管理器接口是根据指定的传播行为,返回当前活动的事务,或者创建一个新的事务,参数的类定义一些基本的事务属性。
第一个接口是PlatformTransactionManager,是Spring事务管理的核心接口。主要功能是事务管理器,是用于平台相关事务的管理,包括commit 事务的提交;rollback 事务的回滚;getTransaction 事务状态的获取三种方法。
第二个接口是TransactionDefinition,主要功能是事务定义信息,是用来定义事务相关的属性,给事务管理器PlatformTransactionManager使用的。而且在TransactionDefinition接口中定义了它自己的传播行为和隔离级别。包括getIsolationLevel:获取隔离级别;getPropagationBehavior:获取传播行为;getTimeout:获取超时时间;isReadOnly:是否只读 四种方法。
第三个接口是TransactionStatus,主要功能是事务具体运行状态,是事务管理过程中,每个时间点事务的状态信息,它可以封装许多代码,节省我们的工作量。包括hasSavepoint():返回这个事务内部是否包含一个保存点;isCompleted():返回该事务是否已完成,也就是说,是否已经提交或回滚;isNewTransaction():判断当前事务是否是一个新事务 这三种方法。
看完以上的三个接口,那么你知道Spring是如何配置事务管理器的吗?
通过PlatformTransactionManager实现来进行事务管理。这种方式在实际开发中,很少使用,基本都是使用声明式事务管理。
<!--配置事务管理的模板-->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transacationManager />
<property name="isolationLevelName" value="ISOLATION_DEFAULT" />
<property name="propagationBeHaviorName" value="PROPAGETION_REQUIRED" />
</bean>
声明式事务管理有又有两种不同的方式:一种是基于tx和aop命名空间的xml配置文件,也称配置Aspectj方式的声明式事务,另一种是使用注解的声明式事务
步骤:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.2</version> </dependency>
需要使用的命名空间有tx和aop。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
">
<!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManag er"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务通知 --> <tx:advice id="tx" transaction-manager="transactionManager"> <tx:attributes> <!-- name:表示以什么开头的方法 --> <!-- propagation:传播行为 --> <!-- isolation:隔离级别 --> <tx:method name="add*" propagation="REQUIRED" isolation="DEFAULT" /> <tx:method name="insert*" propagation="REQUIRED" isolation="DEFAULT" /> <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" /> <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" /> <tx:method name="del*" propagation="REQUIRED" isolation="DEFAULT" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="tx-point" expression="execution(* com.golden3young.service..*.*(..))" /> <aop:advisor advice-ref="tx" pointcut-ref="tx-point" /> </aop:config>
关于代码中的execution(* com.golden3young.service….(…)),解释一下是什么意思。这是一个表达式:开头的 * 表示 任意方法权限修饰符, com.golden3young.service… 表示com.golden3young.service包及其所有子包下的内容,至于是什么内容,由紧接着的 *. *(…)来指定,意思是任意类型下的任意方法。(…)表示任意的方法参数
重点就是 一个 * 表示当前层级的所有 , 两个 * 表示当前层级和所有子层级
步骤:
<!-- 事务管理器 -->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManag er">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置注解扫描驱动,用于自动扫描写在代码中的注解 -->
<tx:annotation-driven transaction-manager="tx" />
根据配置的代码可以看出来,依赖于命名空间tx,所以也需要提前引入。
@Transactional
@Override
public int addUser(User user) {
return userMapper.addUser(user);
}
例如,在Service层中调用dao层方法的时候,我们就可以直接使用@Transactional注解,Spring容器将自动进行扫描,为我们构建对应的事务管理。
知道了事务具体的配置方法,那么下面我们再来研究一下,在配置过程中,可以配置的参数都用哪些,以及对应着哪些功能。
spring提供了五种隔离级:
当多个具有事务的方法直接存在依赖关系时,事务是如何传播的呢?我们可以进行设置。
解释:
method A(){
methodB();
}
method B(){
}
如果A方法和B方法的事务传播行为都是 REQUIRED 等级,方法A中调用了方法B,那么如果A和B都有事务,B将加入到A的事务中。如果A没有事务,而B有事务,B将创建自己的事务。
method A(){
methodB();
}
method B(){}
如果A\B都有事务 --B 将暂停A的事务
如果A没有事务,B有事务 ---B 将创建自己的事务
method A(){
methodB();
}
method B(){}
如果A\B都有事务 --B 将加入到A 的事务中
如果A没有事务,B有事务 ---B 将不使用任何事务
method A(){ //
methodB();
}
method B(){}
不管A有没有事务,B都不用。A如果有,B就给它暂停,如果没有那正好。
method A(){
methodB();
}
method B(){ //PROPAGATION_MANDATORY
}
如果方法B的事务传播等级为MANDATORY
那它必须以事务的方式运行
调用的地方必须要有事务,如果没有事务,B将直接抛异常
method A(){ //
methodB();
}
method B(){ //
}
必须以没有事务的方式运行
调用的地方必须没有事务,如果有事务,B将直接抛异常
也就是在注解的括号中,增加了propagation属性和isolation属性并赋值。
Java的世界里,有两种异常:运行时异常和非运行时异常。根据名字即可轻松的辨别出它们的区别。
运行时异常是在代码运行过程中出现的例外情况。运行时异常是不需要捕获的,程序员可以不去处理,当异常出现时,虚拟机会处理,当然如果虚拟机处理不了,最终还是得程序员去处理。
非运行时异常(也叫checked异常)就必须得捕获了,否则连编译都不过去,java编译器要求程序员必须对这种异常进行catch,Java认为Checked异常都是可以被处理(修复)的异常,所以Java程序必须显式处理Checked异常。
在处理非运行时异常时,有两种处理办法:一种是抛给上级,一种是try-catch自己消化掉。
在spring事务的回滚机制中,其作用就是当指定的方法抛出异常时,会触发事务的回滚机制,来将刚才对数据库的修改进行回滚。
默认情况下,Spring只有在抛出的异常是运行时异常(“非检查型”)时才回滚该事务; 也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚); 而抛出非运行时异常(检查型)则不会导致事务回滚; 但是,我们可以明确的配置抛出哪些异常时回滚事务,包括checked异常。也可以定义哪些异常抛出时不回滚事务。
我们再来将刚才那个注解,添加上回滚机制中的属性和属性值:
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class, noRollbackFor = XxxExcetion.class )
所谓Spring事务,也就是将数据库中的事务放到了Spring中,其实Spring是整合了一下各种数据库中的事务,将不同数据库中的事务进行总结,这样,一旦使用了Spring框架,就可以直接将事务管理交给Spring来处理,不再需要像之前面向数据库来自己处理事务。既然数据库的种类繁多,各数据库中的事务种类又各不相同,所以在整合过程中,就存在着多种情况,这就是为什么在本文一开头就介绍了Spring事务的底层接口和实现类,以及它们直接是如何进行工作的。随后,由于事务处理中,有各种属性,如:隔离级别、传播行为、回滚机制,所以,我们在使用spring管理事务的时候,可以通过属性+属性值来进行设置,剩下的工作就全部交给Spring去帮助我们完成。配置Spring事务的方法又有两种,编程式和声明式,一般在实际开发中,使用声明式居多,同时,Aspectj方式在springmvc中使用较多,注解方式在springboot中使用较多。不过,这都不是固定的,在掌握了不同的配置方法后,如何配置完全由自己决定,当然,我们都偏爱简洁迅速的方式。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。