}

## 2. Spring 事务管理接口介绍
Spring 框架中,事务管理相关最重要的 3 个接口如下:- `PlatformTransactionManager` : (平台)事务管理器,Spring 事务策略的核心。- `TransactionDefinition` : 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。- `TransactionStatus` : 事务运行状态。我们可以把 `PlatformTransactionManager` 接口可以被看作是事务上层的管理者,而 `TransactionDefinition 和 TransactionStatus` 这两个接口可以看作是事物的描述。`PlatformTransactionManager` 会根据 `TransactionDefinition` 的定义比如事务超时时间、隔离界别、传播行为等来进行事务管理 ,而 `TransactionStatus` 接口则提供了一些方法来获取事务相应的状态比如是否新事务、是否可以回滚等等。
### 1)PlatformTransactionManager:事务管理接口
**Spring 并不直接管理事务,而是提供了多种事务管理器** 。Spring 事务管理器的接口是:`PlatformTransactionManager` 。通过这个接口,Spring 为各个平台如 JDBC( `DataSourceTransactionManager` )、Hibernate( `HibernateTransactionManager` )、JPA( `JpaTransactionManager `)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。`PlatformTransactionManager` **接口的具体实现如下:**
![](https://upload-images.jianshu.io/upload_images/25222111-7f456d31d5a95825?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
`PlatformTransactionManager` 接口中定义了三个方法:
```java
package org.springframework.transaction; import org.springframework.lang.Nullable; public interface PlatformTransactionManager { //获得事务 TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException; //提交事务 void commit(TransactionStatus var1) throws TransactionException; //回滚事务 void rollback(TransactionStatus var1) throws TransactionException;
}

这里多插一嘴。为什么要定义或者说抽象出来 PlatformTransactionManager 这个接口呢?

主要是因为要将事务管理行为抽象出来,然后不同的平台去实现它,这样我们可以保证提供给外部的行为不变,方便我们扩展。我前段时间分享过:“为什么我们要用接口?”

2)TransactionDefinition:事务属性

事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition)方法来得到一个事务,这个方法里面的参数是 TransactionDefinition 类 ,这个类就定义了一些基本的事务属性。

那么什么是 事务属性 呢?

事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。

事务属性包含了 5 个方面:

TransactionDefinition 接口中定义了 5 个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等。

package org.springframework.transaction; import org.springframework.lang.Nullable; 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; int ISOLATION_DEFAULT = -1; int ISOLATION_READ_UNCOMMITTED = 1; int ISOLATION_READ_COMMITTED = 2; int ISOLATION_REPEATABLE_READ = 4; int ISOLATION_SERIALIZABLE = 8; int TIMEOUT_DEFAULT = -1; // 返回事务的传播行为,默认值为 REQUIRED。 int getPropagationBehavior(); //返回事务的隔离级别,默认值是 DEFAULT int getIsolationLevel(); // 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。 int getTimeout(); // 返回是否为只读事务,默认值为 false boolean isReadOnly(); @Nullable String getName();
}

3)TransactionStatus:事务状态

TransactionStatus 接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。

PlatformTransactionManager.getTransaction(…)方法返回一个TransactionStatus 对象。

TransactionStatus 接口接口内容如下:

public interface TransactionStatus{ boolean isNewTransaction(); // 是否是新的事物 boolean hasSavepoint(); // 是否有恢复点 void setRollbackOnly(); // 设置为只回滚 boolean isRollbackOnly(); // 是否为只回滚 boolean isCompleted; // 是否已完成
}

3.事务属性详解

实际业务开发中,大家一般都是使用 @Transactional 注解来开启事务,很多人并不清楚这个参数里 面的参数是什么意思,有什么用。为了更好的在项目中使用事务管理,强烈推荐好好阅读一下下面的内容。

1)事务传播行为

事务传播行为是为了解决业务层方法之间互相调用的事务问题。

当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

举个例子!

我们在 A 类的 aMethod()方法中调用了 B 类的 bMethod() 方法。这个时候就涉及到业务层方法之间互相调用的事务问题。如果我们的 bMethod() 如果发生异常需要回滚,如何配置事务传播行为才能让aMethod() 也跟着回滚呢?这个时候就需要事务传播行为的知识了,如果`你不知道的话一定要好好看一下。

Class A { @Transactional(propagation=propagation.xxx) public void aMethod { //do something B b = new B(); b.bMethod(); }
}Class B { @Transactional(propagation=propagation.xxx) public void bMethod { //do something }
}

TransactionDefinition 定义中包括了如下几个表示传播行为的常量:

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; ......
}

不过如此,为了方便使用,Spring会相应地定义了一个枚举类:Propagation

package org.springframework.transaction.annotation; import org.springframework.transaction.TransactionDefinition; public enum Propagation { REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED), SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS), MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW), NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED), NEVER(TransactionDefinition.PROPAGATION_NEVER), NESTED(TransactionDefinition.PROPAGATION_NESTED); private final int value; Propagation(int value) { this.value = value; }public int value() { return this.value; }
}

正确的事务传播行为可能的值如下 :

1_ TransactionDefinition.PROPAGATION_REQUIRED

使用的最多的一个事务传播行为,我们平时经常使用的 @Transactional 注解默认使用就是这个事务传播行为。如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。也就是说:

  1. 如果外部方法没有开启事务的话, Propagation.REQUIRED 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
  2. 如果外部方法开启事务并且被 Propagation.REQUIRED 的话,所有 Propagation.REQUIRED 修饰的内部方法和外部方法均属于同一事务 ,只要一个方法回滚,整个事务均回滚。

举个例子:如果我们上面的 aMethod()bMethod() 使用的都是 PROPAGATION_REQUIRED 传播行为的话,两者使用的就是同一个事务,只要其中一个方法回滚,整个事务均回滚。

Class A { @Transactional(propagation=propagation.PROPAGATION_REQUIRED) public void aMethod { //do something B b = new B(); b.bMethod(); }
}Class B { @Transactional(propagation=propagation.PROPAGATION_REQUIRED) public void bMethod { //do something }
}

2_TransactionDefinition.PROPAGATION_REQUIRES_NEW

创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。

举个例子:如果我们上面的 bMethod() 使用 PROPAGATION_REQUIRES_NEW 事务传播行为修饰,aMethod 还是用 PROPAGATION_REQUIRED 修饰的话。如果 aMethod() 发生异常回滚, bMethod() 不会跟着回滚,因为 bMethod() 开启了独立的事务。但是,如果 bMethod() 抛出了未被捕获的异常并且这个异常满足事务回滚规则的话, aMethod() 同样也会回滚,因为这个异常被 aMethod() 的事务管理机制检测到了。

Class A { @Transactional(propagation=propagation.PROPAGATION_REQUIRED) public void aMethod { //do something B b = new B(); b.bMethod(); }
}Class B { @Transactional(propagation=propagation.REQUIRES_NEW) public void bMethod { //do something }
}

3_TransactionDefinition.PROPAGATION_NESTED:

如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 TransactionDefinition.PROPAGATION_REQUIRED。也就是说:

  1. 在外部方法未开启事务的情况下 Propagation.NESTEDPropagation.REQUIRED 作用相同,修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干扰。
  2. 如果外部方法开启事务的话, Propagation.NESTED 修饰的内部方法属于外部事务的子事务,外部主事务回滚的话,子事务也会回滚,而内部子事务可以单独回滚而不影响外部主事务和其他子事务。

这里还是简单举个例子:

如果 aMethod() 回滚的话, bMethod()bMethod2() 都要回滚,而 bMethod() 回滚的话,并不会造成 aMethod()bMethod() 回滚。

Class A { @Transactional(propagation=propagation.PROPAGATION_REQUIRED) public void aMethod { //do something B b = new B(); b.bMethod(); b.bMethod2(); }
}Class B { @Transactional(propagation=propagation.PROPAGATION_NESTED) public void bMethod { //do something }@Transactional(propagation=propagation.PROPAGATION_NESTED) public void bMethod2 { //do something }
}

4_ TransactionDefinition.PROPAGATION_MANDATORY

如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

这个使用的很少,就不举例子来说了。

若是错误的配置以下 3 种事务传播行为,事务将不会发生回滚,这里不对照案例讲解了,使用的很少。

  • TransactionDefinition.PROPAGATION_SUPPORTS : 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED : 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER : 以非事务方式运行,如果当前存在事务,则抛出异常。

2)事务隔离级别

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

public interface TransactionDefinition { ...... int ISOLATION_DEFAULT = -1; int ISOLATION_READ_UNCOMMITTED = 1; int ISOLATION_READ_COMMITTED = 2; int ISOLATION_REPEATABLE_READ = 4; int ISOLATION_SERIALIZABLE = 8; ......
}

和事务传播行为这块一样,为了方便使用,Spring 也相应地定义了一个枚举类: Isolation

public enum Isolation { DEFAULT(TransactionDefinition.ISOLATION_DEFAULT), READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED), READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED), REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ), SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE); private final int value; Isolation(int value) { this.value = value; }public int value() { return this.value; }
}

下面我依次对每一种事务隔离级别进行介绍:

  • TransactionDefinition.ISOLATION_DEFAULT :使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED :最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • TransactionDefinition.ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
  • TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

因为平时使用 MySQL 数据库比较多,这里再多提一嘴!

MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ可重读)。我们可以通过SELECT @@tx_isolation; 命令来查看,如下:

这里需要注意的是:与 SQL 标准不同的地方在于 InnoDB 存储引擎在 REPEATABLE-READ可重读)事务隔离级别下使用的是 Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如
SQL Server)是不同的。所以说 InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ可重读) 已经可以完全保证事务的隔离性要求,即达到了 SQL 标准的 SERIALIZABLE (可串行化) 隔离级别。

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 READ-COMMITTED (读取提交内容) :,但是你要知道的是 InnoDB 存储引擎默认使用 REPEATABLE-READ可重读) 并不会什么任何性能上的损失。

3)事务超时属性

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒,默认值为-1。

4)事务只读属性

package org.springframework.transaction; import org.springframework.lang.Nullable; public interface TransactionDefinition { ...... // 返回是否为只读事务,默认值为 false boolean isReadOnly();
}

对于只有读取数据查询的事务,可以指定事务类型为 readonly,即只读事务。只读事务不涉及数据的修改,数据库会提供一些优化手段,适合用在有多条数据库查询操作的方法中。

很多人就会疑问了,为什么我一个数据查询操作还要启用事务支持呢?

MySQL 默认对每一个新建立的连接都启用了 autocommit 模式。在该模式下,每一个发送到MySQL 服务器的 sql 语句都会在一个单独的事务中进行处理,执行结束后会自动提交事务,并开启一个新的事务。

但是,如果你给方法加上了 Transactional 注解的话,这个方法执行的所有 sql 会被放在一个事务中。如果声明了只读事务的话,数据库就会去优化它的执行,并不会带来其他的什么收益。

最后

无论是哪家公司,都很重视基础,大厂更加重视技术的深度和广度,面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。

针对以上面试技术点,我在这里也做一些资料分享,希望能更好的帮助到大家。

戳这里免费领取以下资料

来其他的什么收益。

最后

无论是哪家公司,都很重视基础,大厂更加重视技术的深度和广度,面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。

针对以上面试技术点,我在这里也做一些资料分享,希望能更好的帮助到大家。

戳这里免费领取以下资料

[外链图片转存中…(img-Gaikvv7g-1628071671869)]

[外链图片转存中…(img-x5bS7854-1628071671871)]

[外链图片转存中…(img-fmvbxI1J-1628071671872)]

Java开发面试问题,Java中高级核心知识全面解析(10)相关推荐

  1. java file取不到linux文件_Java中高级核心知识全面解析——Linux基本命令(切换、增删改查、压缩文件、权限命令)...

    一.目录切换命令 cd usr: 切换到该目录下usr目录 cd ..(或cd../): 切换到上一层目录 cd /: 切换到系统根目录 cd ~: 切换到用户主目录 cd -: 切换到上一个操作所在 ...

  2. Java中高级核心知识全面解析——常用框架(SpringMVC-工作原理详解)

    一.先来看一下什么是 MVC 模式 MVC 是一种设计模式. MVC 的原理图如下: 二.SpringMVC 简单介绍 SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控 ...

  3. java 数学公式解析框架有哪些_java程序员该如何进阶?这份java中高级核心知识全面解析请收好...

    <Java中高级核心知识全面解析>是整理收录GitHub50K+Star以上的高质量学习文档,前前后后花了近半个月的时间,终于整理而成.包含了Java基础.网络.Linux.数据结构与算法 ...

  4. Java中高级核心知识全面解析

    前言 今天给大家推荐一本PDF文档<Java中高级核心知识全面解析>这份文档总页数:524页.分为八个部分每个部分详细地讲解了核心知识点. 第一部分 扎实的Java基础 ( Java基础+ ...

  5. 呵呵,阿里高工熬夜手写“Java中高级核心知识全面解析”就这?也就让我五体投地的水平!

    前言 先说一下自己的个人情况,大专生,18年通过校招进入湖南金蝶软件公司,干了接近3年的CRUD,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了三 ...

  6. Java中高级核心知识全面解析——什么是Spring Cloud、需要掌握哪些知识点?(下)

    目录 一.必不可少的 Hystrix 1.什么是 Hystrix之熔断和降级 2.什么是Hystrix之其他 二.微服务网关--Zuul 1.Zuul 的路由功能 1)简单配置 2)统一前缀 3)路由 ...

  7. Java程序员必经的实践之路:Java中高级核心知识全面解析(11)

    ThreadPoolTaskExecutor定义一些策略: ThreadPoolExecutor.AbortPolicy:抛出RejectedExecutionException来拒绝新任务的处理. ...

  8. 从CRUD到自身架构师的蜕变之路?全靠这份:Java中高级核心知识全面解析

    Java 入门(基础概念与常识) Java 语法 基本数据类型 方法(函数) 2. Java 面向对象 ============= 类和对象 面向对象三大特征 修饰符 接口和抽象类 其它重要知识点 3 ...

  9. Java中高级核心知识全面解析(3),美团Java面试算法题

    主服务器 需要将自己生成的 RDB 文件 发送给从服务器,这个发送操作会 消耗 主服务器 大量的网络资源 (带宽和流量),并对主服务器响应命令请求的时间产生影响: 接收到 RDB 文件的 从服务器 需 ...

最新文章

  1. Mysql学习之order by的工作原理
  2. 【错误记录】编译 ijkplayer 报错 (fatal error: ijksoundtouch/ijksoundtouch_wrap.h: No such file or directory )
  3. 有趣的MS Live Labs
  4. CountDownLatch应用及原理
  5. input date保存值_涛哥文集(36):R keras保存和还原模型
  6. 吴恩达老师深度学习,结课了
  7. Selenium UI自动化测试(一)环境配置
  8. Anchor 对象学习
  9. 阿里架构师:​程序员必须掌握的几项核心能力
  10. sqlite简单笔记
  11. 解码H264文件的一些基础知识
  12. 【IDEA类注释模板和方法注释模板】
  13. k2p刷机丢失eeprom_刷机经验分享,K2P无线路由器救砖必备,无线和MAC恢复窍门
  14. 闪迪u盘量产工具万能版_加密保护,更高性能!闪迪酷奂CZ74 U盘新品果然够惊艳...
  15. 人脸识别闸机系统解决方案
  16. 使用Struts标签的基本配置
  17. linux应用层读写event,Linux应用层获取鼠标坐标
  18. 46道史上最全Redis面试题
  19. 国家基金申请书撰写的共性问题(转)
  20. SQL Server 2005 Integration Services (SSIS) (3)–Business Intelligence Development Studio (BIDS)

热门文章

  1. opencv jni Android 实例笔记
  2. HRFormer,内存和参数降低40%
  3. TensorBoard logging requires TensorBoard version 1.15 or above
  4. 图像分类、目标检测、语义分割、实例分割和全景分割的区别
  5. dlib win32
  6. PriorBox 改进
  7. Python3 websocket server与client
  8. Opencv 去高光或镜面反射(illuminationChange)
  9. pytorch可视化 resnet50特征图
  10. win10 远程登录-出现身份验证错误[可能是由于CredSSP加密Oracle修正]