一, 事务的一些基础知识简单回顾一下,讲的不是很深入,网上博客很多。

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事务在实际项目开发中的使用的更多相关文章

  1. 团队项目开发中,常见的版本控制有svn,git

    团队项目开发中,常见的版本控制有svn,git

  2. 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获

    项目开发中的一些注意事项以及技巧总结   1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...

  3. Angular 项目开发中父子组件传参

    在项目开发中经常会遇到 组件之间传参的问题.今天总结下在使用angular的项目中父子组件传参的问题: 1.父组件向子组件传参: 然后在父组件中 然后在父组件的html中 然后就可以在子组件中使用了 ...

  4. 《Maven在Java项目开发中的应用》论文笔记(十七)

    标题:Maven在Java项目开发中的应用 一.基本信息 时间:2019 来源:山西农业大学 关键词:Maven:Java Web:仓库:开发人员:极限编程; 二.研究内容 1.Maven 基本原理概 ...

  5. 炼金术(1): 识别项目开发中的ProtoType、Demo、MVP

    软件开发是很分裂的,只有不断使用原则和规律,才能带来质量. 只要不是玩具性质的项目,项目应该可以大概划分为0-1,1-10,10-100,100-1000四个种重要阶段.其中,0-1是原型验证性的:1 ...

  6. 项目开发中的git简单使用

    原文地址: https://www.zhuyilong.fun/tech/the-blog-git.html 示例远程仓库地址: https://github.com/zhu-longge/gitWo ...

  7. MyBatis 项目开发中是基于 XML 还是注解?

    只要你对 MyBatis 有所认识和了解,想必知道 MyBatis 有两种 SQL 语句映射模式,一种是基于注解,一种是基于XML. 基于 XML <mapper namespace=" ...

  8. Java项目开发中实现分页的三种方式一篇包会

    前言   Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBatis两种框架,这两种框架都提供了相应的分页工具,使用 ...

  9. 项目开发中Maven的单向依赖-2022新项目

    一.业务场景 工作多年,在真实的项目开发中经常会遇到将一个项目拆分成多个工程的情况,比如将一个真实的项目拆分成controller层,service层, dao层,common公共服务层等等.这样拆分 ...

随机推荐

  1. ServiceFabric极简文档-2 部署环境搭建-配置文件

    类型:ClusterConfig.Unsecure.MultiMachine 说明:至少3台机子 { "name": "SampleCluster", &quo ...

  2. infiniband 网卡驱动安装

    硬件:Mellanox InfiniBand,主要包括 HCA(主机通道适配器)和交换机两部分软件:CentOS 6.4MLNX_OFED_LINUX-2.1-1.0.0-rhel6.4-x86_64 ...

  3. 【拓扑排序】威虎山上的分配-C++

    威虎山上的分配 描述 每年过年的时候,座山雕都会给兄弟们分银子,分银子之前,座山雕允许大伙儿发表意见,因为要是没法满足所有人的意见,指不定谁要搞出什么大新闻.不过每个人在提意见的时候只能说:" ...

  4. ItemsControl绑定的数据模板显示不同样式:模板选择器

    总所周知,wpf提供了数据模板,列表控件可以绑定数据实现批量显示同类型数据.不过同个数据模板显示不同的样式怎么办?这时我们可以用模板选择器. 首先我们可以将数据绑定到首先定义资源样式 <Data ...

  5. MySQL常见操作指令

    1:使用SHOW语句找出在服务器上当前存在什么数据库: mysql> SHOW DATABASES; 2:创建一个数据库MYSQLDATA mysql> CREATE DATABASE M ...

  6. 渐进式web应用开发---promise式数据库(五)

    在前面的一篇文章中,我们已经实现了使用indexedDB实现ajax本地数据存储的功能,详情,请看这篇文章.现在我们需要把上面的一篇文章中的代码使用promise结构来重构下.我们为什么需要使用pro ...

  7. HTTPS协议学习笔记

    在前一段时间准备面试的时候,面试官反复提到了HTTPS这个协议.我只是单纯的知道,HTTPS是安全的应用层协议 是HTTP更安全的版本,通过对称密钥加密.但是具体的其他的,可能我不太了解.今天就专门抽 ...

  8. Socket 连接问题之大量 TIME_WAIT

    简评:最近项目就出现了大量短连接导致建立新连接超时问题,最后是通过维护长连接解决的. 代理或者服务器设备都有端口限制,如果使用 TCP 连接,连接数量达到端口限制,在这种情况下,将不能创建新的连接. ...

  9. 将个人网站主页设置为Tomcat默认打开页面

    步骤: 1.打开server.xml,在</Host>的上一行添加内容格式如下 <Context path="" reloadable="true&qu ...

  10. 《VR入门系列教程》之17---发布第一个应用

    发布运行     Unity可以支持多种目标平台的发布,包括:桌面端.Web端.移动端.游戏主机端.     发布运行之前的Cubes场景至桌面端,我们先选择File->Build Settin ...