猿蜕变16——一文搞懂Spring事务花式玩法
看过之前的蜕变系列文章,相信你对事务有了应用方面的认识。但是这些要完成你的蜕变还不够,考虑到大家的基础知识,我们继续回到spring的话题上来,我们一起聊一聊Spring在事务中的花式玩儿法。
曾经学渣很多年的猿人君知道你的记性不是太好,经常学完一个忘记了另一个,如果你不了解事务,或者说看的过程中有不理解的地方,建议你先可以看看猿思考系列6——事务也就那么回事儿,复习下,原理搞懂,使用只是花拳绣腿一般容易。
我们先说说侵入式编码的方式,虽然很多人会吐槽说,有配置了balabalabala....但是侵入式的编码可以解决一些配置无法做到的事情,应用范围依然广泛。
spring提供了PlatformTransactionManager接口,给编程人员控制事务相关了操作,一般情况下,我们会用到以下两个实现类来完成对事务的控制操作:
DataSourceTransactionManager:使用JDBC 或 myBatis 操作数据库时使用。
HibernateTransactionManager:使用Hibernate 进操作数据库时使用。
我们再看看Spring的事务管理办法。Spring事务管理事务的默认方式:程序发生运行时异常时回滚,程序发生一般性异常时提交。针对一般性的异常,我们也可以手动处理,设置为回滚。
异常分类:
运行时异常:程序在运行时才会产生的异常,是RuntimeException的子类,比如NullPointerException等异常。
一般性异常:在编写代码时必须处理的异常,若不处理,则无法通过编译,比如IOException等等。
隔离性(注意噢,隔离性首先数据库支持才会有哈,否则然并卵)属性的支持均是以 ISOLATION_开头。例如 :
ISOLATION_DEFAULT:使用 数据库 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ(可重复读);Oracle默认为 READ_COMMITTED(已提交读)。
ISOLATION_READ_UNCOMMITTED:未提交读。解决不了任何事务并发问题。
ISOLATION_READ_COMMITTED:已提交读。解决脏读问题,存在不可重复读和幻读。
ISOLATION_REPEATABLE_READ:可重复读。解决脏读问题、不可重复读问题,存在幻读
ISOLATION_SERIALIZABLE:串行化。解决脏读问题、不可重复读问题,幻读的问题,效率低。
事务的传播行为指的是一段程序中,存在不同事务的相互调用行为时,在程序执行期间Spring对于事务的处理策略。比如,A 事务中的方法 t1()调用 B 事务中的方法 t2(),在调用执行期间Spring对于事务的处理策略,就称为事务传播行为。事务传播行为是定义在方法上的。事务传播行为常量都是以 PROPAGATION_ 开头,例如:
PROPAGATION_REQUIRED 指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中;若当前没有事务,则创建一个新事务。这种传播行为是最常见的也是 Spring 默认的事务传播行为。如该传播行为加在 doOther()方法上。若 doSome()方法在调用 doOther()方法时就是在事务内运行的,则 doOther()方法的执行也加入到该事务内执行。若 doSome()方法在调用doOther()方法时没有在事务内执行,则 doOther()方法会创建一个事务,并在其中执行。
PROPAGATION_SUPPORTS 指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行。
PROPAGATION_MANDATORY 指定的方法必须在当前事务内执行,若当前没有事务,则直接抛出异常。
PROPAGATION_REQUIRES_NEW 总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕。
PROPAGATION_NOT_SUPPORTED 指定的方法不能在事务环境中执行,若当前存在事务,就将当前事务挂起。
PROPAGATION_NEVER 指定的方法不能在事务环境下执行,若当前存在事务,就直接抛出异常。
PROPAGATION_NESTED 指定的方法必须在事务内执行。若当前存在事务,则在嵌套事务内执行;若当前没有事务,则创建一个新事务。
常量 TIMEOUT_DEFAULT 定义了事务默认的超时时间,即一个事务最多被执行多长时间,一般情况下,都有程序的整体性能要求,很多时候不会超过30秒,这个值是秒级单位,推荐设置为30s.当然,如果你希望没有限制,也可以使用默认值 -1。
使用xml配置事务
配置事务管理器和数据源,数据源使用在spring-mybatis.xml文件中的配置的数据源即可。
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource"ref="dataSource" />
</bean>
配置事务管理的AOP增强属性,事务的传播使用REQUIRED,name表示要添加事务的方法,其中*表示通配符。(重点来了噢,AOP哈,不了解原理的,自己回去看看,猿蜕变14——一文搞懂AOP的套路和猿蜕变15——一文搞懂Spring AOP的正确姿势以及猿思考的猿思考系列5——一文明白java和微商那点儿事儿)
<!-- 事务管理AOP增强 -->
<tx:advice id="txAdvice"transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*"propagation="REQUIRED" />
<tx:method name="insert*"propagation="REQUIRED" />
<tx:method name="add*"propagation="REQUIRED" />
<tx:method name="create*"propagation="REQUIRED" />
<tx:method name="delete*"propagation="REQUIRED" />
<tx:method name="update*"propagation="REQUIRED" />
<tx:method name="find*"propagation="SUPPORTS" read-only="true"/>
<tx:method name="select*"propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*"propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
配置切面,这里的切入点要注意是在service层
<!-- 切面 -->
<aop:config>
<!--切入点必须是在service层-->
<aop:advisor advice-ref="txAdvice"
pointcut="execution(*com.pz.web.study.ssm.service.*.*(..))" />
</aop:config>
使用注解配置事务
Spring 也提供了注解的方式来使用事务,使用注解的方式管理事务时,此时只需要在spring-tx.xml配置事务管理器和事务驱动即可:
<!-- 事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源 -->
<property name="dataSource"ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
最后在需要使用事务的类上或者时方法上使用@Transactional注解即可,需要注意的是,@Transactional只能用于public 方法上。如果标记在其 public方法上,程序不会报错,但是Spring不会将指定事务的管理方式织入到该方法中。
@Transactional中的属性如下:
§ propagation :用于设置事务传播属性。该属性类型为 Propagation 枚举,默认值为Propagation.REQUIRED。
§ isolation :用于设置事务的隔离级别。该属性类型为 Isolation 枚举,默认值为Isolation.DEFAULT。
§ readOnly:用于设置方法对数据库的操作是不是仅仅是读操作。该属性为 boolean,默认值为 false。
§ timeout:用于设置本操作与数据库连接的超时时间。
§ rollbackFor:指定需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
§ rollbackForClassName:指定需要回滚的异常类类名。类型为 String[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
§ noRollbackFor:指定不需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
§ noRollbackForClassName:指定不需要回滚的异常类类名。类型为 String[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
添加在类名上:
@Transactional
public class TravelRouteServiceImpl implements TravelRouteService {
//用在方法上,表示当抛出异常时会进行回滚:
@Override
@Transactional(propagation= Propagation.REQUIRED,rollbackFor = Exception.class)
public void addTravelRoute(TravelRoute travelRoute) {
travelRouteDao.add(travelRoute);
}
- 你真的会玩SQL吗?玩爆你的数据报表之存储过程编写(上)
- 你真的会玩SQL吗?实用函数方法汇总
- 你真的会玩SQL吗?冷落的Top和Apply
- 你真的会玩SQL吗?你所不知道的 数据聚合
- 你真的会玩SQL吗?简单的数据修改
- 将Error异常日志从普通日志中剥离
- 一步一步在Windows中使用MyCat负载均衡 下篇
- Android实现TCP断点上传,后台C#服务实现接收
- Android如何制作漂亮的自适布局的键盘
- 实用收藏Linux命令备忘
- 0基础搭建Hadoop大数据处理-环境
- 如何实现两台服务器间无密码的传输数据和操作
- 一步到位Linux中安装配置MySQL及补坑
- 我是如何处理大并发量订单处理的 KafKa部署总结
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 嵌入式linux之go语言开发(八)存储模块的封装(二)
- 招商银行校招题二
- 小程序工程化系列(一):文件依赖分析
- ucgui在windows上的移植,及为go语言打造简易跨平台GUI的想法
- React setState 是异步执行还是同步执行?
- sm2,sm3,sm4国密算法的纯c语言版本,使用于任何嵌入式平台
- sm2国密算法的纯c语言版本,使用于单片机平台(静态内存分配)
- 面试:mysql 事务和锁的解释
- 【STM32F407开发板用户手册】第35章 STM32F407的FSMC总线应用之驱动AD7606(8通道同步采样, 16bit, 正负10V)
- 玩转easyARM imax283A开发版(二),移植NES模拟器并增加按键驱动,让板子可以玩超级玛丽游戏
- 完了!TCP出了大事!
- redis高并发高可用
- 嵌入式linux之go语言开发(九)关于嵌入式GUI
- docker入门总结,从使用的角度谈起
- 使用 Go 语言开发 Android 应用的正确姿势探索