Spring框架面试典籍30+ | 大别山码将

Spring

什么是Spring框架

Spring 是⼀种轻量级(从大小与开销两方面)开发框架,目的是用于简化企业应用程序的开发,它使得开发者只需要 关心业务需求。常见的配置方式有三种:基于 XML 的配置.基于注解的配置. 基 于 Java 的配置

  • Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

  • 从大小与开销两方面而言Spring都是轻量级的。

  • 通过控制反转(IoC)的技术达到松耦合的目的;控制反转(依赖注入)IoC,用白话来讲,就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控,达到松耦合的目的。

  • 提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发(应用对象只实现它们应该做的完成业务逻辑)

  • Spring 属于低侵入式设计,代码的污染极低;

  • 包含并管理应用对象(Bean)的配置和生命周期,这个意义上是一个容器。

  • Spring 对于主流的应用框架提供了集成支持

  • Spring 将对象之间的依赖关系交由框架处理,减低组件的耦合性;

  • Spring 提供了 AOP 技术,支持将一些通用任务,如安全.事务.日志.

    权限等进行集中式管理,从而提供更好的复用

img

Spring 框架是一个分层架构,由 7 个模块组成,使⽤这些模块可以很⽅便地协助我们进⾏开发。组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC 依赖注⼊功能。

Spring Aspects : 该模块为与AspectJ的集成提供⽀持。

Spring AOP :提供了⾯向切⾯的编程实现。

Spring JDBC : Java数据库连接。

Spring JMS :Java消息服务。

Spring ORM : ⽤于⽀持Hibernate等ORM⼯具。

Spring Web : 为创建Web应⽤程序提供⽀持。

Spring Test : 提供了对 JUnit 和 TestNG 测试的⽀持。

@RestController和@Controller

@Controller 返回⼀个⻚⾯

单独使⽤ @Controller 不加 @ResponseBody 的话⼀般使⽤在要返回⼀个视图的情况,这种情况属于⽐较传统的Spring MVC 的应⽤,对应于前后端不分离的情况。

@RestController **返回JSON **或 XML 形式数据

但 @RestController 只返回对象,对象数据直接以 JSON 或 XML 形式写⼊ HTTP 响应(Response)中,这种情况属于 RESTful Web服务,这也是⽬前⽇常开发所接触的最常⽤的情况(前后端分离)

@Controller +@ResponseBody 返回JSON XML 形式数据

如果你需要在Spring4之前开发 RESTful Web服务的话,你需要使⽤ @Controller 并结合 @ResponseBody 注解,也就是说 @Controller + @ResponseBody = @RestController (Spring 4之后新加的注解)。

  • 如果需要返回的是数据(如:JSON、XML或自定义的metatype等数据类型)时:@RestController完全等同于@Controller+@Responsebody,@RestController返回的直接是index字符串(优先)
  • 如果要返回的是jsp、html等页面时两种注解使用方法:@Controller返回的直接是index字符串(优先)

Spring IOC和Aop

IOC:IoC(控制反转)(依赖注入)是⼀种设计思想就是将手动控制对象之间的相互依赖关系交给 IoC 容器(Spring⽤来实现IoC 的载体)来管理并由 IoC 容器完成对象的注⼊。这样可以很⼤程度上简化应⽤的开发,把应⽤从复杂的依赖关系中解放出来。IoC容器就像是⼀个⼯⼚⼀样,当我们需要创建⼀个对象的时候,只需要配置好配置⽂件注解,然后在需要的地⽅引⽤就⾏了,这⼤⼤增加了项⽬的可维护性且降低了开发难度,完全不⽤考虑对象是如何被创建出来的。

AOP:

AOP(⾯向切⾯编程)能够将那些与业务⽆关,却为业务模块所共同调⽤的逻辑或责任(例如事务处理、⽇志管理、权限控制等)封装成一个可重用的模块,便于减少系统的重复代码**,**降低模块间的耦合度,并有利于未来的可拓展性和可维护性。**它使得开发者只需要 关心业务需求。使⽤ AOP 之后我们可以把⼀些通⽤功能抽象出来,在需要⽤到的地⽅直接使⽤即可,这样⼤⼤简化了代码量。**我们需要增加新功能时也⽅便,这样也提⾼了系统扩展性。⽇志功能、事务管理等等场景都⽤到了 AOP

AOP 实现的关键:在于代理模式,AOP 代理主要分为静态代理和动态代理。Spring AOP是基于动态代理实现的,Spring AOP 使用的动态代理,所谓的动态代理就是说 AOP 框架不会 去修改字节码,而是每次运行时在内存中临时为方法生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

静态代理与动态代理区别在于生成 AOP 代理对象的时机不同,其中静态代理是指使用AOP框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于JDK动态代理、CGLIB等在内存中“临时”生成AOP动态代理类,因此也被称为运行时增强。相对来说 AspectJ 的静态代理方式具有更好的性能,但是 AspectJ 需要特定的编译器进行处理,而 Spring AOP 则无需特定的编译器处理。

Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和 CGLIB 动态代理。

  • 如果要代理的对象,实现了某个接⼝,那么Spring AOP会使⽤JDK 动态代理,(只提供接口的代理,不支持类的代理),去创建代理对象
  • 对于没有实现接⼝的对象,那么Spring AOP会选择使用 CGLIB 来动态代理目标类,CGLIB 是通过继承的方式做的 动态代理,因此如果某个类被标记为 final,那么它是无法使用 CGLIB 做动态代理的。

Spring AOP和AspectJ AOP有什么区别?

Spring AOP 属于运⾏时增强(运行时生成代理类),⽽ AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying), ⽽ AspectJ 基于字节码操作(Bytecode Manipulation)。Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java ⽣态系统中最完整的 AOP 框架了。AspectJ 相⽐于 Spring AOP 功能更加强⼤,但是 Spring AOP 相对来说更简单,如果我们的切⾯⽐较少,那么两者性能差异不⼤。但是,当切⾯太多的话,最好选择 AspectJ ,它⽐Spring AOP 快很多。

AOP实现的关键就在于AOP框架自动创建的AOP代理,AOP代理则可分为静态代理和动态代理两大类,其中静态代理是指使用AOP框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于JDK动态代理、CGLIB等在内存中“临时”生成AOP动态代理类,因此也被称为运行时增强相对来说 AspectJ 的静态代理方式具有更好的性能,但是 AspectJ 需要特定的编译器进行处理,而 Spring AOP 则无需特定的编译器处理。

Spring Bean?

Spring 官方文档对 bean 的解释是:

在 Spring 中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是一个由Spring IoC容器实例化、组装和管理的对象。(我们的程序由一个个Bean构成)

bean规范如下:

  1. 所有属性为private
  2. 提供默认构造方法
  3. 提供gettersetter
  4. 实现serializable接口

把Bean理解为类的代理或代言人(实际上确实是通过反射、代理来实现的),这样它就能代表类拥有该拥有的东西了(对象是类的实例)

我们都在微博上**@过某某**,对方会优先看到这条信息,并给你反馈,那么在Spring中,你标识一个@符号,那么Spring就会来看看,并且从这里拿到一个Bean或者给出一个Bean

Spring Bean中的作用域有哪些?

singleton : 默认,唯⼀ bean 实例,Spring 中的 bean 默认都是单例的。

prototype : 每次请求都会创建⼀个新的 bean 实例。

request : 每⼀次HTTP请求都会产⽣⼀个新的bean,该bean仅在当前HTTP request内有效。

session : 每⼀次HTTP请求都会产⽣⼀个新的 bean,该bean仅在当前 HTTP session 内有效。

global-session: 全局session作⽤域,仅仅在基于portlet的web应⽤中才有意义,Spring5已经没有了。Portlet是能够⽣成语义代码(例如:HTML)⽚段的⼩型Java Web插件。它们基于portlet容器,可以像servlet⼀样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话

五种作用域中,request、session和global session三种作用域仅在基于web的应用中使用

  • 当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。
  • 当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
  • 当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。
  • 当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。
  • 当一个bean的作用域为Global Session,表示在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。global session作用域类似于标准的HTTP Session作用域,不过仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。

Spring Bean的生命周期

**对于普通的Java对象,当new的时候创建对象,当它没有任何引用的时候被垃圾回收机制回收。而由Spring IoC容器托管的对象,它们的生命周期完全由容器控制。**Spring中每个Bean的生命周期分为:

实例化属性注入初始化销毁四个主要部分,其余部分相当于使用AOP技术,如果实现了相关接口,才会有这些过程。

img

img

Spring中的单例bean的线程安全问题

**有状态的bean:对象中有实例变量(成员变量),可以保存数据,是非线程安全的 **

无状态的bean:对象中没有实例变量(成员变量),不能保存数据,可以在多线程环境下共享,是线程安全的

⼤部分时候我们并没有在系统中使⽤多线程,所以很少有⼈会关注这个问题。**单例 bean 存在线程问题,主要是因为当多个线程操作同⼀个对象的时候,对这个对象的⾮静态成员变量的写操作会存在线程安全问题。 **

  • 有状态的Bean,多线程环境下不安全,适合使用Prototype原型模式。(Prototype: 每次对bean的请求都会创建一个新的bean实例)每次使用时都会重新生成一个对象,解决了线程不安全的问题 。也可以采用ThreadLocal进行处理,使它们成为线程安全可以共享的对象
  • 在spring中,绝大部分bean都是无状态的,比如controller、service、dao这些类,这些类里面通常不会含有成员变量,因此无状态的Bean适合使用不变模式,即单例模式,这样可以共享实例,提高性能。

常⻅的有两种解决办法:

  1. 在Bean对象中尽量避免定义可变的成员变量(不太现实)。

  2. 在类中定义⼀个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐)

将一个类声明为Spring的bean的注解有哪些?

我们⼀般使⽤ @Autowired 注解⾃动装配 bean,要想把类标识成可⽤于

@Autowired 注解⾃动装配的 bean 的类,采⽤以下注解可实现:

  • @Component :通⽤的注解,可标注任意类为 Spring 组件。如果⼀个Bean不知道属于哪个层,可以使⽤ @Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要⽤于数据库相关操作。
  • @Service : 对应服务层,主要涉及⼀些复杂的逻辑,需要⽤到 Dao层。
  • @Controller : 对应 Spring MVC 控制层,主要⽤户接受⽤户请求并调⽤ Service 层返回数据给前端⻚⾯。

@Component和@Bean的区别

  1. 作⽤对象不同: @Component 注解作⽤于类,⽽ @Bean 注解作⽤于⽅法

  2. @Component 通常是通过类路径扫描来⾃动侦测以及⾃动装配到Spring容器中; @Bean 注解通常是我们在标有该注解的⽅法中定义产⽣这个bean, @Bean 告诉了Spring这是某个类的示例,当我需要⽤它的时候还给我。

  3. @Bean 注解⽐ Component 注解的⾃定义性更强,⽽且很多地⽅我们只能通过 @Bean 注解来注册bean。⽐如当我们引⽤第三⽅库中的类需要装配到 Spring 容器时,则只能通过@Bean 来实现。

    @Component 作用于类上,只有在我们的SpringBoot应用程序启用了组件扫描并且包含了被注解的类时才有效。通过组件扫描,Spring将扫描整个类路径,并将所有@Component注释类添加到Spring Context,这里有的不足就是会把整个类当成bean注册到spring 容器上,如果这个类中并不是所有方法都需要注册为bean的话,会出现不需要的方法都注册成为bean,这时候必须确保这些不需要的方法也能注册为bean或者在扫描中加filter 过滤这些不需要的bean,否者spring将无法成功启动。

    @Bean相对来说就更加灵活了,它可以独立加在方法上,按需注册到spring容器,而且如果你要用到第三方类库里面某个方法的时候,你就只能用@Bean把这个方法注册到spring容器,

什么是Spring MVC

随着 Spring 轻量级开发框架的流⾏,Spring ⽣态圈出现了 Spring MVC 框架, Spring MVC 是当前最优秀的 MVC 框架。相⽐于Struts2 ,Spring MVC 使⽤更加简单和⽅便,开发效率更⾼,并且 Spring MVC 运⾏速度更快。

MVC 是⼀种设计模式,Spring MVC 是⼀款很优秀的 MVC 框架,在实际开发中,接收浏览器的请求响应,对数据进行处理,然后返回页面进行显示。Spring MVC 可以帮助我们进⾏更简洁的Web层的开发,并且它天⽣与 Spring 框架集成。Spring MVC 下我们⼀般把后端项⽬分为 Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层,返回数据给前台⻚⾯)

Spring MVC工作原理

img

流程说明(重要):

  • 1.用户发送请求至 前端控制器DispatcherServlet。
  • 2.前端控制器DispatcherServlet收到请求后调用处理器映射器HandlerMapping。
  • 3.处理器映射器HandlerMapping根据请求的Url找到具体的处理器,生成处理器对象Handler及处理器拦截器HandlerIntercepter(如果有则生成)一并返回给前端控制器DispatcherServlet。
  • 4.前端控制器DispatcherServlet通过处理器适配器HandlerAdapter调用处理器Controller。
  • 5.执行处理器(Controller,也叫后端控制器)
  • 6.处理器Controller执行完后返回ModelAnView。
  • 7.处理器映射器HandlerAdapter将处理器Controller执行返回的结果ModelAndView返回给前端控制器DispatcherServlet。
  • 8.前端控制器DispatcherServlet将ModelAnView传给视图解析器ViewResolver。
  • 9.视图解析器ViewResolver解析后返回具体的视图View。
  • 10.前端控制器DispatcherServlet对视图View进行渲染视图(即:将模型数据填充至视图中)
  • 11.前端控制器DispatcherServlet响应用户。

6个组件:

1.DisPatcherServlet 前端控制器
核心。用户在浏览器输入url,发起请求,首先会到达DisPatcherServlet,由它来调用其他组件来配合工作的完成,DisPatcherServlet的存在大大降低了组件之间的耦合性
2.HandlerMapping 处理器映射器
记录url与处理器的映射,方式有注解、XML配置等
3.HandLer 处理器
后端控制器(通俗一点:Controller层所写的业务代码)。对用户的请求进行处理
4.HandlerAdapter 处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。(我也不太明白)
5.ViewResolver 视图解析器
ViewResolver负责解析view视图,并进行渲染(数据填充),将处理结果通过页面展示给用户看
6.View 视图
View是一个接口,实现类支持不同的View类型(jsp、freemarker、velocity)
一般情况下需要通过页面标签或者页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

Spring框架中用到了哪些设计模式

  • 工厂设计模式 : Spring使用工厂模式通过 BeanFactoryApplicationContext 创建 bean 对象。
  • 代理设计模式 : Spring AOP 功能时与使用JDK的动态代理
  • 单例设计模式 : Spring 中的 Bean 默认都是单例的。
  • 模板方法模式 : 用来解决代码重复的问题,Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
  • 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  • 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
  • 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller
  • ……

单例设计模式在我们的系统中,**有一些对象其实我们只需要一个,**比如说:线程池、缓存、对话框、注册表、日志对象、充当打印机、显卡等设备驱动程序的对象。事实上,这一类对象只能有一个实例,如果制造出多个实例就可能会导致一些问题的产生,比如:程序的行为异常、资源使用过量、或者不一致性的结果。使用单例模式的好处:

  • 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
  • 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。

代理设计模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。**一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。**在现实生活中,这种情形非常的常见,比如请一个律师代理来打官司

模板方法模式一种行为设计模式,它定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的实现方式。

观察者模式一种对象行为型模式它表示的是一种对象与对象之间具有依赖关系,当一个对象发生改变的时候,这个对象所依赖的对象也会做出反应。Spring 事件驱动模型就是观察者模式很经典的一个应用。Spring 事件驱动模型非常有用,在很多场景都可以解耦我们的代码。比如我们每次添加商品的时候都需要重新更新商品索引,这个时候就可以利用观察者模式来解决这个问题。

适配器模式 将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。

装饰者模式可以动态地给对象添加一些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。简单点儿说就是当我们需要修改原有的功能,但我们又不愿直接去修改原有的代码时,就可以使用装饰者模式

Spring事务

(1)Spring 事务的种类:

spring 支持编程式事务管理和声明式事务管理两种方式:

  1. 编程式事务,在代码中硬编码。(不推荐使⽤)。

  2. 声明式事务,在配置⽂件中配置(推荐使⽤)。

    声明式事务管理建立在 AOP 之上的。其本质是通过 AOP 功能,对方法 前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之 前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

    声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码, 只需在配置文件中做相关的事务规则声明或通过@Transactional 注解的方式, 便可以将事务规则应用到业务逻辑中。这正是 spring 倡导的非侵入式的 开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一 不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以 作用到代码块级别。

    声明式事务⼜分为两种:

    1. 基于XML的声明式事务

    2. 基于注解的声明式事务

(2) Spring 的事务传播行为:

Spring 事务的传播行为说的是,当多个事务同时存在的时候,Spring 如何 处理这些事务的行为。

⽀持当前事务的情况:

  • ① PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,

    如果当前存在事务,就加入该事务,该设置是最常用的设置。

  • ② PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。‘

  • ③ PROPAGATION_MANDATORY:如果当前存在事务, 就加入该事务,如果当前不存在事务,就抛出异常。

    不⽀持当前事务的情况:

  • ④ PROPAGATION_REQUIRES_NEW:创建一个新事务,如果当前存在事务,则把当前事务挂起(无论当前存不存在事 务,都创建新事务)

  • ⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  • ⑥ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

    其他情况:

  • ⑦ PROPAGATION_NESTED:如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则按 REQUIRED 属性执行。

(3) Spring 事务中的隔离级别:

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

  • ① ISOLATION_DEFAULT:使用数据库默认的事务隔离级别。 Mysql默认采⽤的 REPEATABLE_READ隔离级别Oracle 默认采⽤的 READ_COMMITTED隔离级别

  • ② ISOLATION_READ_UNCOMMITTED:(最低的事务隔离级别)读未提交,允许另外一个事务读取这个事务未提交的数据。可能会导致脏读、幻读或不可重复读

  • ③ ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才 能被另一事务读取,可以阻⽌脏读,但是幻读或不可重复读仍有可能发⽣

  • ④ ISOLATION_REPEATABLE_READ:可重复读,对同⼀字段的多次读取结果

    都是⼀致的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有可能发⽣

  • ⑤ ISOLATION_SERIALIZABLE:(最⾼的隔离级别),完全服从ACID的隔离级别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该级别可以防⽌脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会⽤到该级别。

1.脏读:

第一个事务对一个表中的数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问该同一数据,如果这时第一个事务突然回滚了事务,此时那行数据的值回滚为 NULL 值。然后事务 B 紧接着此时再次查询那行数据的值,看到的居然是 NULL 值。这种读取到另一个事务未提交的数据的现象就是脏读

2.不可重复读:
是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

3.幻读:
是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象
发生了幻觉一样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李莲花*

多谢多谢,来自一名大学生的感谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值