中电信数智科技 后端 30min
- 自我介绍
- 老家
- 当前工作ip地
- 当前工作项目中你任务挑战/有难点的地方,怎么解决的衍生问题,为什么是用了这个方案而不是其他的?
- spring中bean的生命周期
- beanDefinition加载解析的过程
- 数据库索引失效的场景
- 左连接、右连接会导致索引失效吗?
- 有多个会议室,把每天进入和出入会议室的人员列表展示出来,列表展示的有:名称、地址、姓名、职务和时间。做对应的表设计
- 冒泡排序最好和最坏的情况下的复杂度
- 垃圾回收的几种算法(了解的话讲一下)
- tcp三次握手四次挥手的过程
- @Transactional失效的7中场景和原因
个人复盘&答案整理:
- 自我介绍确实是没有背很熟
- 项目中的挑战点问题,activiti工作流的引入项目为什么对我来说是难的,第一步,清晰的介绍这个难点解决方案,一步步介绍,清晰的展示你的思考和你的想法
- 为什么用activti,直接给到惯性去是用确实糟糕,而且没有给到当时选择的环境(老板希望快速出粗糙版本的大前提),像面试官提到应该更具业务去比对选择适合的工作流,这里可以展开到对技术的了解,侧面反映技术的广度。
- bean生命周期实例化:
- 创建Bean的实例。 实现了BeanNameAware的接口,将是用这里指定的beanName实现了BeanFactoryAware接口则获取到BeanFactory的实例,通过工厂实例获取对象实现了ApplicationContextAware接口,则从上下文中获取属性赋值:为Bean的属性设置值和依赖关系。 实现了BeanPostProcessor接口,需要在初始化前后去执行指定代码初始化:Bean在设置了所有属性之后,需要执行初始化逻辑。 实现了InitializingBean接口,执行afterPropertiesSet()方法等同于init-method销毁:当容器关闭时,Bean需要执行清理逻辑。 实现了DisposableBean接口,Spring将调用它的destory()接口方法等同于destory-method
- beanDefinition加载解析的过程
- 通过BeanDefinitionReader 将配置类(AnnotatedBeanDefinitionReader)(xml文件:XmlBeanDefinitionReader) 注册为BeanDefinition
- 解析配置类ConfigurationClassParser(xml文件:BeanDefinitionDocumentReader)不同的注解(xml节点)有不同的解析器。
- 比如ComponentScan 需要通过ClassPathBeanDefinitionScanner扫描所有类找到类上面有@Import的类
- 将读取到的Bean定义信息通过BeanDefinitionRegistry注册为一个BeanDefinition
- 数据库索引失效索引
- 使用左后者左右模糊匹配
- 对索引是用函数
- 对索引进行表达式计算
- 对索引隐式类型转换
- 联合索引非做做匹配
- where字句中的or
- 左连接、右连接会导致索引失效吗?不会,不属于这些失效场景。
- 会议需求的表设计(来自kimi)room id PK | name | addressuser id PK | name | titleroom_access id PK | room_id FK(room.id) | user_id FK(user.id) | access_time DATETIME | direction ENUM('IN','OUT')查询时把 access_time 拆成“日期 + 时间”两列即可。
- 冒泡排序
- 空间复杂度都为 O(1),时间复杂度可以分为三种情况:
- 最优情况:当输入数据已经是有序的,只需要进行一次遍历即可完成排序。此时的时间复杂度为 O(n)。
- 最差情况:当输入数据是完全逆序的,每次遍历都需要交换元素。此时的时间复杂度为 O(n^2)。
- 平均情况:在一般情况下,冒泡排序的时间复杂度为 O(n^2)。
- 垃圾回收算法
- 引用计数法:通过计数对象的引用数来判断对象是否可以回收。当对象的引用数降至零时,对象被认为是垃圾并可以被回收。然而,这种方法无法解决循环引用的问题。
- 可达性分析:从一系列的“GC Roots”开始,如果某个对象到GC Roots没有任何引用链,则该对象是不可达的,因此可能成为垃圾对象。
- 标记-清除算法:将垃圾回收分为标记和清除两个阶段。首先标记所有从根节点开始可达的对象,然后清除所有未被标记的对象。这种算法的缺点是会产生内存碎片。
- 复制算法:将内存分为两部分,活动对象被复制到未使用的内存区域,然后清除原有内存区域中的所有对象。这种算法适用于对象存活率不高的年轻代,但会浪费一半的内存空间。
- 标记-压缩算法:在标记阶段后,不是简单地清除未标记对象,而是将所有存活对象移动到内存的一端,然后清除边界外的内存。这种方法避免了内存碎片的产生。
- 分代收集算法:目前JVM使用的主要垃圾回收算法。它根据对象的生命周期将内存分为新生代和老年代,并在不同的代上使用不同的垃圾回收算法。新生代通常使用复制算法,而老年代使用标记-清除或标记-压缩算法。
- tcp三次握手四次挥手
- 握手:
- 客户端发送SYN包到服务器,进入SYN_SENT状态。(证明客户端的发送能力正常)
- 服务器确认收到SYN包,发送SYN+ACK包,进入SYN_RECV状态。(证明服务器端的接收能力、发送能力正常)
- 客户端收到SYN+ACK包后,发送ACK包,连接建立成功。(证明客户端的接收能力正常)
- 挥手:
- 客户端发送FIN包,表示要关闭连接。
- 服务器确认收到FIN包,发送ACK包。
- 服务器发送FIN包,表示也要关闭连接。
- 客户端确认收到FIN包,发送ACK包,连接关闭成功。
- 事务
- 类没被 Spring 管理(Spring 根本不知道要给你生成代理对象,事务自然无效。)
- 方法不是 public(如果用在 private/protected 方法,或者默认包访问权限的方法,事务会直接失效(底层代理机制限制)。)
- 异常类型不对,默认只回滚运行时异常(Spring 默认只会对 RuntimeException 及其子类 (比如 NullPointerException、IllegalArgumentException)触发事务回滚。)需要指定的回滚异常:@Transactional(rollbackFor = {SQLException.class, IOException.class})
- 同一类内方法调用(通过生成代理对象来实现事务的。如果在同一个类里,非事务方法直接调用事务方法(比如 this.xxx()),此时用的是 this(真实对象),而不是代理对象,事务就失效了。)
- 没配置事务管理器(spring boot项目多数据源需要手动配置)
- 传播行为配置错误(@Transactional 的 propagation 属性控制事务的传播行为。如果配置不当,比如用了 Propagation.NOT_SUPPORTED(不支持事务),或者 Propagation.SUPPORTS(有事务就加入,没有就非事务执行),可能导致事务失效。)
- 数据库不支持事务(使用 MySQL 的 MyISAM 引擎(不支持事务),或者执行了不支持事务的 DDL 语句(比如建表)。)