目录
48.ApplicationContext和BeanFactory有什么区别
50.Spring中什么时候@Transactional会失效
41.谈谈你对AQS的理解,AQS如何实现可重入锁?
1. AQS是⼀个JAVA线程同步的框架。是JDK中很多锁⼯具的核⼼实现框架。
2. 在AQS中,维护了⼀个信号量state和⼀个线程组成的双向链表队列。其中,这个线程队列,就是⽤ 来给线程排队的,⽽state就像是⼀个红绿灯,⽤来控制线程排队或者放⾏的。 在不同的场景下,有不⽤的意义。
3. 在可重⼊锁这个场景下,state就⽤来表示加锁的次数。0标识⽆锁,每加⼀次锁,state就加1。释放锁state就减1。
42.谈谈你对IOC的理解
- 提到Spring 我们都能想到核心是,IOC和AOP
- 那么我就谈一谈IOC的理解,说到IOC就要想到他的核心就是控制反转。
- 对于我来说,控制反转就是把对于成员变量赋值的控制权,从代码中反转(转移)Spring工厂和配置文件中完成,他的好处就是解耦合,底层实现是工厂设计模式。
43.单例Bean和单例模式
- 单例模式表示JVM中某个类的对象只会存在唯⼀⼀个。
- ⽽单例Bean并不表示JVM中只能存在唯⼀的某个类的Bean对象。
44.Spring事务传播机制
- 多个事务⽅法相互调⽤时,事务如何在这些⽅法间传播,⽅法A是⼀个事务的⽅法,⽅法A执⾏过程中调 ⽤了⽅法B,那么⽅法B有⽆事务以及⽅法B对事务的要求不同都会对⽅法A的事务具体执⾏造成影响, 同时⽅法A的事务对⽅法B的事务执⾏也有影响,这种影响具体是什么就由两个⽅法所定义的事务传播类型所决定。
- REQUIRED(Spring中默认的传播类型): 如果a有事务,那么b就加入, 如果a没有事务,b就创建一个事务执行。
- SUPPORT: 如果a有事务,b就加入,如果a没有事务,那么b也没有必要有事务
- MANDATORY:如果a有事务,b就加入,没有事务,就抛出异常
- REQUIRES_NEW: 如果a有事务,b暂时挂起,互不影响,各自执行
- NOT_SUPPORTS:如果a有事务,则挂起事务,以非事务方式
- NEVER:不使用事务,如果有事务就抛出异常
- NESTED:如果当前有事务存在,就嵌套执行,跟REQUIRED一样。
45.Spring事务什么时候会失效?
Spring的事务其实就是Aop,进行了切面增强,如果事务失效就说明Aop动态代理失效。
- 发生自身调用,类方法调用本类的this方法(this通常省略),动态代理就会失效
- 数据库不支持事务
- 有异常被吃掉,事务没有回滚
- 没有被spring容器管理
- @Transactional 注解需要在public方法上面,如果不是public修饰,导致事务失效
46.Spring中的Bean创建的生命周期有哪些步骤
实例化:
- 通过推断构造方法(反射)
- 实例工厂、静态工厂
属性注入:
- 解析自动装配(@Autowried,byname,bytype,@Resource,@constractor),DI
- 循环依赖
初始化:
- 实现不同的XXXAware的回调方法
- 调用初始化生命周期回调(实现init().@PostConstruct,实现InitializingBean接口)
- 如bean实现Aop,创建动态代理
销毁:
- Spring容器关闭时回调
- 调用摧毁时回调
47.Spring中Bean是线程安全的吗
Spring本身并没有针对Bean做线程安全的处理,所以:
- 如果Bean是⽆状态的,那么Bean则是线程安全的
- 如果Bean是有状态的,那么Bean则不是线程安全的
- 另外,Bean是不是线程安全,跟Bean的作⽤域没有关系,Bean的作⽤域只是表示Bean的⽣命周期范 围,对于任何⽣命周期的Bean都是⼀个对象,这个对象是不是线程安全的,还是得看这个Bean对象本身。
48.ApplicationContext和BeanFactory有什么区别
- BeanFactory 是Spring的核心组件,表示bean工厂,管理bean,维护bean。ApplicationContext 继承了Beanfactory,不仅有BeanFactory所有的方法,还继承了诸如 EnvironmentCapable、MessageSource、ApplicationEventPublisher等接⼝,从⽽ ApplicationContext还有获取系统环境变量、国际化、事件发布等功能。
- BeanFactory是延迟加载的,调用得时候才会getBean获取
- ApplicationContext是积极加载的,new 出来的时候会加载所有的bean
- Beanfactory 是手动注册的,ApplicationContext 是自动注册的
49.Spring中的事务是如何实现的
1. Spring事务底层是基于数据库事务和AOP机制的
2. ⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean
3. 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解
4. 如果加了,那么则利⽤事务管理器创建⼀个数据库连接
5. 并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮ 常重要的⼀步
6. 然后执⾏当前⽅法,⽅法中会执⾏sql
7. 执⾏完当前⽅法后,如果没有出现异常就直接提交事务
8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务
9. Spring事务的隔离级别对应的就是数据库的隔离级别
10. Spring事务的传播机制是Spring事务⾃⼰实现的,也是Spring事务中最复杂的
11. Spring事务的传播机制是基于数据库连接来做的,⼀个数据库连接⼀个事务,如果传播机制配置为 需要新开⼀个事务,那么实际上就是先建⽴⼀个数据库连接,在此新数据库连接上执⾏sql
50.Spring中什么时候@Transactional会失效
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效,所以如果是被代理对象来调⽤这个⽅法,那么@Transactional是不会失效的。 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效
51.Spring容器启动流程是怎样的
1. 在创建Spring容器,也就是启动Spring时:
2. ⾸先会进⾏扫描,扫描得到所有的BeanDefinition对象,并存在⼀个Map中
3. 然后筛选出⾮懒加载的单例BeanDefinition进⾏创建Bean,对于多例Bean不需要在启动过程中去进 ⾏创建,对于多例Bean会在每次获取Bean时利⽤BeanDefinition去创建
4. 利⽤BeanDefinition创建Bean就是Bean的创建⽣命周期,这期间包括了合并BeanDefinition、推断 构造⽅法、实例化、属性填充、初始化前、初始化、初始化后等步骤,其中AOP就是发⽣在初始化 后这⼀步骤中
5. 单例Bean创建完了之后,Spring会发布⼀个容器启动事件
6. Spring启动结束
7. 在源码中会更复杂,⽐如源码中会提供⼀些模板⽅法,让⼦类来实现,⽐如源码中还涉及到⼀些
BeanFactoryPostProcessor和BeanPostProcessor的注册,Spring的扫描就是通过
BenaFactoryPostProcessor来实现的,依赖注⼊就是通过BeanPostProcessor来实现的
8. 在Spring启动过程中还会去处理@Import等注解
52.Spring用到了哪些设计模式
53. Spring Boot中常用注解及其底层实现
1. @SpringBootApplication注解:这个注解标识了⼀个SpringBoot⼯程,它实际上是另外三个注解的 组合,这三个注解是:
a. @SpringBootConfiguration:这个注解实际就是⼀个@Configuration,表示启动类也是⼀个 配置类
b. @EnableAutoConfiguration:向Spring容器中导⼊了⼀个Selector,⽤来加载ClassPath下
SpringFactories中所定义的⾃动配置类,将这些⾃动加载为配置Bean
c. @ComponentScan:标识扫描路径,因为默认是没有配置实际扫描路径,所以SpringBoot扫描的路径是启动类所在的当前⽬录
2. @Bean注解:⽤来定义Bean,类似于XML中的<bean>标签,Spring在启动时,会对加了@Bean注 解的⽅法进⾏解析,将⽅法的名字做为beanName,并通过执⾏⽅法得到bean对象
3. @Controller、@Service、@ ResponseBody、@Autowired都可以说
54.Spring Boot是如何启动Tomcat的
1. ⾸先,SpringBoot在启动时会先创建⼀个Spring容器
2. 在创建Spring容器过程中,会利⽤@ConditionalOnClass技术来判断当前classpath中是否存在
Tomcat依赖,如果存在则会⽣成⼀个启动Tomcat的Bean
3. Spring容器创建完之后,就会获取启动Tomcat的Bean,并创建Tomcat对象,并绑定端⼝等,然后 启动Tomcat
55.Mybatis的优缺点
优点:
1. 基于 SQL 语句编程,相当灵活,不会对应⽤程序或者数据库的现有设计造成任何影响,SQL 写在 XML ⾥,解除 sql 与程序代码的耦合,便于统⼀管理;提供 XML 标签, ⽀持编写动态 SQL 语
句, 并可重⽤。
2. 与 JDBC 相⽐,减少了 50%以上的代码量,消除了 JDBC ⼤量冗余的代码,不需要⼿动开关连
接;
3. 很好的与各种数据库兼容( 因为 MyBatis 使⽤ JDBC 来连接数据库,所以只要JDBC ⽀持的数据库 MyBatis 都⽀持)。
4. 能够与 Spring 很好的集成;
5. 提供映射标签, ⽀持对象与数据库的 ORM 字段关系映射; 提供对象关系映射标签, ⽀持对象关 系组件维护。
缺点:
27 1. SQL 语句的编写⼯作量较⼤, 尤其当字段多、关联表多时, 对开发⼈员编写SQL 语句的功底有⼀定要求。
2. SQL语句依赖于数据库, 导致数据库移植性差, 不能随意更换数据库。
56.#{}和${}的区别是什么?
#{}是预编译处理、是占位符, ${}是字符串替换、是拼接符。 Mybatis在处理#{}时,会将sql中的#{}替换为?号,调⽤ PreparedStatement 来赋值; Mybatis在处理${}时,会将sql中的${}替换成变量的值,调⽤ Statement 来赋值; 使⽤#{}可以有效的防⽌ SQL 注⼊, 提⾼系统安全性
57.索引的基本原理
索引⽤来快速地寻找那些具有特定值的记录。如果没有索引,⼀般来说执⾏查询时遍历整张表。
索引的原理:就是把⽆序的数据变成有序的查询
1. 把创建了索引的列的内容进⾏排序
2. 对排序结果⽣成倒排表
3. 在倒排表内容上拼上数据地址链
4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从⽽拿到具体数据
58.索引设计的原则?
查询更快、占⽤空间更⼩
1. 适合索引的列是出现在where⼦句中的列,或者连接⼦句中指定的列
2. 基数较⼩的表,索引效果较差,没有必要在此列建⽴索引
3. 使⽤短索引,如果对⻓字符串列进⾏索引,应该指定⼀个前缀⻓度,这样能够节省⼤量索引空间, 如果搜索词超过索引前缀⻓度,则使⽤索引排除不匹配的⾏,然后检查其余⾏是否可能匹配。
4. 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改表内容的时候,索引会进 ⾏更新甚⾄重构,索引列越多,这个时间就会越⻓。所以只保持需要的索引有利于查询即可。
5. 定义有外键的数据列⼀定要建⽴索引。
6. 更新频繁字段不适合创建索引
7. 若是不能有效区分数据的列不适合做索引列(如性别,男⼥未知,最多也就三种,区分度实在太低)
8. 尽量的扩展索引,不要新建索引。⽐如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修 改原来的索引即可。
9. 对于那些查询中很少涉及的列,重复值⽐较多的列不要建⽴索引。
10. 对于定义为text、image和bit的数据类型的列不要建⽴索引。
59.事务的基本特性和隔离级别
事务基本特性ACID分别是:
原⼦性指的是⼀个事务中的操作要么全部成功,要么全部失败。
⼀致性指的是数据库总是从⼀个⼀致性的状态转换到另外⼀个⼀致性的状态。⽐如A转账给B100块钱, 假设A只有90块,⽀付之前我们数据库⾥的数据都是符合约束的,但是如果事务执⾏成功了,我们的数据库 数据就破坏约束了,因此事务不能成功,这⾥我们说事务提供了⼀致性的保证 隔离性指的是⼀个事务的修改在最终提交前,对其他事务是不可⻅的。 持久性指的是⼀旦事务提交,所做的修改就会永久保存到数据库中。 隔离性有4个隔离级别,分别是:
- read uncommit 读未提交,可能会读到其他事务未提交的数据,也叫做脏读。⽤户本来应该读取到id=1的⽤户age应该是10,结果读取到了其他事务还没有提交的事务,结果读取 结果age=20,这就是脏读。
- read commit 读已提交,两次读取结果不⼀致,叫做不可重复读。不可重复读解决了脏读的问题,他只会读取已经提交的事务。⽤户开启事务读取id=1⽤户,查询到age=10,再次读取发现结果=20,在同⼀个事务⾥同⼀个查询读取到不同的结果叫做不可重复读。
- repeatable read 可重复复读,这是mysql的默认级别,就是每次读取结果都⼀样,但是有可能产 ⽣幻读。
- serializable 串⾏,⼀般是不会使⽤的,他会给每⼀⾏读取的数据加锁,会导致⼤量超时和锁竞争 的问题
60.什么是MVCC
.