Java常见面试题

面试之路,怎么少的了刷题那。
以下是基于java SE部分的面试题的汇总,有什么不当之处,请留言。

JAVA基础部分

讲一下String 和 StringBuilder 的区别(final) ?StringBuffer和StringBuilder的区别?
  • 在java中提供三个类String、StringBuffer StringBuilder 来表示和操作字符串,字符串就是多个字符串的集合。
  • String 是内容不可变的字符串。String 底层使用了一个不可变的字符串数组 final char []
    /** The value is used for character storage. */
    private final char value[];
  • StringBuilder StringBuffer 是内容可以改变的字符串。底层使用的是可变的字符数组(没有使用final 来修饰)
    /**
     * The value is used for character storage.
     */
    char[] value;
  • 最经典的就是拼接字符串
  1. StringBuilder是线程不安全的,效率较高,而StringBuffer是线程安全的,效率较低。
 public synchronized void setCharAt(int index, char ch) {
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        toStringCache = null;
        value[index] = ch;
    }
讲一下 java中的集合?
  • java 中的集合分为 value, key-value 两种 (collection, Map)两种
  • 存储值的又分为 List、Set
  1. List 是有序的,可以重复的。
  2. Set 是无序的,不可以重复的。根据equals和hashcode 判断,如果一个对象要存储在set中,必须重写equals 和 hashcode方法
  3. ArrayList 和 LinkedList 的区别?
  4. List 常用的ArrayList 和LinkedList ,ArrayList底层使用的是数组。
// ArrayList
transient Object[] elementData  
----------------------------------------------------------------
// LinkedList
Node<E> last
private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
  1. 数组查询特定元素比较快。而插入和删除和修改比较慢(数组在内存中是一块连续的内存,如果插入或删除是需要移动内存。)
    而链表不要求地址内存是连续的,在当前元素中存放下一个或上一个元素的地址。查询时需要从头部开始,一个一个找,所以查询效率低。插入时不需要移动内存,只需要改变引用指向即可,所以插入或者删除的效率高。
  • ArrayList 使用在查询比较多,但是插入和删除比较少的情况。 而LinkList 使用在查询比较少,而插入删除比较多的场景下。
实现一个拷贝文件的工具类,使用字节流还是字符流?
  1. 我们拷贝的文件不确定是只包含字符流,有可能有字节流,为了考虑到工具的通用型,要使用字节流。
讲一下线程的几种实现方式?
  1. 通过继承Thread 类实现一个线程。
  2. 通过实现Runnable接口实现一个线程。继承扩展性不强,java中只支持单继承,如果一个类继承Thread类,就不能继承其他的类了。
    怎么启动?
  3. new Thread(继承了Thread的对象\实现了Runnable的对象)
  4. 启动线程使用start方法,而启动以后执行的是 run方法。
  • 怎么区分线程? 在一个系统中有很多线程,每个线程都会打印日志,我想区分是哪个线程打印的怎么办?
  1. thread.setName("设置一个线程名称”), 在创建线程完成后,都需要设置名称。
有没有使用过线程并发库?

JDK5增加了 java.util.current包中提供了对线程的优化、管理的各项操作。
java通过Executors提供了四个静态方法创建线程池,分别为:

  1. Executors.newCachedThreadPool(); // 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  2. Executors.newFixedThreadPool(1); // 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  3. Executors.newScheduledThreadPool(10); // 创建一个定长线程池,支持定时及周期性任务执行。
  4. Executors.newSingleThreadExecutor(); //创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO 优先级来执行)
    线程池的作用:
    限定线程的个数,不会导致由于线程过多导致系统运行缓慢或崩溃
    线程池在开始时创建线程,用完回收,不需要再频繁的创建和销毁了。
讲一下HashMap和HashTable的区别? HashMap 和 CurentMap的区别?
  • 相同点: HashMap 和 HashTable 都可以使用来存储key-value的数据
  • HashMap 是线程不安全的,效率较高。而HashTable是线程安全的,效率较低。
  • 想要线程安全又要保证效率,怎么办?ConcurrentHashMap
  • 通过把整个Map 分为N个Segment(段,每一个段类似于HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
什么是设计模式? 常用的设计模式有哪些?

设计模式是经过前任无数次的实践总结出来的,设计过程中可以反复使用的,可以解决特定的问题的设计方法。

  1. 单例模式:
    ① 构造方法私有化
    ② 在自己的类中创建一个单实例
    ③ 提供一个方法获取该实例对象

饿汉模式:

public class SingleObject {
 
   //创建 SingleObject 的一个对象
   private static SingleObject instance = new SingleObject();
 
   //让构造函数为 private,这样该类就不会被实例化
   private SingleObject(){}
 
   //获取唯一可用的对象
   public static SingleObject getInstance(){
      return instance;
   }
}

懒汉模式:

 public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}
  1. 工厂模式:SpringIOC 就是使用了工厂模式(对象的创建交给一个工厂去创建,自己不用new)
  2. 代理模式:SpringAOP就是使用了动态代理。
  3. 包装模式

Java WEB方面

讲一下http get和post请求的区别?
  • Get 和Post 请求都是http的请求方式,用户通过不同的http的提交方式完成对资源(url)的操作。具体点来讲Get 一般用于获取/查询 资源信息,而Post 一般用于更新资源信息。Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是Get、Post、PUT、DELETE URL全称是资源描述符,我们可以这样认为,一个url地址,它用来描述一个网络上的资源,Http中的Get 、POST、PUT、DELETE 就对应着这个资源的查改增删 4 个操作。
  • 具体点来讲Get 一般用于获取/查询 资源信息,而post提交,地址栏不会改变,一把用于更新资源信息。
  • Get 请求提交的数据会在地址栏显示出来,而post请求不会再地址栏显示出来。Get提交,请求的数据会附在url之后,(就是把数据放置到http协议头中),以? 分割url 和传输数据,多个参数用&连接;post提交: 把提交的数据放置在是http包的包体中。因此,get请求的数据会在地址栏中显示出来,而post提交,地址栏不会改变。
  • 传输数据的大小
    http get 请求由于浏览器对地址长度的限制而导致传输的数据有限制。而post请求不会因为地址长度限制而导致传输数据限制
  • 安全性 post的安全性要不get的安全性高
讲一下Servlet的理解?

Servlet(Server Applet),全程java servlet,是用Java编写的服务器端程序,而这些Sevlet都要实现Servlet这个接口,其主要功能在于交互式的浏览器和修改数据,生成动态Web内容,Servlet运行与支持Java的应用服务器中。
HttpServlet,重写doGet 和 doPost 方法或者你也可以重写service方法完成对get和post请求的响应。

简单说一下 servlet的生命周期
  • servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servletServlet接口的init service 和 destory方法表达。
  • Servlet启动时,开始加载servlet声明周期开始。servlet被服务器实例化后,容器运行器init 方法。请求到达时,运行其service方法,service方法自动派遣运行与请求对应的doXX 方法(doGet, doPost)等,当服务器决定将实例销毁的时候调用其destory方法。
  • 加载servlet的class —> 实例化servlet —> 调用Service的Init完成初始化----> 响应请求-----> 响应请求service() ----> Service容器关闭时(调用service的destory方法)
Servlet API中 forward()和redirect()的区别?
  1. forward是服务器端的转向而redirect是客户端的跳转
  2. 使用forward浏览器的地址不会发生改变,而redirect会发生改变
  3. forward是一次请求中完成的,而redirect是重新发起请求
  4. forward是在服务器端完成,而不用客户端重新发起请求,效率较高
JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?

在这里插入图片描述

  • JSP是Servlet技术的扩展,所有的Jsp文件都会被翻译为一个继承HttpServlet的类,也就是说jsp最终也是一个Servlet。
  • JSP是Servlet技术的扩展,所有的jsp文件都会被翻译为一个继承HttpServlet的类。也就是jsp最终也是一个Servlet对外提供服务
  • Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和Html 可以组合成一个扩展名为.jsp的文件,JSP侧重于视图。Servlet主要用于控制逻辑。
  • Servlet如果要实现html的功能,必须使用Writer输出对应的html
JSP有哪些内置对象? 作用分别是什么?分别有什么方法?
对象作用
request用户端请求,此请求会包含来自Get/Post 请求的参数
response网页传回用户端的回应
pageContext网页的属性是在这里管理
session与请求有关的回话期
applicationContext正在执行的内容
out用来传送回应的输出
configservlet 的构架部件
pageJSP网页本身
exception针对错误网页
  • 四大作用域: pageContext,request,session,application 可以通过jstl 从四大作用域中取值。
  • JSP传递值: request,session,application,cookie 也能传值
Session和Cookie的区别?你在项目中哪些地方使用了?
  • Session和Cookie都是会话跟踪技术。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户信息。但是session的实现依赖于Cookie, (cookie中的 sessionId【唯一标识】 需要存放在客户端)
  • cookie和session的区别
  1. cookie数据存放在客户的浏览器上,session数据存放在服务器上。
  2. cookie不是很安全,别人可以分析放在本地的Cookie并进行cookie欺骗考虑到安全应使用session
  3. session会在一定时间内保存在服务器上。当访问增多,会比较占服务器的性能 ,(考虑到减轻服务器性能方面,应当使用cookie)
  4. 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie
  5. 个人建议: 登陆信息等重要信息放到session。 其他信息如果需要保留,可以放到cookie中。cookie是可以在客户端禁用的,这时候我们要使用cookie+数据库的方式实现。当从cookie中不能读出数据时,就从数据库中获取。
MVC的各个部分都有哪些技术来实现?
  • M (Model) 模型 javaBean
  • V (View )代码视图 html jsp freemark
  • C (Controll)控制器 Servlet, Action
  • 最经典的mvc模式: jsp + servlet + javaBean ,就是把视图和逻辑隔离开来。

数据库部分

数据库的分类:

关系型数据库和非关系型数据库

  • 常见的关系型数据库
    Mysql、Oracle、SqlServer
  • 非关系型数据库
    redis memcashe, mogoDb, hadoop等
简单介绍一下关系数据库三范式
  • 要想满足第二范式必须先满足第一范式,要满足第三范式必须先满足第二范式
  1. 第一范式: 是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。
  2. 第二范式:要求数据库表中的每一个行必须可以被唯一区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。
  3. 要求一个数据库表中不包含已在其它表中已包含的非主关键字信息
  4. 反三范式: 有的时候为了效率查询,可以设置重复的字段。
事务
  • 事务时并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
  1. 原子性:表示事务内操作不可分割,要么都成功,要么都失败。
  2. 一致性:要么都成功,要么都失败。后面的失败了,要对前面的操作进行回滚。
  3. 隔离型:一个事务开始后,不能受其他事务干扰
  4. 持久性:表示事务开始了,就不能终止。
Mysql数据库的默认的最大连接数?
  • 为什么需要最大连接数?特定服务器上面的数据库只能支持一定数目同时连接,这时需要我们设置最大连接数(最多同时服务多少连接)?在数据安装时,都会有一个默认的最大连接数。
  • 默认最大100个
Mysql 和 Oracle分页
  • mysql使用关键字 limit 来进行分页的 limit offset size
  • oracle 使用嵌套子查询和 rownum关键字配合使用
SELECT *
  FROM (SELECT ROWNUM AS rowno, t.*
          FROM emp t
         WHERE ROWNUM <= 20) table_alias
 WHERE table_alias.rowno >= 10;
数据库的存储过程的使用场景?
  • 存储过程只在创建时进行编译,以后每次执行存储过程都不需要再重新编译,而一般SQL语句每执行一次就编译一次,因此使用存储过程可以大大提高数据库执行速度。
  • 通常,复杂的业务逻辑需要多条SQL语句。这些语句要分别地从客户机发送到服务器,当客户机和服务器之间的操作很多时,将产生大量的网络传输。如果将这些操作放在一个存储过程中,那么客户机和服务器之间的网络传输就会大大的减少,降低了网络负载。
  • 存储过程创建一次便可以重复使用,从而可以减少数据库开发人员的工作量。
  • 安全性高,存储过程可以屏蔽对地城数据库对象的执行访问,使用Execute 权限调用存储过程,无需拥有访问底层数据库队形的显示权限。
  • 正是由于存储过程的上述优点,目前常见的数据库都支持存储过程,例如 IBM DB2, Microsoft SqlServer,Oracle ,开源数据库Mysql也在5.0的时候实现了对存储过程的支持。在这里插入图片描述
JDBC中的PreparedStatement相比Statement的好处
  • 大多数我们都使用PreparedStatement代替
  1. PreparedStatement是预编译的,比Statement速度快。
  2. 代码的可读性和可扩展性
    虽然用PreparedStatement来替代Statement会使代码多几行,但这样的代码无论从可读性还是可维护性上来说,都比直接用哪个Statement的代码高出很多档次。
  3. 安全性
    prepareStattement可以防止SQL注入攻击,而Statement却不能,
数据库连接池的作用
  1. 限定数据库的个数,不会导致由于数据库连接过多导致系统运行缓慢或崩溃
  2. 数据库连接不需要每次都去参加或销毁,节约了资源
  3. 数据库连接不需要每次都去创建,响应时间更快。

框架

MVC模式
  • MVC全名是Model View Controller,是模型 model – 视图 — 控制器 controller的缩写,一种软件设计典范,用一种业务逻辑,数据,界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制页面及用户交互的同时,不需要重新编写业务逻辑。
SpringMVC执行流程? 原理
  1. 用户向服务器发送请求,请求被Spring前端控制Servlet DispatcherServlet捕获
  2. DispatcherServlet 对请求URL进行解析,得到请求资源标识符(URI),然后根据URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器) ,最后以HandlerExecutionChain对象的形式返回。
  3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller),Handler执行完成后,向DispatcherServlet返回一个ModelAndView对象
  4. DispatcherServlet根据返回的ModelAndView,选择一个适合的ViewResolver(必须是注册到spring容器中的ViewResolver)
  5. 通过ViewResolver 结合Model和View , 来渲染视图,DispatcherServlet将渲染结果返回给客户端。
  • 核心控制器捕获请求—> 查找Handler-----> 执行Handler-----> 选择ViewResolver----> ViewResolver渲染视图并返回
    在这里插入图片描述
说一下Struts2 和 SpringMVC有什么不同?
  1. 核心控制器(前端控制器,预处理控制器);核心控制器的主要用途是处理所有的请求。然后对那些特殊的请求(控制器)统一的进行处理(字符编码、文件上传、参数接收、异常处理等),springmvc核心控制器是Servlet,而Strutts2是过滤器 Filter
  2. 控制器实例: SpringMVC会比Struts2快一些(理论上)。SpringMVC是基于方法设计,而sturts2是基于对象每次发一次请求都会实例一个action,每一个action都会被注入属性,而spring更像Servlet一样,只有一个实例,每次请求执行对应的方法即可,由于单例实例,所以对应避免全局变量的修改,这样会产生线程安全性问题。
  3. 参数传递:Strust2是自身提供多种参数接收,其实都是通过(ValueStack) 值栈进行传递和赋值,而SpringMVC是通过方法的参数进行接收
  4. intercepter 的实现机制: struts有自己的interceptor机制,springmvc用的是独立的AOP方式。这样导致struts的配置文件量还是比springmvc大。
  5. springmvc处理ajax请求,直接通过返回数据,方法中使用注解@ResponseBody, springmvc自动帮我们对象转换为JSON数据,而struts2是通过插件的方式进行处理。
说一下Spring中的两大核心?
  • Spring是一个J2EE应用程序框架,是轻量级的IOC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。
  1. IOC (Inversion of Control) 或者 DI (Dependency Injection)
    ioc 控制反转: 原来 service需要调用Dao,service 就需要创建Dao
    spring: spring发现你Service依赖于dao, 就给你注入
    核心原理:就是工厂模式+反射+配置文件
  2. AOP: 面向切面编程
    核心原理: 使用动态代理的方式在执行前后或出现异常后做相关逻辑。
    我们主要使用AOP来做: ① 事务处理 ② 权限判断 ③日志
Spring事务的传播特性
传播行为描述
PROPAGATION_REQUIRED如果没有,就开启一个事务;如果有,就加入当前事务(方法B看到自己已经运行在 方法A的事务内部,就不再起新的事务,直接加入方法A)默认使用,80%
RROPAGATION_REQUIRES_NEW如果没有,就开启一个事务;如果有,就将当前事务挂起。(方法A所在的事务就会挂起,方法B会起一个新的事务,等待方法B的事务完成以后,方法A才继续执行)
PROPAGATION_NESTED如果没有,就开启一个事务;如果有,就在当前事务中嵌套其他事务
PROPAGATION_SUPPORTS如果没有,就以非事务方式执行;如果有,就加入当前事务(方法B看到自己已经运行在 方法A的事务内部,就不再起新的事务,直接加入方法A)
PROPAGATION_NOT_SUPPORTED如果没有,就以非事务方式执行;如果有,就将当前事务挂起,(方法A所在的事务就会挂起,而方法B以非事务的状态运行完,再继续方法A的事务)
PROPAGATION_NEVER如果没有,就以非事务方式执行;如果有,就抛出异常。
PROPAGATION_MANDATORY如果没有,就抛出异常;如果有,就使用当前事务
数据库的隔离级别
  • √ 为会发生,×为不会发生:
  • mysql 默认隔离级别 可重复读
隔离级别脏读不可重复读幻读
read uncommitted(未提交读)
read committed(提交读)×
repeatable read(可重复读)××
serialization(可串行化)×××
什么是ORM?
  • 对象关系映射(Object Relational Mapping)模式是一种为了解决面向对象与关系数据库存在的互补匹配的现象的技术。简答的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。那么,到底如何实现持久化那?一种简单的方案是采用硬编码方式(jdbc操作sql的方式),为每一种可能的数据库访问操作提供单独的方法。
  • 这种方案存在以下不足:
  1. 持久化层缺乏弹性。一旦出现业务需求的变更,就必须修改持久化层的接口。
  2. 持久化层同时与域模型与关系数据库模型绑定,不管域模型还是关系数据库模型发生变化,都需要修改持久化层的相关层数代码,增加了软件的维护难度。
    ORM提供了实现持久化层的另一种模式,它采用映射元数据来描述对象关系的映射,使得ORM中间件能在任何一个应用的业务逻辑层和数据库层之间充当桥梁。jav a典型的ORM框架有: Hibernate,ibatis。
IBatis(Mybatis) 与 Hibernate 有什么不同?
  • 都是java中orm框架、屏蔽jdbc api 的底层访问细节,使得我们不用与jdbc api打交道,就可以完成对数据库持久化的操作。jdbc api编程流程固定,还将sql语句与java代码混合在一起,经常需要拼接sql语句,细节很繁琐。
  • ibatis的好处:屏蔽了jdbc api的底层访问细节,将sql语句与java代码进行分离,提供了将结果集自动封装称为实体对象和对象的集合功能,queryForList 返回对象集合,用queryForObject返回单个对象,提供了自动将实体对象的属性传输给sql语句的参数
  • Hibernate的好处: Hibernate是一个全自动的orm映射工具,它可以自动生成sql语句,并执行并返回java结果
  • 不同点:ibatis需要我们自己在xml配置文件中写sql语句,hibernate我们无法控制该语句,我们就无法去写特定的高效率的sql,对于一些不太复杂 sql查询,hibernate可以很好帮我们完成,但是,对于特别复杂的查询,hibernate就很难适应了,这时候ibatis就是不错的选择,因为ibatis还是由我们自己写sql语句
  • ibatis要比hibernate简单的多,ibatis是面向sql的,不用考虑对象之间的映射关系。
简单讲一下webservice的使用场景?
  • webService是SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言见的相互调用,通过Internet进行基于http协议的网络应用见的交互。
  1. 异构系统的整合
  2. 不同客户端的整合,浏览器,手机端,PC端
简单介绍一下activiti?
  • Activiti是一个业务流程管理(BPM)和工作流系统,适用于开发人员和系统管理人员,其核心是超快速,稳定的BPMN2流程引擎,它易于与Spring集成使用。
  • 主要要在OA中,把线下流程放到线上,把现实生活中一些流程固化定义到系统中。然后通过输入表单数据完成业务。
  1. 请假流程
  2. 报销流程
  3. 审批流程

高级部分

你是使用什么来连接远程的Linux服务器的?
  • 需要依赖于Linux服务器安装ssh 服务端,一般这个ssh 服务端的端口 22
  • 使用ssh客户端连接Linux服务器,就有点像windows下面的远程连接,但是linux通过ssh连接上以后是没有图形页面,全是命令行。
有没有做过数据库优化方面的事情?

查找、定位慢查询,并优化

  • 优化手段
  1. 创建索引:创建合适的索引,我们就可以先在索引中查询,查询到以后,找对应的记录。
  2. 分表:当一张表的数据比较多或者一张表的某些字段的值比较多并且很少使用时,采用水平分表和垂直分表来优化
  3. 读写分离:当一台服务器不能满足需求时,采用读写分离的方式进行集群。
  4. 缓存:使用redis来进行缓存
查找并定位慢查询?
  • 在启动mysql数据库时,开启慢查询,并且把执行慢的语句写到日志中,在运行一定时间后,通过查看日志找到慢查询的语句。
  • 开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能
mysql> show variables like 'slow_query%';
+---------------------------+----------------------------------+
| Variable_name             | Value                            |
+---------------------------+----------------------------------+
| slow_query_log            | OFF                              |
| slow_query_log_file       | /mysql/data/localhost-slow.log   |
+---------------------------+----------------------------------+

mysql> show variables like 'long_query_time';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000
选择合适的存储引擎
  • 在开发中,我们经常使用的存储引擎 myisam / innodb / memory
  1. 如果表对事务要求不高,同时是以查询和添加为主的,我们考虑使用myisam存储引擎,比如 bbs 中的发帖表,回复表。
  2. INNODB存储引擎:
    对事物要求高,保存的数据都是重要数据,我们建议使用INNODB,比如订单表,账号表。
  3. Memory存储
    我们数据变化频繁,不需要入库,同时又频繁的查询和修改,我们考虑使用memory,速度极快。
  • MyIasm 和 InnoDB的区别(主要)
  1. 事务安全性 myisam 不支持事务而innodb支持
  2. 查询和添加速度, myisam 不用支持事务就不用考虑同步锁,查询和添加的速度快
  3. 支持全文检索 myisam 支持 Innodb 不支持
  4. 锁机制 myisam 支持表锁, 而innodb支持行锁
  5. 外键 MylSAM 不支持外键,Innodb支持外键。(通常不设置外键,通常是在程序中保证数据的一致性)
数据库优化之创建合适的索引?
  • 索引(index)是帮助DBMS高效获取数据的数据结构。
    分类: 普通索引/唯一索引/主键索引/全文索引
    普通索引:允许重复的值出现
    唯一索引:除了不能有重复的记录外,其他和普通索引一样。(用户名、用户身份证、email,tel)
    主键索引:是随着设定主键而创建的,也就是把某个列设为主键的时候,数据库就会给改列创建索引。这就是主键索引,唯一且没有null值。
    全文索引:用来对表中的文本域(char,varchar,text)进行索引,全文索引针对MyIsam会生效。
使用索引的技巧?
  • 索引弊端:
  1. 占用磁盘空间
  2. 对dml (插入,修改,删除)操作有影响,变慢。
    使用场景: a. 在where条件中经常使用的,如果不做查询就没有意义。
    b. 该字段的内容不是唯一的几个值(sex)
    c. 字段内容不是频繁变化。
    具体技巧: 1. 对于创建的多列索引(复合索引),不是使用的第一部分就不会使用索引。
    alter table dept add index my_ind (dname,loc) // dname 左边的列,loc就是右边的列
    select * from dept where dname = ‘aaa’ 会使用索引
    select * from dept where loc = ‘beijing’ 就不会使用索引
    1. 对于使用like 的查询,查询如果是 ‘%aaa’,就不会使用到索引,而’aaa%'就会用到索引
      select * from dept where dname like ‘%aaa’ // 不会用到索引
      select * from dept where dname like ‘aaa%’ //会用到索引
    2. 如果条件中有or, 有条件没有使用索引,即使其中有条件带索引也不会使用,换言之,就是要求使用的所有字段,都必须单独使用能使用索引。
    3. 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引。
    4. 如果mysql 估计使用全表扫描要比使用索引快,就不使用索引。
      如: 表里只有一条记录。
数据库优化之分表
  • 分表分为水平分表(按行)分表和(按列)垂直分表
  • 根据经验,Mysql表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉;水平分表能够很大程度减少这些压力。
    垂直分表:如果一张表中某个字段的值非常多(字符串、长文本、二进制等),而且只有在很少的情况下会查询,这时候就可以把字段多个单独放到一个表,通过外键把原表关联起来。
    比如: 考试详情,一般我们只关注分数,不关注详情。
  • 水平分表策略:
  1. 按时间分表策略:
    这种分表方式有一定的局限性,当数据有较强的失效性,如微博发送记录、微信消息记录等,这种数据很少有用户会查询几个月前的数据,如就可以按月分表。
  2. 按区间范围分表:
    一般在自增ID需求上,如按照user_id 水平分表;
    table_1 user_id 从 1~100W
    table_2 user_id 从 101~200W
    table_3 user_id 从 201~300W
  3. hash分表(* 用的最多的)
    通过一个原始目标的ID或者名称通过一定的hash算法计算出数据存储表的表名,然后访问相应的表。
数据库优化之读写分离
  • 当一台数据库支持的最大并发连接数是有限的,如果用户并发访问太多,一台服务器满足不了要求,就可以采用集群处理,Mysql的集群处理技术最常用的就是读写分离
  • 主从同步:数据库最终会把数据持久化到磁盘,如果集群必须确保每个数据库服务器的数据时一直的,能改变数据库的操作都往主数据库去写,而其他的数据库从主数据库上同步数据。
  • 读写分离:使用负载均衡来实现写的操作都往主数据库上去,而读的操作都去从的数据库上操作。
数据库优化之缓存
  • 在持久层和数据库之间添加一个缓存层,如果用户访问的数据已经缓存起来时,在用户访问时直接从缓存中获取。不用访问数据库,而缓存是子操作内存级,访问速度快。
  • 作用: 减少数据库服务器压力,减少访问时间。
语句优化小技巧
  • DDL优化:
  1. 通过禁用索引来提供导入数据性能。这个操作主要针对有数据库的表,追加数据
// 出除键
alter table test3 disable keys;
// 批量插入数据
insert into test 
// 恢复键
alter table test3 Enable keys;
  1. 关闭唯一校验
set unique_clecks=0 关闭
set unique_checks=1 开启
  1. 修改事务提交方式(导入) ,变多次提交为1次
set autocommit=0 关闭
set autocommit=1 开启
  1. DML优化
insert into test values(1,2);
 insert into test values(1,3);
 //合并多条为 一条
 insert into test values(1,2)(1,3)
批量插入几百万数据怎么实现?
  • 省出的时间非常可观在这里插入图片描述
有没有使用过Redis? Redis是什么?
  • Redis是一个key-value的nosql数据库,先存到内存中,会根据一定的策略持久化到磁盘,即使断电也不会丢失数据,支持的数据类型比较多。
  • 主要用来做缓存数据库的数据和web集群时当做中央缓存存放session。
简单说一下redis的使用场景?

在这里插入图片描述

redis对象保存方式?
  • Json字符串:
    需要把对象转换为json字符串,当做字符串处理,直接使用set get来设置
    优点: 设置和获取比较简单。
    缺点:没有提供专门的方法,需要把对象转换为json。(通过jsonlib来实现)
  1. 字节:
    如果是数据完全可以使用Json方式,毕竟redis直接set、get使用起来门槛很低,redis是没有提供专用的设置对象方法,需要自己进行改写。
  2. 如果是担心Json转对象会消耗资源的情况,这个问题需要考量几个地方,第一点:就是使用的Json转lib是否就存在性能问题。第二点,数据的数据量级别,如果是存储百万级的大数据对象,建议采用存储序列化对象方式,如果是少量的数据级对象,或者是数据对象字段不多,还是建议采用Json转换成String方式。毕竟redis对存储字符类型这部分优化的非常好,具体采用的方式与方法,还要看你所使用的场景。
Redis数据淘汰机制
  • 在redis中,允许用户设置最大使用内存大小,在内存限定的情况下是很有用的,比如,在一台8G机子上部署了4个redis服务点,每一个服务点分配1.5G的内存大小,减少内存紧张的情况,由此获取更为稳健的服务。
  • 内存大小有限,需要确保有效的数据
  1. redis 内存数据集大小上升到一定打下的时候,就会施行数据淘汰策略,redis提供6种数据淘汰策略。
    ① volatile-lru: 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰 主要。
    ② volatile-ttl: 从已设置过期时间的数据集中挑选将要过期的数据淘汰
    ③ volatile-random: 从已设置过期时间的数据集中任意选择数据淘汰
    ④ allkeys-lru: 从数据集中挑选最近最少使用的数据淘汰
    ⑤ no-enviction: 禁止驱逐数据
    redis确定驱逐某个键值对后,会删除这个数据,并将这个数据变更消息发布到本地(AOF持久化)和从机(主从连接)
Java访问Redis
  1. 使用jedis java客户端来访问redis服务器,有点类似通过jdbc访问mysql一样。
  2. 当然如果是spring进行集成时,可以使用spring data来访问redis,spring data,只是对jedis的二次封装。和jdbcTemplate jdbc关系一样。
Redis集群
  • 当一台数据无法满足要求,可以使用redis集群来处理,类似于mysql的读写分离。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值