Java面试题:java的垮平台原理
为什么要跨平台使用?????
其实说白了就是个操作系统支持的指令集是不一样的。我们的程序需要再不同的操作系统上运行这些代码。
但是不要说jvm是跨平台的,而真正跨平台的是 Java 程序,而不是 JVM。JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 JVM
答:
我们编写的 Java 源码,编译后会生成一种 .class 文件,称为字节码文件。Java 虚拟机(JVM)就是负责将字节码文件翻译成特定平台下的机器码然后运行,也就是说,只要在不同平台上安装对应的 JVM,就可以运行字节码文件,运行我们编写的 Java 程序。
而这个过程,我们编写的 Java 程序没有做任何改变,仅仅是通过 JVM 这一 “中间层” ,就能在不同平台上运行,真正实现了 “一次编译,到处运行” 的目的。
Java面试题:JVM由哪些部分组成?
答:JVM 的结构基本上由 4 部分组成:
• 类加载器,在 JVM 启动时或者类运行时将需要的 class 加载到 JVM 中
• 执行引擎,执行引擎的任务是负责执行 class 文件中包含的字节码指令,相当于实际机器上的 CPU
• 内存区,将内存划分成若干个区以模拟实际机器上的存储、记录和调度功能模块,如实际机器上的各种功能的寄存器或者 PC 指针的记录器等
• 本地方法调用C 或 C++ 实现的本地,调用方法的代码返回结果
Java面试题:类加载器是有了解吗?
答:顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说, Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。
类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象?
Java面试题:Java 虚拟机是如何判定两个 Java 类是相同的?
答:Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。比如一个 Java 类 com.example.Sample,编译之后生成了字节代码文件 Sample.class。两个不同的类加载器 ClassLoaderA和 ClassLoaderB分别读取了这个 Sample.class文件,并定义出两个 java.lang.Class类的实例来表示这个类。这两个实例是不相同的。对于 Java 虚拟机来说,它们是不同的类。试图对这两个类的对象进行相互赋值,会抛出运行时异常 ClassCastException。
双亲委派模型(Parent Delegation Model)
该模型要求除了顶层的 Bootstrap class loader 启动类加载器外,其余的类加载器都应当有自己的父类加载器。子类加载器和父类加载器不是以继承(Inheritance)的关系来实现,而是通过组合(Composition)关系来复用父加载器的代码。每个类加载器都有自己的命名空间(由该加载器及所有父类加载器所加载的类组成,在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类;在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类)
面试官:双亲委派模型的工作过程?
答:
1.当前 ClassLoader 首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。
每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存,
等下次加载的时候就可以直接返回了。
2.当前 ClassLoader 的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到 bootstrap ClassLoader.
当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。
面试官:为什么这样设计呢?
解析:这是对于使用这种模型来组织累加器的好处
答:主要是为了安全性,避免用户自己编写的类动态替换 Java 的一些核心类
同时也避免了重复加载,因为 JVM 中区分不同类,不仅仅是根据类名,相同的 class 文件被不同的 ClassLoader 加载就是不同的两个类,如果相互转型的话会抛java.lang.ClassCaseException.
Jvm垃圾回收算法,原理
引用计数:标记-清除:复制算法:标记-整理:分代收集算法:
Java面试题:java面向对象的特征
面向对象的特征:封装,抽象,继承,多态
大家一定要注意:回答比较抽象的问题的时候一定要举例子
Java面试题:装箱和拆箱
?????有了基本的数据类型,我们为什么还要有包装类型。
说白了。。。就是体现面向对象的思想
基本类型,int ,flout,double, Bollean等
BooleanBoolean
IntInteger
自动装箱是jdk1.5以后增加的功能
装箱:就是把基本数据类型转化成对应的包装类型。
总结一下:
Java是一个面向对象的语言,而基本的数据类型,不具备面向对象的特性。
Java面试题:讲一下java中的集合
Java集合分为两种,一个是value类型的,另一个就是key.value (Map)两种
List是有序的,可以重复的
Set是无序的,不可以重复的(根据equals和hashcode来判断。)也就是说如果一个对象要存储到set当中,就必须要重写我们的equals和hashcode的方法。
Map就是key.value的类型数据。
Hashmap存储原理:
1, API中的常用的属性
2, Hashmap、默认四个构造方法
3, Hash碰撞 ,桶的概念
4, Entry【】--》next属性
Hashmap弹性伸缩的角度不足:
谈不足的时候一定要谈一下时间复杂度和空间复杂度。
在用hashmap的时候要给一个初始容量。
Java面试题:ArrayList 和LinkedList的区别
是什么?区别???使用场景
ArrayList底层使用的是数组,LinkedList底层使用的是链表
数组查询的时候具有查询特定元素比较快。而插入和删除和修改比较慢(数组在内存当中是一块联系的内存,如果插入或者删除是需要移动内存的)
链表不要求内存是连续的,当查询的时候,需要从头部一个一个的找,所以查询效率低,而插入的时候不需要移动内存,只需要改变引用的指向。
应用场景:ArrayList使用在查询比较多,答案是插入和删除比较少的情况,而LinkedList使用在查询比较少而插入和删除比较多的情况
Java面试题:HashMap和HashTable的区别
相同点:都可以用来存储Key.value型数据
区别:
1、 hashMap是可以把null作为可以key或者value,而hashtable不可以
2、 HashMap是线程不安全的,效率较高,而hashtable是线程安全的,效率较低
我想线程安全我又想效率比较高?????what?????
原理—》就是把整个map分为N个segment(类似于hashtable),可以提供相同的线程安全,但是效率提升N。默认提升的16倍。
Java面试题:线程的的实现方式?怎么启动线程?怎么区分线程?
1、 实现方式
a) 常用的通过继承Thread类来实现一个线程
b) 通过实现Runnable接口来实现一个线程。
c) 通过实现Callable借口来实现一个线程
2.怎么启动????
我们通过
Thread thread=new Thread(继承了thread类的对象或者把实现了runnable接口的对象)
thread.start();
启动线程的时候用的是start()方法,然后执行线程的时候用的是run()方法;
2、 怎么样区分线程???
a) 在一个系统当中我们有很多线程,每个系统都会打印日志,我想区分一下到底是哪个系统打印的???
thread.setName(设置一个线程的名称),这是一个规范,你们将来在开发的时候写完多线程一定要及记得设置线程名称。
Java面试题:线程并发库和线程池的作用
简单了解过就行
Jdk1.5的时候增加了Doug Lea的并发库,大大的增加了便利性。Java.util.current
包提供了对线程的优化,包括管理的各项操作。--》线程池的创建,以及线程的生命周期的管理。
Java通过Executors提供四个静态方法来创建四种线程 池:
1, newCachedThreadPool,可缓存的线程池
2, newFixedThreadPool,创建一个定长线程池
3, newScheduledThreadPool,创建一个定长线程池,支 持定时以及周期性任务
4, newSingleThreadExcutor,创建一个单线程化的线程池
线程池的作用:
1、 限定了线程的个数,不会导致由于线程过多导致系统运行缓慢或崩溃
2、 节约资源,我们不会去关心它的创建于销毁。
Java面试题:设计模式和常用的设计模式
设计模式就是经过前人总结和实践出来的,设计过程可以反复的使用,可以解决特定的问题的设计方法
常用的设计模式:
1、单例(饿汉式和饱汉式)
1、构造方法私有化,
2、要自己创建一个对象
3、提供对外获取对象的方法。
2、工厂设计模式:
Spring IOC就是用的就是工厂模式
3、 代理模式:
a) Spring AOP用的就是动态代理
Java面试题:http get post请求的区别
Get和post都是http的请求方式,用户可以通过不同的http请求方式完成对资源(url)的操作,get , post,put,delete,对应的是咱们对资源的,查,改,增,删,四个操作,具体的来说一般情况下,get用于获取、查询资源信息。而post一般用于更新资源信息
区别:
1、 get请求提交的数据会在地址栏显示出来,而post请求不会在地址栏显示出来
2、 传输数据的大小
http get请求由于浏览器对地址长度有限制,所以就导致对传输的数据有限制,而post不会
3,安全性的问题,post的安全性要比get的安全性要高。
Java面试题:Servlet的生命周期
Servlet有良好的生命周期的定义,他包括加载和实例化、初始化、处理请求以及服务结束。这个生命周期是由javax.servlet.Servlet接口中的int 、service、destroy方法来描述。
Servlet启动时,开始加载servlet生命周期的开始,servlet被服务器实例化后,容器运行其init方法,请求到达时运行去service方法,service方法会自动派遣运行对应的doXXX等。然后当服务器决定将实例销毁的时候,这个时候调用destroy方法
Java面试题:jsp和Servlet的相同点和不同点
Jsp本质:
Jsp是servlet的扩展,所有的jsp文件都会被翻译成为一个继承HttpServlet的类,然后对外提供服务
不同点:
1、Jsp偏重于视图,而servlet只要用于控制逻辑
2、servlet如果想要实现html的功能,比喻使用writer输出对应的html,这个比较麻烦,而jsp是servlet和html组合起来的,做界面展示比较方便,但是想要嵌入逻辑比较复杂。
Java面试题:Session和Cookie的区别和使用场景,你在项目当中哪些地方用到了?????
Session和cookie都是会话跟踪技术,cookie是通过在客户端记录信息来确定用户身份,session他是通过服务端来记录用户的身份。。但是session的实现依赖于cookie,sessionId(session的唯一标识)
区别:
1、 Session放在服务器,而cookie放在浏览器
2、 Cookie不是很安全,别人可以通过分析你本地的cookie进行cookie的欺诈,考虑到安全,我们用session
3、 Session会在服务器保存一定的时间,也就是说,当访问增多的时候,会比较占用服务器的性能,如果将来考虑到服务器压力的时候,我们要用cookie。
4、 Cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存50个cookie
5、 个人建议:
要将个人信息保存到session当中
其他的信息,如果需要保留我们放到cookie:购物车信息。
Java面试题:关系型数据库的三范式
范式?????说白了就是规范
想要满足第二范式,你就必须要满足第一范式,然后,你想要满足第三范式,你就必须要满足第一第二范式
第一范式(1nf),列数据不可分割,是指数据库表的每一列都是不可分割的基本数据项,同一列当中不能有多个值,对应到咱们的pojo对象当中,你一个对象的属性不能有多个值。
将来的设计不能这样设计,应为地址还可以再分
但是大家需要注意的是,拆不拆要看业务,比如我们将来要按照国家和省份来分类汇总,那我们就要把它拆掉,但是如果这个字段仅仅起到一个字符串的作用,那我们就没必要拆分,大家明白吧????
第二范式(2nf),针对主键:
1.要求数据库当中的每一行必须可以被唯一的区分,你想要给唯一的区分????加一列设成主键。
2.另外非主键的列要依赖主键,最好第二范式要让每个表只描述一件事情
实际,产品的编号和订单的编号没有明确的关系,购买日期和订单编号有关系。
价格和订单编号也没有关系,而与产品编号有关,那么我们应该拆分为
第三范式(2nf),第三范式、要求一个数据库中非主键列不依赖于其他非主键列
学号和姓名存在传递,因为(学号,姓名)成绩 学号成绩 姓名成绩,冗余了,只需保留一个
反三范式:订单(总价)和订单项(单价)。我们可以通过每一个订单去算总价,这是可以的,但是每次算的时候都得合并计算,影响效率,所以有时候该反的时候就得反
所以什么是老大,需求是老大!!!!需求>>结构设计
Java面试题:事务的四大特征
事务是什么??what????
事务是并发控制的单位,是用户定义的一个操作序列,这些操作要么做,要么不做,是一个不可分割的单位。
转账---》1000 a—》b 500 a500 b1500 a转账成功并不代表这件事情已经成功了,也就是说,当a转账成功,b收到钱以后这个事情才算结束 。
事务必须满足四大特性:原子性,一致性,隔离性,持久性(持续性)
原子性:表示事务内操作不可分割,要么都成功,要么都失败。
一致性:要么都成功,要么都失败,但是后面失败了的要对前面的操作进行回滚,
隔离性:一个事务开始后,后面不能有其他事务干扰。
持久性:表示事务开始了,就不能终止
Java面试题:触发器的使用场景?
触发器,what?????
触发器需要有触发条件,当条件满足之后做相应的操作
比如:学校的校园网,开心网,facebook,当你发一个日志,会自动通知好友,本质就是当你增加一个日志的时候做了一个后触发。再向数据库表当中写入相应的操作。
CREATE TRIGGER trigger_name
trigger_time
trigger_event ON tbl_name
FOR EACH ROW
trigger_stmt
其中:
trigger_name:标识触发器名称,用户自行指定;
trigger_time:标识触发时机,取值为 BEFORE 或 AFTER;
trigger_event:标识触发事件,取值为 INSERT、UPDATE 或 DELETE;
tbl_name:标识建立触发器的表名,即在哪张表上建立触发器;
trigger_stmt:触发器程序体,可以是一句SQL语句,或者用 BEGIN 和 END 包含的多条语句。
好处:????效率高。在贴吧发一条帖子,都希望在页面当中展现我们的最后发帖时间,帖子总数(保证他们的同步更新。)这个时候就可以用到触发器而且效率非常高。
Java面试题:存储过程的优点
create proceduce insert_student(xxx xxx xxx)
begin
insert 。。。。。
select 。。。。。
sql语句
end;
存储过程有什么优点???????******
1、 存储过程只在创建是编译,以后每次执行存储过程都不需要在重新编译,而普通的sql语句每执行一次就编译一次,因此使用存储过程可以大大提高数据库的执行速度。
2、 通常情况下,复杂的业务逻辑需要执行多条sql语句,这些语句分别都要从客户端去链接服务器端,这个时候就会产生大量的网络传输,
这个时候,结合业务,我们应该吧这些sql语句放在我们的存储过程当中,提高我们的效率,降低我们的网络负载
3、 存储过程创建一次可以多次调用,可以减少我们开发人员的工作量。
4、 安全性高,存储过程可以屏蔽对底层数据库对象的直接访问。
现在的数据库支持我们的存储过程,IBM DB2,oracle。Mysql(5.0) ACCESS。
Java面试题:jdbc调用存储过程
过程和jdbc调用数据库的过程差不多
加载驱动
获取链接
设置参数
执行sql
释放资源
Java面试题:数据库连接池的作用
1、 限定了数据库的个数。不会导致由于数据库链接过多导致系统运行缓慢
2、 数据库连接池,不需要每次都去创建和销毁,节约资源
3、 响应时间比较快
Java面试题:简单介绍了一下Ajax
首先必须要说一下??what????作用是什么????使用场景,怎么使用??
什么是ajax????异步的js和xml
作用是什么????我们可以通过ajax来与服务器进行交互,进行数据的交换,可以实现局部刷新,这就意味着,我们可以不重新加载整个网页的情况下,对网页进行更新。
怎么实现????我们通过XmlHttpRequest这个对象,使用这个对象来异步的向服务器发送请求,获取响应,完成局部刷新。
使用场景?????登录失败不跳转页面,注册时用户名是否存在。二级联动,三级联动
Java面试题:Spring MVC的执行流程
1、 用户向服务器发送请求,请求被spring前端控制器捕获,
2、 前端控制器对请求的url进行解析,得到url根据这个url调用HandlerMapping 获得该handler配置的相关信息(包括handler对象以及handler对象对应的拦截器)返回的是以handlerExcutionChain对象的形式进行返回
3、 前端控制器,根据获得的handler,选择一个合适的handlerAdapter,获取到request中的数据模型,填充到handler,并开始执行整个流程,然后向前端控制器返回model and view
4、 前端控制器根据返回的model and view,选择一个合适的ViewResolver对象。
5、 最后一个就是通过ViewResolver对象结合model and view进行视图渲染,将渲染结果返回给客户端
Java面试题:简单介绍一下Spring或者Spring的两大核心
Spring是将j2EE的应用程序框架,轻量级,可以单独使用也可以整合我们 struts2 mybatis 。-------EJB
IOC和DI
AOP
Java面试题:AOP是什么?都用它做什么?
AOP:面向切面编程。
用它来干嘛???
1、 事务的控制
2、 权限的判断
3、 日志
4、 。。。。。。。。。。
Java面试题:Spring事务的传播特性和隔离级别
1) PROPAGATION_REQUIRED ,默认的spring事务传播级别,使用该级别的特点是,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。所以这个级别通常能满足处理大多数的业务场景。
2)PROPAGATION_SUPPORTS ,从字面意思就知道,supports,支持,该传播级别的特点是,如果上下文存在事务,则支持事务加入事务,如果没有事务,则使用非事务的方式执行。所以说,并非所有的包在transactionTemplate.execute中的代码都会有事务支持。这个通常是用来处理那些并非原子性的非核心业务逻辑操作。应用场景较少。
3)PROPAGATION_MANDATORY , 该级别的事务要求上下文中必须要存在事务,否则就会抛出异常!配置该方式的传播级别是有效的控制上下文调用代码遗漏添加事务控制的保证手段。比如一段代码不能单独被调用执行,但是一旦被调用,就必须有事务包含的情况,就可以使用这个传播级别。
4)PROPAGATION_REQUIRES_NEW ,从字面即可知道,new,每次都要一个新事务,该传播级别的特点是,每次都会新建一个事务,并且同时将上下文中的事务挂起,执行当前新建事务完成以后,上下文事务恢复再执行。
问题 :如果其中一个子事务回滚了,父事务是否回滚?答案是不会,因为子事务是新建事务,父事务已经被挂起,两者不会受到影响。
再问:如果父事务回滚了,子事务是否回滚?答案是不会,同样的理由。但是可以手动控制一旦子事务回滚,父事务也回滚。
5)PROPAGATION_NOT_SUPPORTED ,这个也可以从字面得知,not supported ,不支持,当前级别的特点就是上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务。
这个级别有什么好处?可以帮助你将事务极可能的缩小。我们知道一个事务越大,它存在的风险也就越多。所以在处理事务的过程中,要保证尽可能的缩小范围。比如一段代码,是每次逻辑操作都必须调用的,比如循环1000次的某个非核心业务逻辑操作。这样的代码如果包在事务中,势必造成事务太大,导致出现一些难以考虑周全的异常情况。所以这个事务这个级别的传播级别就派上用场了。用当前级别的事务模板抱起来就可以了。
6)PROPAGATION_NEVER ,该事务更严格,上面一个事务传播级别只是不支持而已,有事务就挂起,而PROPAGATION_NEVER传播级别要求上下文中不能存在事务,一旦有事务,就抛出runtime异常,强制停止执行!这个级别上辈子跟事务有仇。
7)PROPAGATION_NESTED ,字面也可知道,nested,嵌套级别事务。该传播级别特征是,如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。Propagation_required_new 总是开启一个新的事务,如果有一个事务存在,就将已存在的事务挂起
隔离级别:
脏读 :所谓的脏读,其实就是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。
不可重复读 :不可重复读字面含义已经很明了了,比如事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,然后事务A再次读取的时候,发现数据不匹配了,就是所谓的不可重复读了。
幻读 :小的时候数手指,第一次数十10个,第二次数是11个,怎么回事?产生幻觉了?
幻读也是这样子,事务A首先根据条件索引得到10条数据,然后事务B改变了数据库一条数据,导致也符合事务A当时的搜索条件,这样事务A再次搜索发现有11条数据了,就产生了幻读。
Java面试::数据库优化方面的事情
1、 查询,并定位慢查询
2、 优化手段
a) 创建索引:创建合适的索引,我们就可以先在索引当中查询,通过索引找到对应的记录
b) 分表。也就是说当一张表的数据比较多的时候,或者一张表当中某些字段的值比较多并且不怎么常用的时候我们要分表。水平拆分和垂直拆分
c) 读写分离:当一个服务器不能满足需求的时候,我们可以建立数据库集群
d) 缓存:也就是我们要用redis。
Java面试::如果查询和定位慢查询
slow_query_log= 1
long_query_time= 1
slow_query_log_file=c:/slow.log
在项目当中,给测试人员执之前,再启动mysql数据的时候,我们开启慢查询,并且把慢查询语句打到我们的日志当中,运行一段时间,看看哪些语句执行效率最慢
Java面试::选择合适的数据库引擎
show engines;
SHOW VARIABLES LIKE 'storage_engine';
在开发当中,我们经常用的存储引擎
Myisam innodb memory
Myisam 存储引擎
MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事物。
Innodb 存储引擎
InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键
Memory
MEMORY存储引擎将表中的数据存储到内存中,当我们的数据频繁变化的时候,而且不需要入库,这个时候用memory存储引擎。
Myisam和innodb的区别:
1, 事务安全 myisam不支持事务,而innodb支持
2, 查询和添加速度, myisam他因为不支持事务,所以就代表不需要考虑同步锁,也就是说查找和添加的速度快
3, 支持全文检索方面 myisam支持 innodb不支持
4, 锁机制 myisam支持的是表锁 innodb支持的是行锁
5, 外键方面 myisam不支持外键 innodb支持外键
Java面试::选择合适的索引
What???--》索引是帮助dbms(数据库管理)用来高效获取数据的数据结构
分类 普通索引唯一索引主键索引全文索引
普通索引:允许重复的值出现
唯一索引:除了不能有重复的数据记录外,和普通索引一样
主键索引:是随着设定主键而创建的,也就是说把某个列设为主键的时候,这个时候数据库会给该列创建索引,注意!!主键索引是唯一的且不能是null值
全文索引:整个表中的文本域都是索引
Java面试::使用索引的一些技巧
索引有什么弊端!!!!
1,占用磁盘空间。
2, 对dml(插入、修改、删除)操作有影响,会变慢。
索引的使用场景:
,1:在where条件经常使用,如果不做查询基本上索引没有什么意义
2:该字段的内容不是唯一的几个值
3:字段的内容不能频繁的变化
具体的技巧:
1:对于创建多列索引的时候(复合索引),记住,如果不是使用的第一部分就不会使用索引
2:对于使用like语句的时候没如果查询是‘%aaa’ 不会使用索引,’aaa%’ 会使用索引
3:当你的sql语句有or的时候,只要是有条件没有使用索引,其他条件即使带索引也不会使用。
4:如果列类型是字符串,那一定要在条件中讲数据使用引号引起来,否则就不能使用索引
5:Mysql如果感觉我遍历整个表都比使用索引快,那么它自动就不使用索引了
Java面试::数据库优化之分表
根据经验,mysql数据达到百万级别,查询效率就非常低了,就会造成锁表,甚至堆积多连接,导致mysql直接挂掉,水平分表就可以减少压力。
按行数据进行分表:
如果一张表当中某个字段非常多(长文本,二进制),很少情况下查询,这个时候我们就要考虑把这些字段单独放到一个表中,通过外键关联起来。
场景:考试详情 我们就关心这个人考了多少分,不关心学习过程
水平分表策略:
1、 按时间分表 *****
a) 微博,qq,我们想要查询月份动态,或者月份的缴费情况,这些有规律性的数据内容,我们可以按时间分表
2、 按区间分表:数据库当中的自增id
3、 Hash分表********
a) 通过一个原始目标的id或者名称通过一定的合适算法,算出来数据库的表名称。然后访问相应的表。
Java面试::数据库的读写分离
背景:一台数据库支持最大的并发链接数量是有限的,如果用户访问量加大,一台服务器是满足不了我们的需求,所以我们用集群的方式来实现。
主从同步
读写分离
Java面试::数据库优化之缓存
Java当中我们持久层和数据库这个层面 常见的缓存有hb的二级缓存,mb二级缓存,这些缓存都不支持分布式缓存
我们可以用redis来作为中央缓存
Java面试::sql语句优化小技巧
- 对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
- 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
- 应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。
- 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如
select id from t where num=10 or Name = 'admin'
可以这样查询:
select id from t where num = 10union allselect id from t where Name = 'admin' - select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的。
调优参数: - back_log:back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。也就是说,如果MySql的连接数据达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。可以从默认的50升至500
- wait_timeout:数据库连接闲置时间,闲置连接会占用内存资源。可以从默认的8小时减到半小时
- max_user_connection: 最大连接数,默认为0无上限,最好设一个合理上限
- thread_concurrency:并发线程数,设为CPU核数的两倍
- skip_name_resolve:禁止对外部连接进行DNS解析,消除DNS解析时间,但需要所有远程主机用IP访问
- key_buffer_size:索引块的缓存大小,增加会提升索引处理速度,对MyISAM表性能影响最大。对于内存4G左右,可设为256M或384M,通过查询show status like 'key_read%',保证key_reads / key_read_requests在0.1%以下最好
- innodb_buffer_pool_size:缓存数据块和索引块,对InnoDB表性能影响最大。通过查询show status like 'Innodb_buffer_pool_read%',保证(Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests越高越好
- innodb_additional_mem_pool_size:InnoDB存储引擎用来存放数据字典信息以及一些内部数据结构的内存空间大小,当数据库对象非常多的时候,适当调整该参数的大小以确保所有数据都能存放在内存中提高访问效率,当过小的时候,MySQL会记录Warning信息到数据库的错误日志中,这时就需要该调整这个参数大小
- innodb_log_buffer_size:InnoDB存储引擎的事务日志所使用的缓冲区,一般来说不建议超过32MB
- query_cache_size:缓存MySQL中的ResultSet,也就是一条SQL语执行的结果集,所以仅仅只能针对select语句。当某个表的数据有任何任何变化,都会导致所有引用了该表的select语句在Query Cache中的缓存数据失效。所以,当我们的数据变化非常频繁的情况下,使用Query Cache可能会得不偿失。根据命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))进行调整,一般不建议太大,256MB可能已经差不多了,大型的配置型静态数据可适当调大.
可以通过命令show status like 'Qcache_%'查看目前系统Query catch使用大小 - read_buffer_size:MySql读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分配一段内存缓冲区。如果对表的顺序扫描请求非常频繁,可以通过增加该变量值以及内存缓冲区大小提高其性能
- sort_buffer_size:MySql执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。如果不能,可以尝试增加sort_buffer_size变量的大小
- read_rnd_buffer_size:MySql的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySql会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。
- record_buffer:每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描,可能想要增加该值
- thread_cache_size:保存当前没有与连接关联但是准备为后面新的连接服务的线程,可以快速响应连接的线程请求而无需创建新的
- table_cache:类似于thread_cache_size,但用来缓存表文件,对InnoDB效果不大,主要用于MyISAM
Java面试::批量插入几百万条数据
1、 修改事务的提交方式
2、 set autocommit=0 开启
//批量导入数据的时候
set autocommit=1 关闭
2、将多条sql语句合成一条去执行
能省出的时候非常可观
尽量不要用java代码去写,要用存储过程(最好用)。
Java面试::有没有使用过redis
介绍一下redis
Redis是一个key_value的非关系型数据库,它会先把数据放到内存房中,,会根据一定的策略持久化到磁盘当中,及时断电也不会丢失,支持的数据类型比较多。(数据结构)
Redis主要是用来。缓存数据库当中的数据,在web集群当中用作中央缓存存放session
Java面试::redis的使用场景
缓存:
把经常需要查询的,很少修改的数据,放到读取速度很快的空间当中(redis),来减少访问时间,减轻数据压力
计数器:
Redis当中的计数器是原子性的内存操作
可以解决数据库溢出的问题。
Session缓存服务器
web集群当中用作中央缓存存放session
Java面试::redis存储对象的方式
1、我们需要把对象转化成json字符串,当做字符串处理,直接我们就可以使用set get来设置
优点就是:获取和设置的时候比较简单
缺点是:redis没有专门的方法去把对象转化成json形式
3、 字节的形式,必要的时候,我们可以把对象序列化,转化成字节保存
我们会担心json在转化成对象的时候会消耗我们的资源的???
第一点:我们使用lib库转化成json的形式的时候,是否会存在性能问题
第二点,数据量的级别,百万级别的大对象,我们就不要用lib转json的形式,我们就直接用序列化的形式
根据应用场景结合业务---redis其实对string支持的最好如果数据量少,我们还是要用json的形式
Java面试::redis数据淘汰机制
背景:
在redis当中,我们用户是可以设置最大使用内存的大小,但是内存是固定的,所以需要我们有一定的数据淘汰机制
1、 volatile_lru 从已设置过期时间的数据集中挑选最近很少使用的数据淘汰
2、 volatile_ttl 从已设置过期时间的数据集中选择将要过期的数据淘汰
3、 volatile_random: 从已设置过期时间的数据集中任意选择数据淘汰
4、 allkeys_lru:从数据集中挑选最近使用的数据淘汰
5、 allkeys_ random:从数据集当中任意选择数据淘汰
6、 no_enviction:禁止驱逐数据
java面试题:为什么要使用消息队列?
直接回答6个字,解耦、异步、削峰
使用消息队列有什么缺点?
1,系统可用性降低:你想啊,本来其他系统只要运行好好的,那你的系统就是正常的。现在你非要加个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性降低
2,系统复杂性增加:要多考虑很多方面的问题,比如一致性问题、如何保证消息不被重复消费,如何保证保证消息可靠传输。因此,需要考虑的东西更多,系统复杂性增大
怎么选型???ActiveMQ,RabbitMQ,RocketMQ,Kafka
建议选RabbitMQ.一方面,erlang语言天生具备高并发的特性,而且他的管理界面用起来十分方便。正所谓,成也萧何,败也萧何!他的弊端也在这里,虽然RabbitMQ是开源的,然而国内有几个能定制化开发erlang的程序员呢?所幸,RabbitMQ的社区十分活跃,可以解决开发过程中遇到的bug,这点对于中小型公司来说十分重要。不考虑rocketmq和kafka的原因是,一方面中小型软件公司不如互联网公司,数据量没那么大,选消息中间件,应首选功能比较完备的,所以kafka排除。不考虑rocketmq的原因是,rocketmq是阿里出品,如果阿里放弃维护rocketmq,中小型公司一般抽不出人来进行rocketmq的定制化开发,因此不推荐。
(2)大型软件公司,根据具体使用在rocketMq和kafka之间二选一。一方面,大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。针对rocketMQ,大型软件公司也可以抽出人手对rocketMQ进行定制化开发,毕竟国内有能力改JAVA源码的人,还是相当多的。至于kafka,根据业务场景选择,如果有日志采集功能,肯定是首选kafka了。具体该选哪个,看使用场景。如何保证消息不被重复消费?
Java面试题:如何保证消息不被重复消费?
分析:这个问题其实换一种问法就是,如何保证消息队列的幂等性?
回答:先来说一下为什么会造成重复消费?
其实无论是那种消息队列,造成重复消费原因其实都是类似的。正常情况下,消费者在消费消息时候,消费完毕后,会发送一个确认信息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除。只是不同的消息队列发送的确认信息形式不同,例如RabbitMQ是发送一个ACK确认消息,RocketMQ是返回一个CONSUME_SUCCESS成功标志,kafka实际上有个offset的概念,简单说一下(如果还不懂,出门找一个kafka入门到精通教程),就是每一个消息都有一个offset,kafka消费过消息后,需要提交offset,让消息队列知道自己已经消费过了。那造成重复消费的原因?,就是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将该消息分发给其他的消费者。
如何解决?这个问题针对业务场景来答分以下几点
(1)比如,你拿到这个消息做数据库的insert操作。那就容易了,给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
(2)再比如,你拿到这个消息做redis的set的操作,那就容易了,不用解决,因为你无论set几次结果都是一样的,set操作本来就算幂等操作。
(3)如果上面两种情况还不行,上大招。准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。
6、如何保证消费的可靠性传输?
回答:其实这个可靠性传输,每种MQ都要从三个角度来分析:生产者弄丢数据、消息队列弄丢数据、消费者弄丢数据
RabbitMQ
(1)生产者丢数据
从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息。
transaction机制就是说,发送消息前,开启事物(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事物就会回滚(channel.txRollback()),如果发送成功则提交事物(channel.txCommit())。
然而缺点就是吞吐量下降了。因此,生产上用confirm模式的居多。一旦channel进入confirm模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,rabbitMQ就会发送一个Ack给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了.如果rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作。处理Ack和Nack的代码如下所示(说好不上代码的,偷偷上了):
(2)消息队列丢数据
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。
那么如何持久化呢,这里顺便说一下吧,其实也很容易,就下面两步
1、将queue的持久化标识durable设置为true,则代表是一个持久的队列
2、发送消息的时候将deliveryMode=2
这样设置以后,rabbitMQ就算挂了,重启后也能恢复数据
消费者丢数据
消费者丢数据一般是因为采用了自动确认消息模式。这种模式下,消费者会自动确认收到信息。这时rahbitMQ会立即将消息删除,这种情况下如果消费者出现异常而没能处理该消息,就会丢失该消息。
至于解决方案,采用手动确认消息即可。
KAFKA
(1)生产者丢数据
在kafka生产中,基本都有一个leader和多个follwer。follwer会去同步leader的信息。因此,为了避免生产者丢数据,做如下两点配置
- 第一个配置要在producer端设置acks=all。这个配置保证了,follwer同步完成后,才认为消息发送成功。
- 在producer端设置retries=MAX,一旦写入失败,这无限重试
(2)消息队列丢数据
针对消息队列丢数据的情况,无外乎就是,数据还没同步,leader就挂了,这时zookpeer会将其他的follwer切换为leader,那数据就丢失了。针对这种情况,应该做两个配置。 - replication.factor参数,这个值必须大于1,即要求每个partition必须有至少2个副本
- min.insync.replicas参数,这个值必须大于1,这个是要求一个leader至少感知到有至少一个follower还跟自己保持联系
这两个配置加上上面生产者的配置联合起来用,基本可确保kafka不丢数据
(3)消费者丢数据
这种情况一般是自动提交了offset,然后你处理程序过程中挂了。kafka以为你处理好了。再强调一次offset是干嘛的
解决方案也很简单,改成手动提交即可。