面试题01
1.常见的SQL优化方法
- 尽量避免使用子查询
- MySQL是先查外表,再查内表,如果外表数据量大时,查询就会很慢
- 使用jion关联查询,这样就不用在内存中创建临时表
- 用IN来替换OR
- MySQL对in做了相应优化,in中的常量全部存在一个排好序的数组里
- 当数量多是,产生消耗大,对于连续值,可以使用between或者连接
- 避免使用select *,只返回必要的列
- select会浪费资源
- select *不会走覆盖索引,会出现大量的回表操作,而从导致查询sql的性能很低
-
多使用limit
-
尽量使用数字型字段,而不是字符型
- 字符型在查询和连接时是挨个比较每一个字符,而数字型只会比较一次
-
只需要一条数据时,使用limit 1
-
高效的分页
-
jion的表不应过多(不超过三个)
-
小表驱动大表
- in 的话里面驱动外面,in适合里子查询是小表
- exist 的话外面驱动里面,适合外面是小表
- 批量插入数据
- 避免不必要的order by
- 避免会使索引失效的操作
2,MySQL索引会在哪些情况下失效
- 非最左匹配:不是最左边的字段为起点查询,联合索引会失效
- 错误的模糊查询:以百分号开头的模糊查询
- 列运算
- 使用函数
- 类型转换:如address=123(address为varchar类型)
- is not null或者 is null
3,MySQL数据库innodb引擎索引底层实现的原理及查找过程
- innodb索引中主要包含主键索引和辅助索引,它们都是通过B+Tree实现的。B+树是一种多路搜索树,它的每个节点都可以存储多个关键字和数据,而且每个节点都有指向下一个节点的指针。
- 在使用主键进行数据查询时,通过主键索引找到对应的叶子节点,然后得到叶子节点上的数据。
- 而通过辅助索引查找数据时,首先找到叶子节点,得到对应的主键,然后再通过主键值作为查询条件到主键索引上找到对应的叶子节点得到数据。
4,innodb引擎与myisam引擎索引的区别
InnoDB 和 MyISAM 是 MySQL 的两种常用存储引擎。它们在索引方面的主要区别在于:
- InnoDB 使用聚集索引,数据文件本身就是主索引文件。InnoDB 的辅助索引 data 域存储相应记录主键的值而不是地址。这意味着 InnoDB 的主键索引的叶子节点存储着行数据,主键索引非常高效。
- MyISAM 使用非聚集索引,索引和数据文件是分开的。MyISAM 索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据。MyISAM 的辅助索引和主索引没有多大区别。
其它区别还有
- innodb支持事务,而myisam不支持
- innodb支持外键,而myisam不支持,所以有外键的innodb表不能转换成myisam
- innodb不保存表的具体行数,select count() 会全表扫描,而myisam保存了表的行数,count()查询速度很快
- innodb不支持全文索引,而myisam支持全文索引
5,ArrayList和LinkedList的区别
- ArrayList内部是由数组实现的,因为地址是连续的,所以查数据很快,但增删除数据很慢,因为其增删除数据需要将后面的所有数据重新排列,其基础容量是10,每次进行1.5倍扩容
- LinkedList内部是由双向链表实现的,地址不连续,在增删方面性能优于ArrayList,但是查询相对较弱
- LinkList实现了堆栈和队列的功能,ArrayList并没有实现堆栈、队列的功能
6,常见设计模式
- 单例模式:只允许创建一个对象,不会频繁创建和销毁对象,节省内存,避免浪费资源
- 懒汉模式:用的时候再去创建对象
//线性安全的懒汉模式
public class Singleton {
//声明对象,不实例化
private static Singleton instance;
//构造函数私有化
private Singleton() {}
//向外提供访问该类的接口
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//双检锁的单例模式
public class Singleton {
private volatile static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
- 饿汉模式:提前加载好的静态static对象
public class Singleton {
//声明对象的时候同时私有化
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
- 代理模式:对其它对象提供一种代理以控制对这个对象的访问,分为静态代理和动态代理
-
静态代理:一般是程序员自己实现或者工具实现,在编译时就将接口实现类和代理类确定好了
-
动态代理:在运行时创建的代理方式,分为jdk动态代理和cglib动态代理
-
jdk代理只能对实现了接口的类进行代理,而cglib代理可以对普通类进行代理;
-
由于cglib代理是为目标类生成了一个子类,并对父类方法进行增强,所以目标类不能用final修饰;
-
jdk动态代理是利用拦截器,加上反射机制生成一个实现代理接口的匿名类。它跟被代理类相当于兄弟关系
-
cglib则是通过利用ASM开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
-
- 观察者模式:定义对象间一对多的关系依赖关系,当被观察者状态发生改变时,其相关依赖对象,也就是观察者都得到通知做出响应,从观察者角度看是观察者模式,从被观察者角度又叫做发布订阅模式
- 装饰器模式:动态的给一个对象添加额外的功能,而又不改变其结构,跟代理模式区别是代理模式重在对访问权限的控制,而装饰器模式重在对功能的增强
- 适配器模式:将一个类的接口变成客户端所期望的另一种接口,可以在不破坏原系统的情况下,让两个不相关的类一起工作,适配器分为
- 类适配器:继承被适配的对象,实现想要的接口
- 对象适配器:实现想要的接口,用有一个被适配的对象
- 缺省适配器:通过抽象类实现被适配接口,然后用户类继承适配器类,达到只实现想要的方法的目的
- 工厂模式:
- 简单工厂的实现思路是,定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。
- 工厂方法模式是简单工厂的仅一步深化, 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。工厂方法的实现思路是,定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
- 抽象工厂模式是工厂方法的仅一步深化,在这个模式中的工厂类不单单可以创建一个对象,而是可以创建一组对象。抽象工厂的实现思路是,提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
7,对IOC和DI的理解
- IOC:控制反转,控制就是对对象创建的控制,传统方式是在对象内部使用new创建对象,这样耦合度高,不利于功能复用,而IOC是将对象的创建交给IOC容器,在使用的时候注入就行,而不用new创建对象,反转就是获取依赖对象的反转,之前是对象主动获取依赖对象,而现在是被动接收注入的依赖
- DI:依赖注入,即应用程序依赖于IOC容器,程序在运行时IOC容器动态注入应用程序需要的外部资源
- 可以说IOC是一种思想,而DI是实现这种思想的具体实现方式,是同一概念的不同角度的描述
8,springbean的生命周期
- springbean生命周期分为四个阶段:实例化,属性赋值,初始化,销毁
- 实例化bean
- 设置对象属性
- 处理Aware接口:根据对象实现不同的aware接口,注入相关的aware实例
- 如果想对bean进行自定义处理,让bean实现BeanPostProcessor接口,调用其方法
- InitializingBean和init-method:如果实现了InitializingBean接口,执行afterProperitesSet()方法
如果配置了init-method属性,会自动调用初始化方法
- 如果想要增强bean,实现BeanPostProcessor接口,调用postProcessAfterInitialization()方法,使用aop达到增强的目的
- 如果bean实现了DisposableBean接口,如果不再需要bean,执行清理,调用destroy()方法
- 如果spring配置了destroy-method方法,会自动调用其销毁方法
9,对AOP的理解
- AOP:面向切面编程,AOP是基于动态代理实现的,将那些与业务无关,但却为业务模块所共同调用的责任和逻辑,抽取并封装为一个可重用的模块,也就是切面,通过将横切逻辑代码与业务代码分离,在不改变原有代码的基础下,将逻辑增强部分应用到原有业务中,从根本上解耦,避免大量的重复操作,降低了模块间的耦合度,提高了系统的可维护性
10,对象创建方式
- new创建新对象
- 反射创建对象
- clone机制创建
- 序列化创建