速通spring与mybatis

news/2024/11/15 0:48:57/文章来源:https://www.cnblogs.com/kun1790051360/p/18378873

 

Spring

1.什么叫线程安全:

  多个线程访问一个对象时,不需要额外的调度与交替执行也不需要额外的同步,调用这个对象的行为都可以获得正确的调度结果

如何保持线程安全:

  1. 使用final修饰变量,让其只可读不可修改
  2. 使用局部变量,公共数据私有化:这样堆内读取的数据就会改成在栈内读取
  3. 使用ThreadLocal,这样每个线程都会在进程内copy一份数据,各自使用自己的数据
  4. 使用互斥锁,让后续操作等待,这个适合线程比较多的情况
  5. 使用乐观锁CAS:失败重试机制:即将修改的数据的原数据不一致,重新获取数据再修改。在线程数较少时,使用锁比较消耗资源,使用此方法

 

2.spring框架中的单例bean是线程安全的吗?

spring中的bean默认是单例的,bean内有一个@scope("singleton")默认注解,说明他是单例的,另一种就是prototype原型设计模式。

单例bean是线程不安全的:如果springbean中有可变的状态,例如成员变量,他是公共的,这时就会有线程安全问题。

 

3.什么是AOP

面相切面编程,用于将与业务无关,但是会对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用模块,这个模块就是aspect(切面)

在事务@Transactional中,就是对方法前后进行了拦截,在执行方法前开启事务,在执行完目标方法之后根据执行情况提交或回滚事务

 

4.JDK动态代理和CGLIB动态代理

JDK代理只提供接口的代理,不支持类的代理

  • 运行时会为目标生成一个$proxy*.class的动态代理类
  • 代理类会实现接口的所有方法增强代码
  • 调用的时候通过代理类先去调用处理类进行增强,再通过反射去调用目标方法实现AOP

如果代理类没有实现接口,那么就是CGLIB来动态代理目标类

  • CGLIB底层是通过ASM在运行时动态的生成目标类的一个子类(会生成多个为了增强调用效率的类)
  • 重写父类所有增强代码
  • 调用是先通过代理类增强,再直接调用父类的方法,从而实现AOP(因此,如果被final修饰,无法通过CGLIB进行动态代理;CGLIB还会生成一个FastClass类路由类,可以让本类方法调用进行增强,而不会失效)

一般来说JDK生成类速度快(因为生成类比较少)而调用慢(采用反射所以慢);CGLIB生成类速度慢,后续调用快。但是JDK在版本升级性能都在提升。在JDK8的时候性能已经比CGLIB快20%左右了。

 

5.事务失效的场景

异常捕获处理,try catch你自己都把异常捕获了系统认为代码没问题就不会回滚了。当然也可以在catch中重新throw new runtimeexpection

抛出检查异常,默认只会回滚非检查异常,如果需要回滚,需要在事务注解内加上rollbackFor

非public方法(默认情况为default,而非public)

类内自调用,事务基于AOP,AOP基于动态代理,this指针的对象是普通对象而非动态代理对象(参考4,我是先写的5再写的4)

数据库引擎不支持、分布式情况

事务传播行为不一致:顺带讲一下常用的两种事务:1.required,适用于绝大多修改方法。A有事务时,B会融入A事务;A没有事务时,B会开启一个新事务。2.support,适用于绝大多查询方法,A有事务,B会加入A事务;A没事务,B会以非事务方法执行

 

6.springbean的生命周期

spring容器在实例化时会将xml中的<bean>封装成一个beanDefinition,其中有很多属性用来描述bean:

  • beanClassName(可以通过getBeanClassName()获取类名,反射创建bean)
  • scope(作用域:比如singleton,prototype,getScope)
  • lazy-init(懒加载)

生命周期:

  • beanDefinition调用bean的构造函数,(这里只负责创建bean,不负责赋值,赋值和创建是分开算的)
  • 依赖注入(通过@Autowired,@Value注入)
  • aware接口(BeanNameAware[运行bean获取自己的name]、BeanFactoryAware[用于获取bean,检查bean是否存在]、ApplicationContextAware[])方便对bean进一步扩展
  • BeanPostProcessor#before bean的后置处理器-前置
  • 初始化方法
  • BeanPostProcessor#after bean的后置处理器-后置(AOP就是通过这个来增强类的,AOP的底层为动态代理,动态代理分为JDK动态代理和CGlib动态代理)

 

7.如何解决循环依赖

为什么spring bean会有循环依赖:bean的生命周期中提到,bean的构造和赋值是分开的;在实例化时beanA会现在堆内申请空间,然后再进行初始化,初始化如果依赖于一个不存在的beanB,则需要优先去创建beanB,beanB也需要先实例化,然后初始化的时候发现他也需要beanA,从而形成循环

spring提供了三层缓存解决了大部分循环依赖问题:

一级缓存(singletonObjects)用于存储经历了完整生命周期的单例bean对象

二级缓存(earlySingletonObjects)用于存储早期的bean对象(生命周期还没有走完)

三级缓存(singletonFactories)用于存储ObjectFactory,对象工厂,用来创建对象的(后面可能会创建普通对象、代理对象)

二级缓存如何解决循环依赖:实例化A后,A的原始对象会被存入二级缓存中,初始化需要注入B,B不存在再实例化B。B先初始化,再初始化的时候将B原始对象存入二级缓存,这里通过二级缓存取出A的原始对象。B创建成功后再将B对象存入一级缓存中,B注入A,A也放入一级缓存中。这时A,B都将对象存入了一级缓存中,但是没有代理对象

三级缓存如何解决循环依赖:实例化A后,A会生成一个A-ObjectFactory,这时再去进行初始化,初始化需要注入B。实例化B,B再生成一个B-ObjectFactory,初始化需要注入A,B会让A-ObjectFactory创建一个A的代理对象。A的代理对象会被放入二级缓存,然后将A的代理对象注入给B,这时B创建成功了,B会被放入一级缓存中。将B注入给A代理对象,A代理对象也创建成功,这时A的代理对象也会放入一级缓存。至此创建成功

 构造方法出现了循环依赖:因为bean的生命周期中会有构造和初始化两个阶段,三级缓存解决的是初始化阶段循环依赖的问题;通过在构造方法内为循环依赖的bean加上@Lazy,让其懒加载。这样就可以将问题从构造方法中抛到初始化阶段从而解决问题

 

8.讲讲springMVC的执行流程

老版本(JSP这类)

1.浏览器发送请求给DispatcherServlet(由tomcat初始化的前端控制器)

2.通过handlermapping查询handler,handlermapping里存了一张map { key:前端发起的路径 , value:"类名#方法名" } 例如:{key:/user/getById/1,value:"UserController#getUserById(Long id)"}。再将handler、拦截器一并返回给dispatcherServlet

3.DispatcherServlet调用handlerAdaptor,handlerAdaptor调用适用的handler/controller,将得到的ModelAndView对象返回给dispatcherServlet。

4.dispatcherServlet将modelAndView传给ViewResolver,ViewResolver解析后返回具体的view

5.dispatcherServlet根据view渲染具体视图响应用户

新版本

1.浏览器发送请求给DispatcherServlet(由tomcat初始化的前端控制器)

2.通过handlermapping查询handlermapping,生成处理器对象及处理器拦截器,再一起返回给dispatcherServlet

3.dispatcherServlet调用handleradapter

4.方法上有responseBody,通过HttpMessageConverter来返回结果转换为JSON并响应

 

9.springboot的自动配置原理

springboot项目的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装:@SpringbootConfiguration,@EnableAutoConfiguration,@CompentScan

其中@EnableAutoConfiguration是实现自动装配类的注解,通过@Import导入了默认的选择器。选择器就是读取了项目以及项目引用的jar包的classpath路径下META-INF/spring.factories所配置的类的类名,这些配置类内的bean会根据条件注解所指定的条件来决定是否需要将其导入到spring容器中

条件判断会类似@ConditionalOnClass的注解来决定是否加载该类,如果有则加载,其中的所有bean也会有@ConditionalOnMissingBean控制,如果一切正确则bean会自动置入spring容器中。

 

10.spring框架常见注解(spring,springboot,springMVC)

spring:bean相关,例如@Component @Controller @Service @Autowired @Scope @Configuration AOP相关 @PointCut @Around @Aspect

springboot:@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan @SpringbootApplication

springMVC:主要是controller里那些 @RequestMapping @RequestBody @RequsetHeader @RequestParam @PathViriable @RestController @ResponseBody

 

Mybatis

1.mybatis的执行流程

读取mybatis配置:spring版本有个mybatis-config.xml;springboot版本实现自动装配功能,直接在yaml文件写jdbc的链接相关内容就可以了

构造会话工厂SqlSessoinFactory

会话工厂构造会话对象SqlSession(用于执行映射SQL的语句、管理事务、代理mapper),sqlsession中的功能是基于executor实现的

executor是mybatis的核心接口,他的执行方法中有一个MapperedStatement类型的参数,其中封装了映射信息,会对输入参数和输出参数进行java到sql以及sql到java的映射。包括了id,resource,resultType,sql。

executor来执行实际的数据库操作。

 

2.mybatis是否支持延迟加载?

支持,但是默认情况下是未开启的

什么是延迟加载?举例来说:有User表和Order表,他们是1对多的关系;User实体类中有List<Order> orderList字段,Order实体类中有User user字段

查询用户时如果把用户所属的订单数据页查询出来,这就是正常加载

查询用户时暂时不查询订单数据,需要订单时再查询订单,这就是延迟加载

如何实现延迟加载:在映射的结果集里的子查询中有fetchType属性,设置为lazy即可实现延迟加载。上例中,只有当你调用了user.getOrderList()才会去执行对应的查询语句

延迟加载主要是通过CGLIB代理对象实现的,调用目标方法时会进入invoke拦截器,发现目标为null会执行sql查询再通过set设参然后才会进入目标方法

 

3.mybatis的一级缓存/二级缓存

mybatis的缓存都是由map集合存储的;sqlSession是与当前线程绑定的,一旦事务结束、请求处理完毕、发生异常,sqlSession都会关闭

一级缓存(默认开启的):作用域是同一个sqlSession,同一个sqlSession内执行两次参数一样的sql语句会在缓存中读取数据,持续到sqlSession没有close或者flush。一般在完成一次数据库操作/事务结束后sqlSession就会关闭了,因此其实一级缓存意义不大。

二级缓存(不建议使用):多个sqlSession共享的,其作用域是mapper的同一个namespace。不同sqlSession执行两次参数一样同一个namespace的sql会在缓存中读取数据。

二级缓存只建议用在数据字典这种基本不会改动,不会有/被外表链接的mapper中。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/793072.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JS解析JSON数据到TABLE表格

效果图: 数据采用JSON,[{"时间段": "上午","XX小学班课表": [{"名称": "教师上班","时间": "8:00","星期一": "","星期二": "","星期三": "&q…

登陆微软账号,输入window密码后,提示「哎呀,出错了」

存在问题解决方案暂时关闭dai~Li 设置 账户 下滑,电子邮件和账户 添加Microsoft账户解决后的效果版权木有,侵权不究,欢迎转载

TDBC回顾 | 钛铂数据肖贝贝:TapData — 自主可控

7月,TapData CTO 肖贝贝出席“2024可信数据库发展大会”,分享了“TapData — 自主可控的实时数据平台”的主题演讲。本文为完整内容。2024年7月17日上午,“2024可信数据库发展大会”数据库生态与国际化分论坛在北京隆重召开。会上,深圳钛铂数据有限公司CTO肖贝贝重点与听众…

服务器时间同步

一、安装ntpddate #centos,redhat系列 yum install ntpdate#debian,ubuntu系列 apt install ntpdate二、在服务器都能联网情况下时间同步 #手动同步阿里云时间服务器时间 ntpdate ntp.aliyun.com 阿里云时间同步地址 ntp1.aliyun.com ntp2.aliyun.com ntp3.aliyun.com ntp4.ali…

D35XT120-ASEMI新能源专用D35XT120

D35XT120-ASEMI新能源专用D35XT120编辑:ll D35XT120-ASEMI新能源专用D35XT120 型号:D35XT120 品牌:ASEMI 封装:DXT-5 批号:2024+ 现货:50000+ 正向电流(Id):35A 反向耐压(VRRM):1200V 正向浪涌电流:450A 正向电压(VF):1.10V 引脚数量:5 芯片个数:5 芯片尺寸:…

高等数学 1.1 映射与函数

目录一、映射映射概念逆映射与复合映射二、函数函数概念函数的几种特性(1)函数的有界性(2)函数的单调性(3) 函数的奇偶性(4)函数的周期性反函数与复合函数反函数复合函数函数的运算初等函数基本初等函数初等函数双曲函数与反双曲函数 一、映射 映射概念定义 设 \(X\) ,…

rfc编写

rfc检索:https://www.rfc-editor.org/rfc-index.html rfc绘图:https://asciiflow.com/ 绘图后保存成ascii art:

前端 - Failed to load module script 解决方案

Failed to load module script 解决方案 问题描述 打包好项目发布上传到 nginx 后,浏览器访问,出现一下报错信息:Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME ty…

有关API接口的介绍及简单的API接口代码示例

https://img2024.cnblogs.com/blog/3506472/202409/3506472-20240906135806395-1508567224.png在当今数字化时代,应用程序不再孤立存在。它们通过API(应用程序编程接口)相互连接,共享数据和功能。API是现代软件开发中不可或缺的一部分,它允许不同的软件系统相互通信,实现…

ext4.vhdx占用C盘过大

ext4.vhdx 是个虚拟磁盘,默认位置为 C:\Users{用户名}\AppData\Local\Docker\wsl\data\ext4.vhdx,会占用很大磁盘空间,可采用下列办法将其改到其它磁盘或分区,如D分区。 1、查看有哪些2、导出目标: wsl --export docker-desktop "D:\\docker-desktop.tar" wsl -…

CRM软件的演进:从传统到连接型CRM

1、CRM定义与分类 1.1CRM的定义 CRM,英文Customer Relationship Management的缩写,中文全称为客户关系管理。通常情况下,人们通常用CRM直接表达客户关系管理软件系统——一个以客户为中心的专门用于管理与客户关系的软件工具,以确保与客户在营销、销售、服务的每一环节上都能…