spring事务在实际项目开发中的使用
一, 事务的一些基础知识简单回顾一下,讲的不是很深入,网上博客很多。
1,关于事务的四大特性:原子性、隔离性、一致性、持久性 本文不再赘述;
2,事务的隔离级别:读未提交,读已提交,可重复读,串行化(这里应该深入了解各个级别会出现什么问题,比如脏读,不可重复读,幻读)
3,事务的传播行为:事务传播行为指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。 例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的。默认采用:PROPAGATION_REQUIRED

二,接下来我们简单回顾一下java的异常体系:
Throwable 是 Java 语言中所有错误或异常的超类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。
实例分为 Error 和 Exception 两种。
Error 类是指 java 运行时系统的内部错误和资源耗尽错误。应用程序不会抛出该类对象。如果
出现了这样的错误,除了告知用户,剩下的就是尽力使程序安全的终止。
Exception 又有两个分支 , 一个是运行时异常 RuntimeException , 一 个是检查异常 CheckedException。
RuntimeException 如 :NullPointerException 、 ClassCastException ;
CheckedException 如: I/O 错误导致的 IOException、SQLException。
RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。 如果出现 RuntimeException,那么一
定是程序员代码书写导致的错误.
CheckedException:一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强
制程序去捕获此类异常,即会出现要求你把这段可能出现异常的程序进行 try catch
三,言归正传,项目中事务的使用
springboot自动配置默认为我们配置好了事务管理器,参考我们另一篇文章https://www.cnblogs.com/enchaolee/p/11364025.html
我们在项目的实际开发中,对于事务的处理,在编码中无外乎使用@Transactional这个注解,以及对于异常的处理,下面我们详细说一下。
1,方法上加入@Transactional注解后,这个方法就成为了事务方法,如果对于注解的一些属性不做特殊配置的话,方法中如果出现了RuntimeException(运行时异常),事务会进行回滚,如果出现了checkedException(编译时异常),则不会回滚。那么对于这类异常,我们想让他在抛出的时候也进行回滚怎么办呢,当我们点进去@Transactional注解后,看下图:

我们可以看到,图中有标红的两个注解中的属性,我们可以在这里进行手动配置,以实现方法抛出具体异常进行回滚的逻辑。例如我们可以这样配置:@Transactional(rollbackFor = Exception.class);
当然还有两个字段可以设置抛出某某异常不进行回滚:noRollbackFor,noRollbackForClassName;
2,对于异常捕获,事务如何处理
如果我们在事务方法中,手动捕获了异常,并没有让事务抛出去,也没有手动指定需要回滚,那么事务方法即使出现异常,也会提交事务。

比如我们这样去做,只是记录了日志,即使使用rollbackfor=Exception.class制定了需要回滚的逻辑,但是事务仍然会提交,除非加上下面这一行:

有这句代码就不需要再手动抛出运行时异常了,但是不建议这样做,因为这样做代码中会多出很多事务回滚的代码,不利于维护,还是交得spring去处理更妥当。3,的
3,我们该怎么样处理异常回滚呢?

如图所示,CommonException是我们定义的全局异常类,我们可以把catch到的异常统一按照一定的格式进行抛出。下面是CommonException相关代码
public class CommonException extends RuntimeException {
protected String errMsg; // 错误提示信息,显示给用户
protected String detailMsg; // 错误的具体信息,可能包含一些参数ID等信息
protected CommonErrorCode error; // 错误码
protected Object data; // 返回内容
public CommonException(CommonErrorCode error) {
super(error.getDesc());
this.error = error;
this.errMsg = error.getDesc();
this.detailMsg = error.getDesc();
}
public CommonException(CommonErrorCode error, String errMsg) {
super(errMsg);
this.error = error;
this.errMsg = errMsg;
this.detailMsg = errMsg;
}
public CommonException(CommonErrorCode error, String errMsg, String detailMsg) {
super(StringUtils.isEmpty(detailMsg) ? errMsg : detailMsg);
this.error = error;
this.errMsg = errMsg;
this.detailMsg = detailMsg;
}
public CommonException(CommonErrorCode error, String errMsg, Throwable cause) {
super(errMsg, cause);
this.error = error;
this.errMsg = errMsg;
this.detailMsg = errMsg;
}
public CommonException(CommonErrorCode error, String errMsg, String detailMsg, Throwable cause) {
super(StringUtils.isEmpty(detailMsg) ? errMsg : detailMsg, cause);
this.error = error;
this.errMsg = errMsg;
this.detailMsg = detailMsg;
}
public CommonException(CommonErrorCode error, Throwable cause) {
super(error.getDesc(), cause);
this.error = error;
this.errMsg = error.getDesc();
this.detailMsg = error.getDesc();
}
public String getErrMsg() {
return errMsg;
}
public CommonErrorCode getError() {
return error;
}
public String getDetailMsg() {
return detailMsg;
}
public void setDetailMsg(String detailMsg) {
this.detailMsg = detailMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
public Object getData() {
return data;
}
public CommonException setData(Object data) {
this.data = data;
return this;
}
}
4,事务方法调用事务方法,怎么去处理
首先我们先确认一个前提:事务的传播行为我们使用默认的即:required,并且我们假设有两个事务方法a,b;a调用b。
(1)根据上面我们讲过的required的特性,我们知道spring对于这种事务方法间的调用,会默认把它当做一个事务;我们假设如果b中抛出了NullpointException,并且a,b都没有做异常的处理,那么由a,b组成的整个事务肯定都会进行回滚,这是毋庸置疑的。
(2)如果b出现异常,a catch了异常,并且没有抛出去,就像我们上面例子讲的只是记录了日志,我们会发现这个异常,思考一下为什么呢?
我们知道spring 事务管理,启用事务的方法,调用另一个事务方法时,会进行事务传播。注解@Transactional默认的传播机制是PROPAGATION_REQUIRED。再来回顾一下required特性:表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
所以是补齐方法运行的时候,同步的事务合并到了补齐的事务里面。当同步发票发生异常后,被try catch 捕获,没有抛出来。但是事务还是会进行回滚,回滚执行到 DataSourceTransactionManager 类的 doSetRollbackOnly 方法时,设置了rollbackOnly = true;
由于异常被catch, 不阻断整个事务执行。整个事务执行完后,执行commit 提交,我们打开这个抽象类AbstractPlatformTransactionManager看一下commit的逻辑

这里我标红了这个方法,我们继续往下看,我们打开DefaultTransactionStatus这个类,可以看到标红方法的具体实现。

在执行commit 提交逻辑时,执行到 DefaultTransactionStatus 类的 isGlobalRollbackOnly方法时,判断rollbackOnly 为true, 则执行回滚,并且打出那句报错的日志”Transaction rolled back because it has been marked as rollback-only”。
5,需要注意的一些点
(1)事务方法需要标记为public的

(2)@Transactional注解只能写在service中,不能再controller中,否则会报404错误
(3)如果在使用事务的情况下,所有操作都是读操作,那建议把事务设置成只读事务,当事务被标识为只读事务时,Spring可以对某些可以针对只读事务进行优化的资源就可以执行相应的优化措施,需要手动设置成true。但是方法再执行增删改回抛异常。
spring事务在实际项目开发中的使用的更多相关文章
- 团队项目开发中,常见的版本控制有svn,git
团队项目开发中,常见的版本控制有svn,git
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
项目开发中的一些注意事项以及技巧总结 1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...
- Angular 项目开发中父子组件传参
在项目开发中经常会遇到 组件之间传参的问题.今天总结下在使用angular的项目中父子组件传参的问题: 1.父组件向子组件传参: 然后在父组件中 然后在父组件的html中 然后就可以在子组件中使用了 ...
- 《Maven在Java项目开发中的应用》论文笔记(十七)
标题:Maven在Java项目开发中的应用 一.基本信息 时间:2019 来源:山西农业大学 关键词:Maven:Java Web:仓库:开发人员:极限编程; 二.研究内容 1.Maven 基本原理概 ...
- 炼金术(1): 识别项目开发中的ProtoType、Demo、MVP
软件开发是很分裂的,只有不断使用原则和规律,才能带来质量. 只要不是玩具性质的项目,项目应该可以大概划分为0-1,1-10,10-100,100-1000四个种重要阶段.其中,0-1是原型验证性的:1 ...
- 项目开发中的git简单使用
原文地址: https://www.zhuyilong.fun/tech/the-blog-git.html 示例远程仓库地址: https://github.com/zhu-longge/gitWo ...
- MyBatis 项目开发中是基于 XML 还是注解?
只要你对 MyBatis 有所认识和了解,想必知道 MyBatis 有两种 SQL 语句映射模式,一种是基于注解,一种是基于XML. 基于 XML <mapper namespace=" ...
- Java项目开发中实现分页的三种方式一篇包会
前言 Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBatis两种框架,这两种框架都提供了相应的分页工具,使用 ...
- 项目开发中Maven的单向依赖-2022新项目
一.业务场景 工作多年,在真实的项目开发中经常会遇到将一个项目拆分成多个工程的情况,比如将一个真实的项目拆分成controller层,service层, dao层,common公共服务层等等.这样拆分 ...
随机推荐
- shell的用处到底大不大
我曾在智联招聘等网站上搜寻有关shell脚本员的职位,与C++.JAVA等热门语言相比,冷清很多.看上去似乎招shell程序员的公司比较少.是不是公司不重视或者是很少用到shell这个东东呢? ...
- Java编程思想:构建复杂模型
import sun.nio.cs.Surrogate; import java.util.ArrayList; import java.util.Random; public class Test ...
- nginx连接资源管理
本文介绍在nginx中连接资源(即ngx_connection_t)的管理与使用. 连接池的初始化 在ngx_cycle_t结构体中维护了几个和连接相关的数据,具体如下 struct ngx_cycl ...
- weex起步
weex文档地址: http://weex-project.io/cn/guide/index.html weex的文档过于简单,加上js语法 & android & ios本身也有很 ...
- GeoPackage - 一个简便轻量的本地地理数据库
GeoPackage(以下简称gpkg),内部使用SQLite实现的一种单文件.与操作系统无关的地理数据库. 当前标准是1.2.1,该版本的html版说明书:https://www.geopackag ...
- springboot序
springboot序 1.写在前面 (1) 前段时间把文章分了下类(说的是专栏,谈不上),分了三类:springboot.springcloud.mpp数据库greenplum,后来给springc ...
- C#7.2 新增功能
连载目录 [已更新最新开发文章,点击查看详细] C# 7.2 又是一个单点版本,它增添了大量有用的功能. 此版本的一项主要功能是避免不必要的复制或分配,进而更有效地处理值类型. C# 7.2 使 ...
- C#3.0新增功能10 表达式树 04 执行表达式
连载目录 [已更新最新开发文章,点击查看详细] 表达式树 是表示一些代码的数据结构. 它不是已编译且可执行的代码. 如果想要执行由表达式树表示的 .NET 代码,则必须将其转换为可执行的 IL ...
- cve-2018-14515复现
一.环境 Windows NT WIN-RRI9T9SN85D 6.1 build 7600 (Windows 7 Business Edition) i586 Apache/2.4.23 (Win3 ...
- 分析了京东内衣销售记录,告诉你妹子们的真Size!
>今天闲暇之余写了一个爬虫例子.通过爬虫去爬取京东的用户评价,通过分析爬取的数据能得到很多结果,比如,哪一种颜色的胸罩最受女性欢迎,以及中国女性的平均size(仅供参考哦~) 打开开发者工具-n ...