北京丰台网站建设公司,网站开发有前景吗,0基础学习网站开发,什么平台目录 一、JVM1.类加载过程2.static和final变量的初始化时机 二、依赖1.Spring Boot 自动装配2.使用依赖过程中遇到问题如何排查3.引入的某个依赖不符合预期#xff0c;如何处理 三、数据库#xff1a;1.InnoDB 和 MyISAM 索引的区别2.字符串类型字段#xff0c;WHERE 数字如何处理 三、数据库1.InnoDB 和 MyISAM 索引的区别2.字符串类型字段WHERE 数字会走索引吗数值型字段WHERE 字符串会走索引吗3.针对 RR 级别提问4.间隙锁什么时候触发5.假设一台线上服务器只放了 MySQL 数据库突发告警CPU、内存等如何排查6.慢 SQL 如何排查除了慢查询日志还有什么方式 一、JVM
1.类加载过程
类加载机制 Java虚拟机把描述类的数据从Class文件加载到内存并对数据进行校验、转换解析和初始化最终形成可以被虚拟机直接使用的Java类型这个过程被称作虚拟机的类加载机制。 类加载过程 在 Java 中类加载是指将类的字节码文件加载到内存中并将其转换为 Java 虚拟机可以使用的数据结构的过程。类加载过程主要包括以下三个步骤 加载Loading将类的字节码文件加载到内存中。在加载阶段Java 虚拟机会根据类的全限定名来查找类的字节码文件并将其读入内存中。在读入字节码文件后Java 虚拟机会为该类创建一个 java.lang.Class 对象用于表示该类在内存中的数据结构。 链接Linking将类的字节码文件转换为 Java 虚拟机可以使用的数据结构。链接阶段主要包括以下三个步骤 验证Verification验证类的字节码文件是否符合 Java 虚拟机规范。在验证阶段Java 虚拟机会对类的字节码文件进行各种验证以确保其符合 Java 虚拟机规范。例如Java 虚拟机会检查类的字节码文件是否包含不合法的指令、是否存在不合法的类型转换等。 准备Preparation为类的静态变量分配内存并设置默认值。在准备阶段Java 虚拟机会为类的静态变量分配内存并设置默认值。例如对于一个 int 类型的静态变量Java 虚拟机会为其分配 4 个字节的内存并将其默认值设置为 0。 解析Resolution将类的符号引用转换为直接引用。在解析阶段Java 虚拟机会将类的符号引用转换为直接引用。例如Java 虚拟机会将类的全限定名转换为内存地址以便在运行时快速访问类的方法和变量。 初始化Initialization为类的静态变量赋值并执行静态代码块。在初始化阶段Java 虚拟机会为类的静态变量赋值并执行静态代码块。例如对于一个 static 代码块Java 虚拟机会在类加载时执行该代码块并将其中的静态变量赋值。
需要注意的是类加载过程是一个递归的过程。当一个类被加载时它所依赖的其他类也会被加载并按照类的依赖关系进行初始化。同时Java 虚拟机还提供了一些机制例如类加载器、双亲委派模型等来保证类的加载过程的安全性和可靠性。
2.static和final变量的初始化时机
初始化阶段简言之为类的静态变量赋予正确的初始值。(显式初始化) 具体描述 类的初始化是类装载的最后一个阶段。如果前面的步骤都没有问题那么表示类可以顺利装载到系统中。此时类才会开始执行Java字节码。即到了初始化阶段才真正开始执行类中定义的 Java 程序代码。 初始化阶段的重要工作是执行类的初始化方法:clinit()方法。
该方法仅能由Java编译器生成并由JVM调用程序开发者无法自定义一个同名的方法更无法直接在Java程序中调用该方法虽然该方法也是由字节码指令所组成。它是由类静态成员的赋值语句以及static语句块合并产生的。
子类加载前先加载父类 在加载一个类之前虚拟机总是会试图加载该类的父类因此父类的 clinit 总是在子类 clinit 之前被调用。也就是说父类的static块优先级高于子类。 口诀由父及子静态先行。
哪些类不会生成方法
一个类中并没有声明任何的类变量也没有静态代码块时一个类中声明类变量但是没有明确使用类变量的初始化语句以及静态代码块来执行初始化操作时一个类中包含static final修饰的基本数据类型的字段这些类字段初始化语句采用编译时常量表达式
代码举例static与final的搭配问题 * 总结* 使用static final 修饰的成员变量称为全局常量。* 什么时候在链接阶段的准备环节给此全局常量附的值是字面量或常量。不涉及到方法或构造器的调用。* 除此之外都是在初始化环节赋值的。二、依赖
1.Spring Boot 自动装配
SpringBootApplication 是一个组合注解它包含了 Configuration、EnableAutoConfiguration 和 ComponentScan 这三个注解的功能。它的作用是标识一个 Spring Boot 应用的主类用于启动 Spring Boot 应用程序。
SpringBootConfiguration 注解表示该类是一个配置类它会被 Spring IOC 容器用来生成 Bean 定义。ComponentScan 注解表示扫描指定的包及其子包下的所有组件用于定义 Spring 的扫描路径等价于在 xml 文件中配置 context:component-scan 假如不配置扫描路径那么 Spring 就会默认扫描当前类所在的包及其子包中的所有标注了 Component Service Controller 等注解的类。将它们注册到 Spring IOC 容器中。EnableAutoConfiguration 注解表示开启自动配置Spring Boot 会根据项目中的依赖自动配置应用程序。
这个注解才是实现自动装配的关键点进去之后发现它是一个由 AutoConfigurationPackage 和 Import 注解组成的复合注解。
Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
Documented
Inherited
AutoConfigurationPackage
Import(AutoConfigurationImportSelector.class)
public interface EnableAutoConfiguration {看起来很多注解实际上关键在 Import 注解它会加载 AutoConfigurationImportSelector 类然后就会触发这个类的 selectImports() 方法。根据返回的 String 数组配置类的 Class 的名称加载配置类。 我们重点看下 AutoConfigurationImportSelector 。 AutoConfigurationImportSelector中的selectImport是自动装配的核心实现它主要是读取META-INF/spring.factories文件经过去重、过滤返回需要装配的配置类集合。 Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationEntry autoConfigurationEntry getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}我们点进 getAutoConfigurationEntry() 方法:
getAttributes 获取 EnableAutoConfiguration 中的 exclude 、 excludeName 等。getCandidateConfigurations 获取所有自动装配的配置类也就是读取 - spring.factories 文件后面会再次说明。removeDuplicates 去除重复的配置项。getExclusions 根据 EnableAutoConfiguration 中的 exclude 、 - excludeName 移除不需要的配置类。fireAutoConfigurationImportEvents 广播事件。
最后根据多次过滤、判重返回配置类合集。 现在我们结合 getAutoConfigurationEntry() 的源码来详细分析一下
第 1 步判断自动装配开关是否打开。 默认 spring.boot.enableautoconfigurationtrue 可在 application.properties 或 application.yml 中设置。
第 2 步 用于获取 EnableAutoConfiguration 注解中的 exclude 和 excludeName 。 第 3 步: 获取需要自动装配的所有配置类读取 META-INF/spring.factories 。 我们点进 getCandidateConfigurations() 方法 protected ListString getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {ListString configurations SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert.notEmpty(configurations, No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.);return configurations;}获取候选配置了使用了 Spring Framework 自定义的 SPI 机制使用 SpringFactoriesLoader#loadFactoryNames 加载了类路径下 /META-INF/spring.factories 文件中的配置类里面是以 key/value 形式存储其中一个 key 是 EnableAutoConfiguration 类的全类名而它的 value 是一个以 AutoConfiguration 结尾的类名的列表。以 spring-boot-autoconfigure 模块为例其 spring.factories 内容如下。 不光是这个依赖下的 META-INF/spring.factories 被读取到所有 Spring Boot Starter 下的 META-INF/spring.factories 都会被读取到。 如果我们自定义一个 Spring Boot Starter就需要创建 META-INF/spring.factories 文件。 第 4 步 到这里可能面试官会问你:“ spring.factories 中这么多配置每次启动都要全部加载么”。 很明显这是不现实的。我们 debug 到后面你会发现 configurations 的值变小了。 虽然 127 个全场景配置项的自动配置启动的时候默认全部加载。但实际经过后续处理后只剩下 23 个配置项真正加载进来。很明显Spring Boot 只会加载实际你要用到的场景中的配置类。这是如何做到的了 按需加载 这里我们分析剩下的 23 个自动配置类观察到每一个自动配置类都有着 Conditional 或者其派生条件注解。 ConditionalOnBean当容器里有指定 Bean 的条件下 ConditionalOnMissingBean当容器里没有指定 Bean 的情况下 ConditionalOnSingleCandidate当指定 Bean 在容器中只有一个或者虽然有多个但是指定首选 Bean ConditionalOnClass当类路径下有指定类的条件下 ConditionalOnMissingClass当类路径下没有指定类的条件下 ConditionalOnProperty指定的属性是否有指定的值 ConditionalOnResource类路径是否有指定的值 ConditionalOnExpression基于 SpEL 表达式作为判断条件 ConditionalOnJava基于 Java 版本作为判断条件 ConditionalOnJndi在 JNDI 存在的条件下差在指定的位置 ConditionalOnNotWebApplication当前项目不是 Web 项目的条件下 ConditionalOnWebApplication当前项目是 Web 项 目的条件下
Configuration(proxyBeanMethods false
)
// 检查是否有该类才会进行加载
ConditionalOnClass({RedisOperations.class})
// 绑定默认配置信息
EnableConfigurationProperties({RedisProperties.class})
Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {public RedisAutoConfiguration() {}...
}所以当 classpath 下存在某一个 Class 时某个配置才会生效。
上面所有的注解都在做一件事注册 bean 到 Spring 容器。他们通过不同的条件不同的方式来完成
SpringBootConfiguration 通过与 Bean 结合完成 Bean 的 JavaConfig 配置
ComponentScan 通过范围扫描的方式扫描特定注解注释的类将其注册到 Spring 容器EnableAutoConfiguration 通过 spring.factories 的配置并结合 Condition 条件完成bean的注册Import 通过导入的方式将指定的 class 注册解析到 Spring 容器 我们在这里画张图把 SpringBootApplication 注解包含的几个注解分别解释一下。 Spring Boot 通过 EnableAutoConfiguration 开启自动装配通过 SpringFactoriesLoader 最终加载 META-INF/spring.factories 中的自动配置类实现自动装配自动配置类其实就是通过 Conditional 按需加载的配置类想要其生效必须引入 spring-boot-starter-xxx 包实现起步依赖。
2.使用依赖过程中遇到问题如何排查
1.使用idea自带的依赖树使用依赖管理工具例如 Maven、Gradle 等可以查看项目的依赖树以便了解项目中使用的依赖及其版本。通过查看依赖树可以发现依赖冲突、依赖版本不兼容等问题。 快捷键ctrlshiftaltu 2.使用idea商城中的插件maven helper
3.引入的某个依赖不符合预期如何处理
最短路径优先原则 依赖链路一主要根据依赖的路径长短来决定引入哪个依赖两个冲突的依赖。 举例说明
依赖链路一A - X - Y - Z(21.0)
依赖链路二B - Q - Z(20.0)项目中同时引入了A和B两个依赖它们间接都引入了Z依赖但由于B的依赖链路比较短因此最终生效的是Z(20.0)版本。这就是最短路径优先原则。 此时如果Z的21.0版本和20.0版本区别较大那么就会发生Jar包冲突的表现。
最先声明优先原则 如果两个依赖的路径一样最短路径优先原则是无法进行判断的此时需要使用最先声明优先原则也就是说谁的声明在前则优先选择。 举例说明
依赖链路一A - X - Z(21.0)
依赖链路二B - Q - Z(20.0)A和B最终都依赖Z此时A的声明pom中引入的顺序优先于B则针对冲突的Z会优先引入Z(21.0)。 如果Z(21.0)向下兼容Z(20.0)则不会出现Jar包冲突问题。但如果将B声明放前面则有可能会发生Jar包冲突。
三、数据库
1.InnoDB 和 MyISAM 索引的区别
外键 事务 锁
对比项MyISAMInnoDB外键不支持支持事务不支持支持行表锁表锁即使操作一条记录也会锁住整个表不适合高并发的操作行锁操作时只锁某一行不对其它行有影响适合高并发的操作缓存只缓存索引不缓存真实数据不仅缓存索引还要缓存真实数据对内存要求较高而且内存大小对性能有决定性的影响关注点并发查询节省资源、消耗少、简单业务并发写、事务、多表关系、更大资源默认安装YY默认使用NY自带系统表使用YN
2.字符串类型字段WHERE 数字会走索引吗数值型字段WHERE 字符串会走索引吗
字符串类型字段WHERE 数字会走索引吗不会 数值型字段WHERE 字符串会走索引吗会
当索引字段是字符串类型输入参数是数值类型时会将字段转换成数值类型再进行查找也就是对索引字段做了函数操作破坏了索引的有序性因此无法使用索引。当索引字段是数值类型输参数是字符串类型时会将输入参数转换成数值类型再进行查找对等号后面的输入参数进行函数操作并不影响索引字段的有序性因此可以使用索引。
3.针对 RR 级别提问
RR 级别并不能完全避免幻读问题。幻读是指在一个事务中多次执行同一个查询语句但是每次查询的结果集都不同。在 RR 级别下虽然可以避免不可重复读问题但是无法避免幻读问题。
4.间隙锁什么时候触发
唯一索引等值查询 1.当查询的记录是存在的next-key lock 会退化成「记录锁」。 2.当查询的记录是不存在的next-key lock 会退化成「间隙锁」。
非唯一索引等值查询 1.当查询的记录存在时除了会加 next-key lock 外还额外加间隙锁也就是会加两把锁。 2.当查询的记录不存在时只会加 next-key lock然后会退化为间隙锁也就是只会加一把锁。
非唯一索引和主键索引的范围查询的加锁规则不同之处在于 唯一索引在满足一些条件的时候next-key lock 退化为间隙锁和记录锁。 非唯一索引范围查询next-key lock 不会退化为间隙锁和记录锁。
5.假设一台线上服务器只放了 MySQL 数据库突发告警CPU、内存等如何排查
排查过程 使用top 命令观察确定是mysqld导致还是其他原因。 如果是mysqld导致的使用 show processlist 命令可以查看当前 MySQL 实例中正在执行的所有线程也称为 session的状态信息确定是不是有消耗资源的sql在运行。找出消耗高的 sql看看执行计划是否准确 索引是否缺失数据量是否太大。 处理 kill 掉这些线程(同时观察 cpu 使用率是否下降) 进行相应的调整(比如说加索引、改 sql、改内存参数) 重新跑这些 SQL。 其他情况 也有可能是每个 sql 消耗资源并不多但是突然之间有大量的 session 连进来导致 cpu 飙升这种情况就需要跟应用一起来分析为何连接数会激增再做出相应的调整比如说限制连接数等
6.慢 SQL 如何排查除了慢查询日志还有什么方式
开启慢查询
set global slow_query_log1设置慢查询的时间
SET GLOBAL long_query_time0.1;假如运行时间正好等于long_query_time的情况并不会被记录下来。也就是说在mysql源码里是判断大于long_query_time而非大于等于。 使用mysqldumpslow去分析查找sql然后在使用explain进行分析 排查思路
第1个原因没有索引或者 导致索引失效。第2个原因单表数据量数据过多导致查询瓶颈第3个原因网络原因或者机器负载过高。第4个原因热点数据导致单点负载不均衡。
除了慢查询日志还有什么方式 除了慢查询日志还有一些其他的方式可以帮助我们识别和优化 MySQL 中的慢查询包括 使用 MySQL 自带的性能分析工具MySQL 自带了一些能分析工具如 EXPLAIN、SHOW PROFILE、SHOW STATUS 等可以帮助我们分析 SQL 查询语句的执行计划、性能瓶颈等信息。 使用第三方性能分析工具除了 MySQL 自带的工具还有一些第三方的性能分析工具如 Prometheus . Skywalking等可以帮助我们分析慢查询日志找出慢查询的原因和优化建议。 使用 MySQL 监控工具MySQL 监控工具可以帮助我们实时监控 MySQL 实例的性能指标如 CPU 使用率、内存使用率、磁盘 I/O 等从而帮助我们及时发现性能问题(MySQL Enterprise Monitor,Zabbix)。