面试整理
1,数据库优化? 1、查询语句中不要使用 * 2、尽量减少子查询,使用关联查询(left join,right join,inner join)替代 3、减少使用IN或者NOT IN ,使用exists,not exists或者关联查询语句替代 4、or 的查询尽量用 union或者union all 代替 5、避免where子句中对字段null,!=,<>,in,not in,模糊查询%abc%判断,避免全盘扫描 6、增加中间表进行优化 7、建表的时候能使用数字类型的字段就使用数字类型,数字类型的字段作为条件查询比字符串的快 8、那些可以过滤掉最大数量记录的条件必须写在WHERE子句的最末尾 2,重载(构造方法)和重写(重写方法)? 重载:定义:方法名相同,参数类型或个数不同,对权限没要求,在一个类中发生 重写:定义:方法名,参数类型,返回类型全相同,被重写方法权限不能更严格,发生继承类中 3,接口interface(实现)和抽象类abstract(继承) 接口不能方法声明,抽象类可以声明和实现 有抽象方法就是抽象类,抽象类可以无抽象方法 一个类可实现多个接口,只能继承一个抽象类 4,java中有几种类型的流 字符流和字节流 字节流继承inputStream和OutputStream 字符流继承自InputSteamReader和OutputStreamWriter
请求方式:PUT 请求路径:/索引库名 请求参数:json格式 { "settings": { "number_of_shards": 3, "number_of_replicas": 2 } } settings:索引库的设置 number_of_shards:分片数量 number_of_replicas:副本数量 查看索引设置 type - String类型,又分两种: - text:可分词,不可参与聚合 - keyword:不可分词,数据会作为完整字段进行匹配,可以参与聚合 - Numerical:数值类型,分两类 - 基本数据类型:long、interger、short、byte、double、float、half_float - 浮点数的高精度类型:scaled_float - 需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。 - Date:日期类型 elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。 index index影响字段的索引情况。 - true:字段会被索引,则可以用来进行搜索。默认值就是true - false:字段不会被索引,不能用来搜索 index的默认值就是true,也就是说你不进行任何配置,所有字段都会被索引。 但是有些字段是我们不希望被索引的,比如商品的图片信息,就需要手动设置index为false。 store 是否将数据进行额外存储。 在学习lucene和solr时,我们知道如果一个字段的store设置为false,那么在文档列表中就不会有这个字段的值,用户的搜索结果中不会显示出来。 但是在Elasticsearch中,即便store设置为false,也可以搜索到结果。 原因是Elasticsearch在创建文档索引时,会将文档中的原始数据备份,保存到一个叫做`_source`的属性中。而且我们可以通过过滤`_source`来选择哪些要显示,哪些不显示。 而如果设置store为true,就会在`_source`以外额外存储一份数据,多余,因此一般我们都会将store设置为false,事实上,**store的默认值就是false。** match`类型查询 会把查询条件进行分词,然后进行查询,多个词条之间是or的关系 and关系 只有同时包含`大牛`和`手机`的词条才会被搜索到 `match` 查询支持 `minimum_should_match` 最小匹配参数 通常设置为一个`百分数` 2*50%=1 2*0.99<2 1
缓存+Redis 需要加入data-redis启动器,cache启动器 用enablecaching标注主配置类开启缓存 redis需要在properties加入redis的地址 在方法上加入: @cacheable 查询方法,添加缓存到redis @cacheput 修改方法,更新缓存的内容并且更新缓存方法 @cacheevict 删除方法,清空缓存 @caching 可以定义复杂的缓存规则 自定义keyGenerator,key的生成规则 可以定义redisTemplate(可以定义json序列化保存) 和 cacheManager(定义json保存) 使用RedisTemplate 来操作redis redisTemplate.opsForValue();//操作字符串 redisTemplate.opsForHash();//操作hash redisTemplate.opsForList();//操作list redisTemplate.opsForSet();//操作set redisTemplate.opsForZSet();//操作有序set
消息+RabbitMQ 消息通信机制 点对点,消息只有一个唯一的发送者和接受者,但可以有什么接收者 发布订阅,发布到一个主题,通过接收者订阅这个主题,就可以在消息到达时收到消息 RabbitMQ Publisher,消息发送者 Exchange,交换器,类型默认点对点(direct),发布订阅(fanout,topic,headers) Queue,消息队列,放消息进去,直到取走才会在消息队列中去除 Binding,绑定,Exchange和Queue之间的多对多 点对点,direct 广播,fanout 匹配发送,topic 192.168.1.104 exchanges>>>add a new exchange(name:自定义交换器名,type:类型,durability:Durable持久化) queue>>>add a new queue(name:自定义消息名) exchange>>>add exchanges(name点进去)>>> bindings direct,fanout:(to queue:需要绑定的消息名 routing key:绑定的路由键,与上面相同) topic:(to queue:需要绑定的消息名 routing key:绑定的路由规则,#匹配0个或多个 *匹配一个) publish message(routing key:发送的路由键 payload:发送的内容) direct:只能发送给exchange绑定的路由键与指定的队列 fanout:不管发送上面路由键都会发送给全部绑定的队列 queue>>>all queues>>>name点进去>>>get messages(messages:获取的条数) nack mode:ack messages requeue true,只获取 ack mode:ack messages requeue false,获取之后并删除 IDEA: 引入amqp启动器, 在测试类中直接使用RabbitTemplate操作发送,接收消息,接收后从队列中移除 使用AmqpAdmin创建exchange,queue,binding,routing key 要想使用@RabbitListener需要在主配置类开启@EnableRabbit 运行主配置类,在@RabbitListener中监听的队列收到消息后被接收,队列中不会再有
1,微服务 2,多线程和本地线程的实现逻辑 3,java各种集合区别 4,如何处理好高并发 5,springboot和spring区别 集合有key,key-value两种 key有list和set list有序,可以重复 LinkedList没有同步,ArrayList非同步的,Vector同步的(同ArrayList) set无序,不可重复,根据equals和hashcode判断 key-value有map ArrayList(数组)和LinkedList(链表)区别? ArrayList,查询快,插入删除比较慢(需要移动内存), LinkedList,查询慢(从头部一个一个找,效率低),插入删除改比较快(不需要移动内存,只需要改变引用指向) ArrayList用于查询比较多,插入删除比较少,LinkedList用于查询少,插入删除比较多 HashMap与HashTable区别? 都是存储key-value数据 HashMap可以把null作为key或value,则HashTable不可以 HashMap是线程不安全,效率高,HashTable线程安全,效率低 存储过程procedure 1,执行速度快,创建时编译,以后就直接调用 2,可重复使用,减少工作量 3,安全性高,execute调用 //调用储存过程?代表一个参数 CallableStatement statement=connection.prepareCall("{?=call func(?)}"); //给第一个?设置参数类型为NUMBER statement.registerOutParameter(1,OracleTypes.NUMBER); String,StringBuffer,StringBuilder String内容不可变,private final char value[] StringBuffer,StringBuilder内容可变,没有final修饰 String a="b"+"c";创建了三个对象 StringBuffer a=new StringBuffer();a.append("a").append("b");创建一个对象 拼接字符串不用StringBuffer,StringBuilder拼接, StringBuffer线程安全,效率低 StringBuilder线程不安全,效率高 线程 实现方式 继承Thread类,实现Runnable接口 启动,DiyThread继承Thread类,DiyRunnable实现Runnable接口 Thread thread=new Thread(new DiyThread()); Thread thread=new Thread(new DiyRunnable()); 启动线程使用start方法,启动后执行run方法 区分线程,setName设置名称 创建线程池,new FixedThreadPool 线程池的作用 限定线程个数,不会由于线程多系统崩溃 节约资源不用每次都去创建和销毁 响应时间快,不需每次都创建 ==与equals ==比较值,equals比较引用对象 final 修饰变量必须赋初值,不能改变 修饰类不能被继承 方法不能重写 事务 @Transactional 标注public方法 commit提交,rollback回滚 事务的四大特征 1.原子性:一个事务中所有对数据库的操作要么全做要么全不做 2.一致性:事务的执行的前后数据的完整性保持一致 3.隔离性:一个事物的执行,不受其他事务的干扰 4.持久性:一个事物一旦提交,它对数据库的改变就是永久的 四个隔离级别 2.read_uncommitted: 读未提交,一个事务可以感知或者操作另外一个未提交的事务,可能会出现脏读、不可重复读、幻读 3.read_committed:读已提交,一个事务只能感知或者操作另一个已经提交的事务,可能会出现不可重复读、幻读 4.repeatable_read:可重复读,能够避免脏读,不可重复读,不能避免幻读 4.serializable:串行化,隔离级别最高,消耗资源最低,代价最高,能够防止脏读, 不可重复读,幻读。 七个传播特性 1、Propagation.REQUIRED 调用方已经存在事务,则加入到同一个事务中运行,否则,自启一个事务 2、Propagation.REQUIRES_NEW 无论何时自身都会开启新事务 3、Propagation.SUPPORTS 调用方存在事务,则加入到同一个事务中运行,若不存在事务,则以非事务的方式运行 4、Propagation.NOT_SUPPORTED 调用方存在事务,则会被挂起,直到被调用方运行完毕后,事务恢复。 5、Propagation.MANDATORY 调用方存在事务,则加入到同一个事务中运行,若不存在,则抛出异常 6、Propagation.NEVER 调用方存在事务,则抛出异常 7、Propagation.NESTED 若调用方存在事务,则运行一个嵌套事务,若调用方不存在事务,则以Propagation.REQUIRED的方式运行,即开启一个新的事务 线程 主线程默认名字总是mian 获取当前线程的对象的方法是:Thread.currentThread() start()创建启动新线程,实现多线程工作,使线程处于可运行状态,run方法被当做线程执行体来处理 无需等待run方法运行完毕直接运行下面的代码,再运行run,run方法结束,线程终止 run()被当成是一个方法调用,无法开启新线程 会调用完run方法再执行下面代码 线程五种状态 新建状态:线程对象已经创建,还没有在其上调用start()方法。 可运行状态: 线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。 当start()方法调用时,线程首先进入可运行状态。 在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。 运行状态: 线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。 阻塞/阻塞/睡眠状态: 这是线程有资格运行时它所处的状态。 实际上这个三状态组合为一种,其共同点是:线程仍旧是活的,但是当前没有条件运行。 换句话说,它是可运行的,但是如果某件事件出现,他可能返回到可运行状态。 死亡状态: 当线程的run()方法完成时就认为它死去。 线程一旦死亡,就不能复生。 如果调用start()方法,会抛出java.lang.IllegalThreadStateException异常。 Thread.sleep(3) 当前线程睡眠3毫秒,执行其他线程,由运行状态转为可运行状态 1、线程睡眠是帮助所有线程获得运行机会的最好方法。 2、线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。 sleep()中指定的时间是线程不会运行的最短时间。 因此,sleep()方法不能保证该线程睡眠到期后就开始执行。 3、sleep()是静态方法,只能控制当前正在运行的线程。 Thread.yield();会先去判断是否有和当前线程相同优先级的线程 如果没、则自己继续执行、如果有、自己进入可运行状态 必须在同步块或者同步方法中进行 wait(1000);导致当前线程等待、释放锁、直到其他线程调用此对象的 notify()或 notifyAll()、或超过指定时间 notify();能够唤醒一个正在等待这个对象的锁的线程、如果有多个线程都在等待这个对象的锁、则只能唤醒其中一个线程 notifyAll();能够唤醒所有正在等待这个对象的锁的线程
反射 获取类的 Class 对象实例class.forName("全路径名") 根据 Class 对象实例getConstructor()获取 Constructor 对象 使用 Constructor 对象的 newInstance() 方法获取反射类对象Object Class 对象的getMethod(参数)获取Method 对象 利用Method 对象的 invoke 方法调用方法 SpringMVC的流程 用户发送请求给dispatchservlet dispatchservlet去调用handdle Mapping查找对应的handle路径 handler根据适配调用Controller,执行完成返回modelAndView dispatchservlet再调用ViewReslover去解析返回一个view dispatchservlet根据model渲染视图响应给用户 索引失效 1,varchar2类型没有加引号,错误column=abc ,正确column="abc" 2,不能对索引进行运算,错误column-1=9 ,正确column=10 spring,springmvc,springboot,springcloud区别? 数据库适合创建索引的规则如下 经常出现在where子句中的字段,应该创建索引 表的主键,外键应该创建索引 数据量比较大的表应该创建索引 经常需要和其他表建立连接,在连接字段应该创建索引 经常出现在where子句中的字段,应该创建索引。 数据库不适合创建索引的情况 比较大的文本字段或者长度较长的字段,不适合创建索引 频繁进行数据操作的表,不适合创建过多的索引 小型表(数据量低于300行)不要建立索引。 Redis使用场景 作为缓存功能,减少后端的压力,加速读写 用户登录来存取session 哈希可以储存用户信息, 解决Redis缓存穿透 查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到DB去查询, 加锁,单机用syn同步锁,分布式环境用分布式琐 接口降级,熔断,失败快速返回机制 空结果进行缓存设置一个时间,最长不超过五分钟 解决Redis缓存雪崩: 设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩 加一个随机失效时间,1-5分钟 缓存击穿 一个key的时间到期,这是很多请求对这个key进行访问,只能我DB查询,大并发的请求可能会瞬间把后端DB压垮。 设置不过期