2020最新java面试题库(杭州)

目 录
1.常见的集合有哪些?都有什么区别: 1
2.HashMap的底层原理: 1
3.sleep和wait的区别 1
4.run方法和start方法的区别: 1
5.Threadlocad的作用: 2
6.solr查询出的数据放在哪: 本地 磁盘中 2
7.为什么用solr和其他的区别在哪:https://blog.csdn.net/jokeylin/article/details/80562148 2
8.支付宝的支付流程: 2
9.数据库有几种索引: 3
10redis五种数据类型和应用场景 3
11线程池工作原理: 4
12Gc(垃圾回收机制)的四种算法 4
13Spring ioc和aop 原理 4
14设计模式; 5
15.Redis持久化: 5
16.悲观锁和乐观锁 5
17.springmvc的工作原理: 5
18.索引过多会引发什么: 6
19.手写冒泡: 6
20.在开发中于遇到的困难,怎么解决的,有什么收获 6
21.谈谈集合? 6
22.Hashmap的底层原理? 7
23.有对hashmap初始容量进行修改过吗?修改原理初始容量? 7
24.多线程中使用的集合有哪些是线程安全的? 7
25.项目中有涉及多线程吗?采用什么方法创建线程?(创建线程的集中方式) 8
26.数据库用的什么连接的? 8
27.在哪种场景下使用的多线程?(回答订单)用在订单的用户量很大为什么使用创建线程没有使用创建线程池? 8
28.线程的生命周期? 8
29.说下Ioc Aop 和项目中用到的地方? 10
31.公司项目部署都是手工部署,说一下Linux的常用命令? 10
32.==和equals的区别? 11
33.项目有没有上线的?做了几个项目? 11
34.项目登录功能实现过程?token怎么生成的?登录是用的框架还是自己直接写的? 11
35.登录验证有几步验证?写个脚本一直请求怎么处理的? 11
36.订单模块怎么实现的? 11
37.Tcp、http协议 11
38.mysql数据库存储结构?数据库锁? 12
39.实现线程的方式? 12
40.Nginx的作用? 12
40微服用户信息如何获取? 12
41Sprongboot常用注解? 12
42手写单例 13
43springmvc工作流程 13
44sleep和wait区别 14
45mysql图形计划 14
46sql优化 15
47spring注入方式 15
48redis优点 15
49spring事务管理有几种 15
51.Spring单例线程是否安全 16
52. JDK、JRE、JVM是什么 16
53.Hashmap运行原理 16
54. IO与NIO的区别 17
55. 如何实现多线程 17
3.使用ExecutorService、Callable、Future实现有返回结果的多线程 17
应用场景: 需要让异步执行的线程在执行完成后返回一个值给当前的线程,当前的线程需要依赖这个值做一些其他的业务操作,这个时候就需要实现有返回结果的多线程 17
56.如何防止死锁 17
57. 消息队列 18
58. 内存溢出 20
59. ioc与aop 21
60. Redis持久化 22
61设计模式以及原理? 22
62、分布式? 22
63微服框架? 23
64、反射机制? 23
65、Mvc? 23
66、Jdk 1.8新出了什么功能? 23
67、垃圾回收机制? 23
68、内连接和左外连接的区别? 23
69、Zookeeper原理、作用? 23
70、Dubbo特点和springcloud区别? 24
71.如何保证线程安全 24
72. 内存溢出的原因和解决方法 24
73. 单例模式的作用 25
74. 数据库优化的方法 25
75. hashMap原理 26
76. finally final finaize的区别 26
77. 连接池的作用是什么? 26
78. 什么是 JAVA 事务? 26
79. 主键索引和普通索引的区别 26
80. springmvc工作流程 27
81.wait与sleep的区别 27
82.mysql执行计划 27
83.sql优化 28
84.spring注入方式 29
85.redis优点 29
86.spring事务管理有几种 30
87.spring单例线程是否安全 30
88.除了SSM还用过什么框架 31
89.spring核心库,功能 31
90.springIOC和AOP原理 31
91自己写会怎么写IOC,AOP 32
92spring怎么注入 32
93在二班的课程大于3个的学生 33
94在开发过程中遇到过对框架技术问题怎么解决 33
95对未来3年规则 33
96对产品是否了解 33
97加班出差怎么看 33
98有没有需要问我们 33
99解码格式 33
100接口 33
101. 数据类型不匹配 34
102. spring整个请求流程 34
103. servlet的生命周期 34
104. 别人调用接口时中文乱码解决方式 35
105. web.xml的作用 35
106. double和float的区别 35
107. ArrayList使用时有什么注意事项 35
108. ArrayList和LinkedList区别 35
109. 多态怎么实现 36
110. 重写注意点,怎么看调用的是父类还是子类,权限要求 36
111重载的返回值要求 36
112对redis的理解 36
113使用spring的好处 37
114数据库调用 37
115mybatis中的#和 的 区 别 , 的区别, ,的应用场景 38
116接口和抽象类的区别和各自的应用场景 38
117solr怎么建立索引 38

1.常见的集合有哪些?都有什么区别:
List集合:
ArrayList:数组结构,线程不安全,执行查询效率块,增删改慢
LinkList:链表结构,对元素执行增删改效率高
Set集合:
HashSet:要保证元素唯一性,需要覆盖掉Object中的equals和hashCode方法
(因为底层是通过这两个方法来判断两个元素是否是同一个)
TreeSet:以二叉树的结构对元素进行存储,可以对元素进行排序
Map集合:元素是成对出现的,以健值对的方式体现,健保证唯一性
HashMap:线程不安全,允许存放null键null值
HashTable:线程安全,不允许存放null键null值
TreeMap:可以对键进行排序,

2.HashMap的底层原理:
是以数组和链表的形式存储元素

3.sleep和wait的区别
1.wait来自Object类,sleep来之Thread类
2.调用sleep方法,线程不会释放对象锁,而调用wait方法线程会释放对象锁
3.slee睡眠后不出让系统资源,wait让其他线程可以占用cup
4.sleep需要一个指定睡眠时间,时间一到会自动唤醒,而wait需要配合notify方法或者notifyAll方法使用

4.run方法和start方法的区别:
run方法:当前普通方法的方式调用,程序还是顺序执行,还是要等待run方法体执行完毕后才会继续执行下面的代码

start方法:用来启动线程,真正实现了多线程运行,无序等待run方法体执行完毕后才执行下面的代码

5.Threadlocad的作用:
提供线程内部的局部变量,并且这些变量依靠线程独立存在,可以在多个线程中互不干扰的进行存储数据和修改数据,通过set,get和remove方法。每个线程都是独立操作

原理:在不同的线程中访问一个对象,获取的值是不一样的,因为内部会从各个线程取出一个数组,
	  通多对应的下标,查找对应的值

6.solr查询出的数据放在哪: 本地 磁盘中

7.为什么用solr和其他的区别在哪:https://blog.csdn.net/jokeylin/article/details/80562148
solr是一款高性能的搜索引擎,同时对其进行的扩展,提供了比Lucene更为丰富的查 询语言,实现了高配置,可扩展对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常丰富的全文搜索引擎。

8.支付宝的支付流程:
先是生成商户系统一笔未支付的订单,获得商户订单ID(商户系统生成)和订单的一些其他信息,然后再调用支付宝的SDK提供的数字签名方法,将需要传给支付宝的信息进行加签,然后把加签后的字符串返回给APP。APP拉起支付宝APP,再把这个加签的字符串传给支付宝,完成支付。APP接收到同步通知后,还需要再次调用商户后台的接口(虽然同步通知也有付款情况,但需要以后台通知为准),校验订单最终的付款情况。按照支付宝API上所说,当完成支付后,支付宝会做2个操作,一个是同步返回信息给APP,一个是异步通知商户后台返回支付状态等信息,并且最终的支付结果是以异步通知为准。所以我们还需要考虑到一点,就是当用户支付成功之后,商户系统暂时没有接收到支付宝的异步通知时。我们需要拿着这个商户订单ID主动调用SDK支付宝的查询接口,去获取该订单的支付情况,并最终返回给APP

当点击支付的时候将一笔未支付的订单信息(包含商家,商品以及用户的信息)给支付宝,当输入支付密码支付宝调用SDK加签再给支付宝,当支付完成后,支付宝会做2个操作,一个是同步返回信息给APP,一个是异步通知商户后台返回支付状态等信息,并且最终的支付结果是以异步通知为准。

9.数据库有几种索引:
主键索引:最常见的索引,确保数据记录的唯一性,确定特定数据在数据库的位置
唯一索引:避免同一个表中某数据列中的值重复
常规索引:快速定位特定数据
全文索引:快速定位特定数据

10redis五种数据类型和应用场景
①String(字符串):
string 是 redis 最基本的类型,你可以理解成与 Memcached(分布式缓存) 一模一样的类型,一个 key 对应一个 value。
string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
②Hash(哈希表):
Redis hash 是一个键值(key=>value)对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
③List(集合):
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边
④Set(集合):
Redis 的 Set 是 string 类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
⑤zset(sorted set:有序集合):
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复

11线程池工作原理:
先启动若干数量的线程,并让这些线程都处于睡眠状态,当客户端有一个新请求时,就会唤醒线程池中的某一个睡眠线程,让它来处理客户端的这个请求,当处理完这个请求后,线程又处于睡眠状态

12Gc(垃圾回收机制)的四种算法
及时清除不再使用的对象,将内存清理出来,
①引用计数法:
②标记清除法:
为每个对象存储一个标记位,记录对象的状态(活着或者死亡),死亡则进行清除
③标记压缩法:
是标记清楚法的改进版,该算法不会对死亡的对象直接清理,而是将所有存活的对 象整理一下,放到另一个空间,然后把剩下的对象全部清除
优点: 该算法不会产生大量的碎片空间
缺点: 如果存活对象过多,整理阶段将会执行过多的复制操作,导致算法效率
④复制算法:
将内存评分分成两部分,然后每次只使用其中一部分,当这部分内存满的时候,将 内存中存活的对象复制到另一个内存中,然后将之前的内存清空,只使用这部分内 存,循环下去。

13.Spring ioc和aop 原理
ioc(控制反转):是工厂模式
其包含两个内容,一是控制,二是反转,在程序中,被调用类的选择控制权从调用 它的类中移除,转交给第三方裁决。第三方指的就是spring的容器,IOC另解,依 赖注入,调用类对被调用类的依赖关系由第三方注入,以移除调用类对被调用类的 使用。

aop(面向切面编程):是代理模式
是目前软件开发中的一个热点,也是spring框架中的重要内容,利用AOP可以对 业务逻辑的各个本分进行隔离,从而使得业务逻辑的各个部分减低耦合度,提供程 序的可重用性,提高了开发效率

14设计模式;
工厂模式:spring的IOC容器就是一个大的Bean实列的工厂,复制Bean的周期管理
单列模式:和spring的IOC 是一起的,既然IOC是一个大工程,那么Bean对象为了 减少内存开销就需要提供单列特征。
代理模式:为其他对象提供一种代理访问的机制
观察者模式:当对象发生变化时,则会通知他的依赖对象,属于行为型模式

15.Redis持久化:
ROB:在指定的时间间隔能对你的数据进行快照存储
AOF:记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据

用一句话可以将持久化概括为:将数据(如内存中的对象)保存到可永久保存的存储设 备中。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件 中、 XML 数据文件中等等

为什么要做持久化:因为redis的数据是缓存在内存中的,当你重启或者关闭系统后, 缓存在内存中的数据就会消失殆尽,再也找不回来,所以,为了能让数据长期保存, 就一号将Redis缓存在内存中的数据做持久化成操作。

怎么实现持久化:
1、RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。
2、AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。
3、如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
4、你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

16.悲观锁和乐观锁
悲观锁:总是假设最坏的情况发生,因此每次在取数据的时候就会加锁,操作完成后才 释放锁。Java中典型的悲观锁就是
乐观锁:假设大数据情况下不会发生数据冲突,因此在取数据的时候不加锁,只有在更 新的时候判断该数据在此期间释放被修改过

17.springmvc的工作原理:
1.用户发送请求给点的控制器DispatcherServlet
2.DispatcherServlet接收到用户请求后,通过HandlerMapping处理器映射器寻找合理的 处理器进行处理
3.处理器映射器找到具体的处理器后,生成处理器对象以及处理器拦截器,并返回给前 端控制器
4.前端控制器调用处理器适配器,将请求交给处理器处理
5.处理器适配器调用具体的处理器对请求进行处理
6.处理器处理完成后放回ModelAndView
7.处理器适配器将放回的ModelAndView返回给前端控制器
8.前端控制器将ModelAndView交给视图解析器进行解析
9.视图解析器解析之后返回具体的View
10.前端控制器根据具体的View进行渲染
11.前端控制器响应用户请求

18.索引过多会引发什么:
增加存储开销,对于插入,删除,更新操作也会增加处理上的开销,过多的复合索引, 在有单字段索引情况下,一般都是没有价值的,还有降低性能,特表是对频繁更新的 表来说,负面影响更大

19.手写冒泡:
public static void main(Sring[] args){
//使用冒泡排序实现升序降序
ing[] array={5,25,42,9,36,50,28};
for(int i=0;i<array.length-1;i++){
for(int j=0;j<array.length-1;j++){
if(array[j] > array[j+1]){
int temp;
temp=array[j];
array[j]=array[j+1];
array[j+1]=temp
}
}
System.out.println(“排序后”)
for(int i=o;i<array.length;i++){
System.out.print (array[i]
}
}
}

20.在开发中于遇到的困难,怎么解决的,有什么收获
力求自己解决,可以百度或者进入CSDN之类的学习平台。实在不行找身边的同事
与身边的同事相处好更有利于以后的开发
21.谈谈集合?
集合多个个体拥有同种特性聚集在一起,Java集合是java提供的一个工具包,全部继承自java.util.*。
主要包括两大接口Collection接口和Map接口以及相关的工具类
(Iterator迭代器接口、Enumeration枚举类、Arrays和Colletions)

22.Hashmap的底层原理?
HashMap底层是通过数组加链表的结构来实现的HashMap 的实例有两个参数影响其性能
:“初始容量” 和 “加载因子”HashMap 根据键的 hashCode 值存储数据,大多数情况
下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。
HashMap 最多只允许一条记录的键为 null ,允许多条记录的值为 null 。
HashMap 非线程安全,即任一时刻可以有多个线程同时写 HashMap,可能会
导致数据的不一致。如果需要满足线程安全,可以用 Collections的
synchronizedMap 方法使 HashMap 具有线程安全的能力,或者使用ConcurrentHashMap。
在JDK1.8之前,它的底层结构是数组+链表,而在JDK1.8之后,为了查询效率的优化
(主要是当哈希碰撞较多的时候),它的底层结构变成了数组+链表+红黑树

23.有对hashmap初始容量进行修改过吗?修改原理初始容量?
当我们设置了初始化容量,HashMap就会按照我们设置的容量进行设置吗?
答案是不一定。当你设置的初始化容量是2的n次方时,就会按照你设置的容量设置
;当你设置的初始化容量不是2的n次方时,就会按照大于你设置的那个值但是最接近
你设置的那个值的2的n次方进行设置其中size是HashMap中添加键值对的数量,
而threshold是容量加载因子(capacity * load factor)得出的值,
也是就当我们的容量是16,加载因子是0.75时,当键值对的数量大于16
0.75=12时
,HashMap会进行扩容操作

24.多线程中使用的集合有哪些是线程安全的?
ConcurrentHashMap是Java5中新增加的一个线程安全的Map集合
ConcurrentSkipListSet是线程安全的有序的集合,适用于高并发的场景
LinkedBlockingQueue是一个线程安全的阻塞队列,它实现了BlockingQueue接口
,BlockingQueue接口继承自java.util.Queue接口,并在这个接口的基础上增加了
take和put方法,这两个方法正是队列操作的阻塞版本。
CopyOnWriteArrayList是ArrayList 的一个线程安全的变体,
其中所有可变操作(add、set等等)都是通过对底层数组进行一次新的复制来实现的
Vector和HashTable实现了线程安全的数组和散列表;在java1.2版本中他们就已经不再使用了
,取而代之是ArrayList和HashMap这些集合类不是线程安全但是他们可以通过集合库中提供的
同步包装器使其变成线程安全的;

25.项目中有涉及多线程吗?采用什么方法创建线程?(创建线程的集中方式)
继承therad,实现runnable

26.数据库用的什么连接的?
navicat

27.在哪种场景下使用的多线程?(回答订单)用在订单的用户量很大为什么使用创建线程没有使用创建线程池?
场景一:一个业务逻辑有很多次的循环,每次循环之间没有影响,比如验证1万条url路径是否存在,正常情况要循环1万次,逐个去验证每一条URL,这样效率会很低,假设验证一条需要1分钟,总共就需要1万分钟,有点恐怖。这时可以用多线程,将1万条URL分成50等份,开50个线程,没个线程只需验证200条,这样所有的线程执行完是远小于1万分钟的。

场景二:需要知道一个任务的执行进度,比如我们常看到的进度条,实现方式可以是在任务中加入一个整型属性变量(这样不同方法可以共享),任务执行一定程度就给变量值加1,另外开一个线程按时间间隔不断去访问这个变量,并反馈给用户。

我知道线程池是一件好事,因为它可以重用线程,从而节省创建新线程的成本
如果在其上运行的任务通过阻塞队列交换信息,则有限大小的线程池是危险的,
这可能导致线程饥饿

28.线程的生命周期?
New(初始化状态)
Runnable(可运行/运行状态)
Blocked(阻塞状态)
Waiting(无时间限制的等待状态)
Timed_Waiting(有时间限制的等待状态)
Terminated(终止状态)
1.New(初始化状态):指的是在高级语言,比如Java。在Java层面的线程被创建了,而在操作系统中的
线程其实是还没被创建的,所以这个时候是不可能分配CPU执行这个线程的!所以这个状态是高级语言独
有的,操作系统的线程没这个状态。我们New了一个线程,那时候它就是这个状态。
2.Runnable(可运行/运行状态):这个状态下是可以分配CPU执行的,在New状态时候我们调用start()方法后线程就处于这个状态。
3.Blocked(阻塞状态):这个状态下是不能分配CPU执行的,只有一种情况会导致线程阻塞,就是synchronized
!我们知道被synchronized修饰的方法或者代码块同一时刻只能有一个线程执行,而其他竞争锁的线程就从
Runnable到了Blocked状态!当某个线程竞争到锁了它就变成了Runnable状态。注意并发包中的Lock,是
会让线程属于等待状态而不是阻塞,只有synchronized是阻塞。(感觉是历史遗留问题,没必要多一个阻塞状态和等待没差啊)。
4.Waiting(无时间限制的等待状态):这个状态下也是不能分配CPU执行的。有三种情况会使得Runnable状态到waiting状态
调用无参的Object.wait()方法。等到notifyAll()或者notify()唤醒就会回到Runnable状态。
调用无参的Thread.join()方法。也就是比如你在主线程里面建立了一个线程A,调用A.join(),那么你的主线程是得等A执行完了才会继续执行,这是你的主线程就是等待状态。
调用LockSupport.park()方法。LockSupport是Java6引入的一个工具类Java并发包中的锁都是基于它实现的,再调用LocakSupport.unpark(Thread thread),就会回到Runnable状态。
5.Timed_Waiting(有时间限制的等待状态):其实这个状态和Waiting就是有没有超时时间的差别,这个状态下也是不能分配CPU执行的。有五种情况会使得Runnable状态到waiting状态
Object.wait(long timeout)。
Thread.join(long millis)。
Thread.sleep(long millis)。注意 Thread.sleep(long millis, int nanos) 内部调用的其实也是Thread.sleep(long millis)。
LockSupport.parkNanos(Object blocked,long deadline)。
LockSupport.parkUntil(long deadline)。
6.Terminated(终止状态):在我们的线程正常run结束之后或者run一半异常了就是终止状态!
注意有个方法Thread.stop()是让线程终止的,但是这个方法已经被废弃了,不推荐使用,因为比如你这个线程得到了锁,你stop了之后这个锁也随着没了,其它线程就都拿不到这个锁了!这不玩完了么!所以推荐使用interrupt()方法。
interrupt()会使得线程Waiting和Timed_Waiting状态的线程抛出 interruptedException异常,使得Runnabled状态的线程如果是在I/O操作会抛出其它异常。
如果Runnabled状态的线程没有阻塞在I/O状态的话,那只能主动检测自己是不是被中断了,使用isInterrupted()。

29.说下Ioc Aop 和项目中用到的地方?
ioc,控制反转,这个指的就是我们获取对象的方式进行反转了,改变了。在使用spring之前是需要手
动new出来的,是我们主动获取的。使用spring之后,是将这个获取的过程交给spring来管理,我们只需
要告诉spring你需要什么就行了,它就会把东西给你。比如:在没有电商的时候,我们去上街买东西,需
要考虑到这东西有没有,价钱多少,怎么搬回来,去有多远……等等无数个和主要的业务逻辑(买东西)无
关的问题。这样就会扰乱主业务逻辑。当我们有了电商平台后,买东西时只需要两步。注册账号(装载bean)
,告诉电商你要的东西名字(通过名字获取Bean),然后就可以在门口收到东西了。这就是ioc。
aop,面向切面。在谈这个之前需要了解几个词:切面,切入点,织入,目标对象,通知。
我先解释下名字的意思,再讲故事。
切面:就是你要准备增强的那些方法。
切入点:就是具体织入的方法,定义了地点
织入:动词,就是将切面织入的过层
目标对象:被增强的类
通知:就是什么时候增强,定义了时间
好了,了解清楚上面的几个词的意思后,再听故事就容易多了。
aop的功能就是用来增强,在执行主业务的通知也顺带执行其他业务。如:老李上街办点事儿,走啊走,走到了老王家门前(切入点),老王看见老李问:去哪啊!
老李:上街办点事儿(目标类)
老王:那帮我顺便把这封信投到邮筒里吧。(切面),等到10点的时候邮局开门了去柜台投。(通知)
老李:好嘞。然后老李接过信。(织入)
老李继续走啊走,继续上街办事(增强后的目标类)。办完事后老李回家了。
以上就是aop。aop一般用来处理权限控制,日志记录,加载事务等非主要业务逻辑的事情。底层是采用cglib和jdk的动态代理实现的。

31.公司项目部署都是手工部署,说一下Linux的常用命令?
shutdown -h now 关闭系统,cd 进入个人的主目录,ls查看当前目录下文件,命令有很多,使用时可以查看文档。

32.==和equals的区别?
==是指对内存地址进行比较 , equals()是对字符串的内容进行比较

33.项目有没有上线的?做了几个项目?
上线了/没上线,做过两个项目/三个项目,按自己情况说。
34.项目登录功能实现过程?token怎么生成的?登录是用的框架还是自己直接写的?
获取前端登录的数据(验证码,用户名,密码等),先验证验证码是否正确,再验证用户名和密码(加不加密随意)是否正确,正确与否都要做出提示,然后再设置一个Cookie机制用来保存用户登录的信息,如果勾选了保存密码,就可以对Cookie设置有效期之类的。也可以生成token。 token(分为三部分,header密文,payload密文,签名),将荷载payload,以及Header信息进行Base64加密,形成密文payload密文,header密文,将形成的密文用句号链接起来,用服务端秘钥进行HS256加密,生成签名,将前面的两个密文后面用句号链接签名形成最终的token返回给服务端。 登录用了框架/自己写(视自己的情况说)。

35.登录验证有几步验证?写个脚本一直请求怎么处理的?
同上步骤 Ajax请求外面套一层循环或者递归函数

36.订单模块怎么实现的?
首先订单模块有订单的增删改查等功能,用户选好商品后提交,生成订单详情,然后用户可以对这个订单进行一些操作比如支付、取消等。在生成订单时可能会有并发的情况,这里我使用了消息队列解决并发问题。

37.Tcp、http协议
HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用, HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,过程称为“一次连接” 。。。 TCP/IP是一个协议簇,是由许多协议组成的,TCP/IP按照层次从上至下分为四层,建立起一个TCP连接需要经过“三次握手”

38.mysql数据库存储结构?数据库锁?
存储结构是保存在连续的内存中,所以采用的是B-树索引 。数据库储存引擎有Inoodb,MyISAM,Memory,mysql默认采用的是inoodb。 数据库锁:表级锁(表共享读锁和表独占写锁),行级锁(共享锁,排他锁,意向共享锁和意向排他锁,间隙锁),页级锁
39.实现线程的方式?
实现Runnable接口,以及继承Thread类

40.Nginx的作用?
一、静态http服务器,Nginx是一个HTTP服务器,可以将服务器上的静态文件(如HTML、图片)通过HTTP协议展现给客户端。二、反向代理服务器,客户端本来可以直接通过HTTP协议访问某网站应用服务器,网站管理员可以在中间加上一个Nginx,客户端请求Nginx,Nginx请求应用服务器,然后将结果返回给客户端。三、负载均衡,Nginx可以通过反向代理来实现负载均衡。四、虚拟主机,有的网站,由于访问量太小,需要节省成本,将多个网站部署在同一台服务器上。
40微服用户信息如何获取?
用dubbox搭建的微服各模块注册信息从zookeeper注册中心获取,用springcloud搭建的微服各模块注册信息从eureka注册中心获取。

41Sprongboot常用注解?
@Service: 注解在类上,表示这是一个业务层bean
@Controller:注解在类上,表示这是一个控制层bean
@Repository: 注解在类上,表示这是一个数据访问层bean
@Component: 注解在类上,表示通用bean ,value不写默认就是类名首字母小写
@Autowired:按类型注入
@Resource: 按名称装配
@Configuration:注解在类上,表示这是一个IOC容器,
@Bean: 注解在方法上,声明当前方法返回一个Bean
@Scope:注解在类上,描述spring容器如何创建Bean实例。
@Value:注解在变量上,从配置文件中读取。
@ConfigurationProperties: 赋值,将注解转换成对象。
@EnableAutoConfiguration启用 Spring 应用程序上下文的自动配置,试图猜测和配置您可能需要的bean。
@SpringBootApplication=@ComponentScan+@Configuration+@EnableAutoConfiguration:约定优于配置
@ComponentScan:注解在类上,扫描标注了@Controller等注解的类,注册为bean 。
@RestController @RestController 是一个结合了 @ResponseBody 和 @Controller 的注解
@Responsebody:表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping后,返回值通常解析为跳转路径,加上@Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。
@PathVariable、@RequestParam:两者的作用都是将request里的参数的值绑定到contorl里的方法参数里的,区别在于,URL写法不同。
@EnablCaching:pring framework中的注解驱动的缓存管理功能。
@suppresswarnings: 抑制警告
@Modifying :增,改,删加注解

42手写单例
public class Singleton {
private static Singleton = new Singleton();
private Singleton() {}
public static getSignleton(){
return singleton;
}
}
43springmvc工作流程
1、用户向服务端发送一次请求,这个请求会先到前端控制器DispatcherServlet(也叫中央控制器)。
2、DispatcherServlet接收到请求后会调用HandlerMapping处理器映射器。由此得知,该请求该由哪个Controller来处理(并未调用Controller,只是得知)
3、DispatcherServlet调用HandlerAdapter处理器适配器,告诉处理器适配器应该要去执行哪个Controller
4、HandlerAdapter处理器适配器去执行Controller并得到ModelAndView(数据和视图),并层层返回给DispatcherServlet
5、DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真正的视图。
6、DispatcherServlet将模型数据填充到视图中
7、DispatcherServlet将结果响应给用户
44sleep和wait区别
 原理不同
sleep是Thread类的静态方法,是线程用来控制自身流程的,它会使此线程暂停执行指定的时间,而把执行机会让给其他的线程,等到计时时间到,此线程会自动苏醒.
wait是Object类的方法,用于线程间的通信,这个方法会使当前拥有该对象锁的进程等待,直到其他线程调用notify方法才醒来,也可以指定时间自己醒来.
 对锁的处理机制不同
由于sleep方法的主要作用是让线程休眠指定一段时间,在时间到时自动恢复,不涉及线程间的通信,因此,调用sleep方法并不会释放掉锁.
但是调用wait方法的时候,线程会释放掉它所占用的锁,从而使线程所在对象中的其他synchronized数据可以被其他线程使用.
 使用的区域不同
由于wait方法的特殊含义,所以它必须放在同步控制方法或者同步语句块中使用,而sleep方法则可以放在任何地方使用.
 异常的捕获
sleep方法必须捕获异常,而wait,notify以及notifyall不需要捕获异常,在sleep的过程中,有可能别其他对象调用其interrupt(),产生InterruptedException异常.
sleep不会释放锁标志,容易导致死锁的发生,所以一般情况下,不推荐使用sleep方法,而是使用wait方法.
45mysql图形计划
执行计划,简单的来说,是SQL在数据库中执行时的表现情况,通常用于SQL性能分析,优化等场景。在MySQL中使用 explain 关键字来查看。explain sql语句
table:显示这一行的数据是关于哪张表的
type:显示连接使用了何种类型。
possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。
key:实际使用的索引。
key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好
ref:显示索引的哪一列被使用了,如果可能的话,是一个常数
rows:MYSQL认为必须检查的用来返回请求数据的行数
Extra:关于MYSQL如何解析查询的额外信息。
46sql优化
1、在表中建立索引,优先考虑where、group by使用到的字段。
2、尽量避免使用select *,返回无用的字段会降低查询效率。
3、尽量避免使用in 和not in,会导致数据库引擎放弃索引进行全表扫描。
4、尽量避免使用or,会导致数据库引擎放弃索引进行全表扫描。
5、尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描。
6、尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。
7、尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描。
8、当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描。
47spring注入方式
一、构造器注入
构造器注入依赖于构造方法的实现,构造方法可以是有参数的,也可以是无参数的 。
二、setter注入
setter注入利用JAVA Bean规范所定 首先将构造方法设置为无参的构造方法,然后利用setter注入为其设置新的值,这是通过java的反射技术得以实现的
三、接口注入
有时候资源并非来自于自身的系统,而是来自于外界,比如说数据库连接资源完全可以在Tomcat下配置,然后通过JNDI的方式去获取它,这样的数据库连接资源就属于开发工程外的资源。

48redis优点
性能极高: Redis能读的速度是110000次/s,写的速度是81000次/s 。
丰富的数据类型: Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
原子性: Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。(事务)
丰富的特性:Redis还支持 publish/subscribe, 通知, key 过期等等特性。

49spring事务管理有几种
(1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
(2)基于 TransactionProxyFactoryBean的声明式事务管理
(3)基于 @Transactional 的声明式事务管理
(4)基于Aspectj AOP配置事务

51.Spring单例线程是否安全
spring框架里的bean获取实例的时候都是默认单例模式,所以在多线程开发里就有可能会出现线程不安全的问题。
当多个用户同时请求一个服务器时,容器(tomcat)会给每一个请求分配一个线程,这时多个线程会并发执行该请求所对应的业务逻辑(controller里的方法),此时就要注意啦,如果controller(是单例对象)里有全局变量并且又是可以修改的,那么就需要考虑线程安全的问题。解决方案有很多,比如设置@scope(“prototype”)为多例模式,为每个线程创建一个controller,还可以使用ThreadLocal
52. JDK、JRE、JVM是什么
JDK:Java开发工具包,是整个JAVA开发的核心,包括了JRE,JAVA基本类库和一堆JAVA工具(比如说编译器等等)
JRE:Java运行时环境,包含了JVM和JAVA运行时基本类库
JVM:Java虚拟机,它是Java实现跨平台最核心的部分,所有的java文件被编译成.class文件后,通过JVM进行识别执行
53.Hashmap运行原理
同上(2题)
54. IO与NIO的区别
IO是面向流的,NIO是面向缓冲区的:IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方
IO是阻塞的,NIO是不阻塞的:如果在一次读写数据调用时数据还没有准备好,或者目前不可写,那么读写操作就会被阻塞直到数据准备好或目标可写为止。Java NIO则是非阻塞的,每一次数据读写调用都会立即返回,并将目前可读(或可写)的内容写入缓冲区或者从缓冲区中输出,即使当前没有可用数据,调用仍然会立即返回并且不对缓冲区做任何操作。这就好像去超市买东西,如果超市中没有需要的商品或者数量还不够,那么Java IO会一直等直到超市中需要的商品数量足够了就将所有需要的商品带回来,Java NIO则不同,不论超市中有多少需要的商品,它都会立即买下可以买到的所有需要的商品并返回,甚至是没有需要的商品也会立即返回。
55. 如何实现多线程
1.继承Thread类,重写run()方法
2.实现Runnable接口并实例化一个线程
3.使用ExecutorService、Callable、Future实现有返回结果的多线程
应用场景: 需要让异步执行的线程在执行完成后返回一个值给当前的线程,当前的线程需要依赖这个值做一些其他的业务操作,这个时候就需要实现有返回结果的多线程
56.如何防止死锁
1.设置加锁顺序
如果一个线程需要锁,那么就需要按照锁的顺序来获得锁
比如说,线程1占据着锁A,,线程2和线程3只有在获取锁A后才能获取到锁B(锁A是锁B的必要条件),所以线程2或3需要等待线程A释放锁之后才可以进行加锁操作
缺点:按照顺序加锁是一个很有效的死锁预防机制,但是按序加锁也就意味着需要清楚所有可能用到的锁以及锁之间的先后顺序
2.设置加锁时长
若一个线程在给定的时间内没有成功的获取到所需要的锁,则会进行回退并释放其所占用的的锁,然后等待一段随机的时间后在进行尝试
缺点:有些线程可能需要花很长时间去执行任务而导致了锁的超时,所以并不能确定一定发生了死锁
3.设置死锁检测
当一个线程获取锁后,会对其进行记录,记录在数据结构中,如果有线程对某锁进行请求,也会进行记录。当一个线程请求锁失败后,这个线程会去遍历锁的关系图,如果发现发生了死锁,线程则会进行回退和等待,当然,也有可能发生回退后大量线程抢占同一批锁的情况,继而又发生了死锁,这里可以对线程设置优先级,让部分线程先进行回退操作
57. 消息队列
1.为什么要用消息队列?
解耦:A系统调用B系统、C系统,传统的调用是直接调用,但是当B系统说我不需要你提供数据了,这时候A需要改代码,C系统说我不需要某个字段了,这时候A也要改代码,如果又多了一个D系统,A又要写代码。为了实现解耦,引入消息队列,A将产生的数据丢到消息队列中,哪个系统需要,哪个系统就去取;
异步:A系统调用B系统,B系统由于某个需要调用第三方接口超时,导致A系统响应速度慢,而B系统的好坏又不会影响业务逻辑,所以可以改为A异步调用B,A将消息丢到消息队列中,B系统订阅消息,实现A的快速响应;
削峰:当大量流量请求到系统A时,由于数据库的处理能力有限,造成数据库连接异常。使用消息队列,大量请求先丢到消息队列中,系统A使用按批拉数据的方式,批量处理数据,生产中,高峰期短暂的消息积压是允许的。
2.使用消息队列有什么缺点
系统复杂性增加:需要考虑消息的处理,包括消息幂等性(重复消费问题),消息保序性(一个订单多条消息问题),以及消息中间件本身的持久化和稳定性可靠性
系统的可用性降低:解耦后,多个系统通过消息中间件交互,消息中间件挂了整个系统就挂了
3.各种MQ的比较
ActiveMQ:
优点: 技术成熟,功能齐全,历史悠久,有大量公司在使用
缺点: 偶尔会有较低概率丢失数据,而且社区已经不怎么维护5.15.X版本
适用场景: 主要用于系统解耦和异步处理,不适用与大数据量吞吐情况。互联网公司很少适用
rabitMQ:
优点: 吞吐量高,功能齐全,管理界面易用,社区活跃,性能极好
缺点: 吞吐量只是万级,erlang难以二次开发和掌控;集群动态扩展非常麻烦
适用场景: 吞吐量不高而要求低延迟,并且不会频繁调整和扩展的场景。非常适合国内中小型互联网公司适用,因为管理界面非常友好,可以在界面进行配置和优化/集群监控
rocketMQ
优点: 支持百千级大规模topic。吞吐量高(十万级,日处理上百亿)。接口易用。,分布式易扩展,阿里支持。java开发易于掌控
缺点: 与阿里(社区)存在绑定。不兼容JMS规范
适用场景: 高吞吐量
Kafka
优点: 超高吞吐量,超高可用性和可靠性,分布式易扩展
缺点: topic支持少,MQ功能简单,消息可能会重复消费影响数据精确度
适用场景: 超高吞吐量场景而数据精确度没那么高,天然适合大数据实时计算和日志采集场景
58. 内存溢出
内存溢出的情形:
1.java堆内存溢出: 当出现java.lang.OutOfMemoryError:Java heap space异常时,就是堆内存溢出了
发生场景:1.设置的jvm内存太小,对象所需内存太大,创建对象时分配空间,就会抛出这个异常。2.流量/数据峰值,应用程序自身的处理存在一定的限额,比如一定数量的用户或一定数量的数据。而当用户数量或数据量突然激增并超过预期的阈值时,那么就会峰值停止前正常运行的操作将停止并触发java . lang.OutOfMemoryError:Java堆空间错误
解决方法:首先,如果代码没有什么问题的情况下,可以适当调整-Xms和-Xmx两个jvm参数,使用压力测试来调整这两个参数达到最优值。其次,尽量避免大的对象的申请,像文件上传,大批量从数据库中获取,这是需要避免的,尽量分块或者分批处理,有助于系统的正常稳定的执行。最后,尽量提高一次请求的执行速度,垃圾回收越早越好,否则,大量的并发来了的时候,再来新的请求就无法分配内存了,就容易造成系统的雪崩
2. 垃圾回收超时内存溢出:
发生场景: 当应用程序耗尽所有可用内存时,GC开销限制超过了错误,而GC多次未能清除它,这时便会引发java.lang.OutOfMemoryError。当JVM花费大量的时间执行GC,而收效甚微,而一旦整个GC的过程超过限制便会触发错误(默认的jvm配置GC的时间超过98%,回收堆内存低于2%)
解决方法:减少对象生命周期,尽量能快速的进行垃圾回收
59. ioc与aop
同上(14题)
60. Redis持久化
同上(16题)

61设计模式以及原理?
1、工厂模式:创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。应用实例: 1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。使用场景: 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 3、设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。
2、单例模式:创建型模式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。应用实例:一个班级只有一个班主任。使用场景:1、要求生产唯一序列号。2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等
3、代理模式:结构型模式,在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。应用实例:Windows 里面的快捷方式。使用场景:按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。
4、MVC模式:Model-View-Controller(模型-视图-控制器)模式,这种模式用于应用程序的分层开发,Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器;View(视图) - 视图代表模型包含的数据的可视化;Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
62、分布式?
多台服务器合起来跑的才是一套完整代码,这就叫分布式;多台服务器跑的都是一套完整的代码,这就叫集群
63微服框架?
微服务架构是一种架构模式或者说是一种架构风格,它将单一应用程序划分一组小的服务,每个服务运行在其独立的自己的进程中,服务之间按照一定的方式进行通信。
64、反射机制?
动态获取对象信息和调用对象方法的功能称之为反射机制。
65、Mvc?
MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式,是用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
66、Jdk 1.8新出了什么功能?
1、default关键字
2、Lambda 表达式
3、函数式接口
4、方法与构造函数引用
5、局部变量限制
6、Date Api更新;
7、流
67、垃圾回收机制?
垃圾回收机制是由垃圾收集器Garbage Collection GC来实现的,GC是后台的守护进程。它的特别之处是它是一个低优先级进程,但是可以根据内存的使用情况动态的调整他的优先级。因此,它是在内存中低到一定限度时才会自动运行,从而实现对内存的回收。
68、内连接和左外连接的区别?
内连接:显示两个表中有联系的所有数据;左链接:以左表为参照,显示所有数据,右边表数据数据少了补NULL值,数据多了不显示。
69、Zookeeper原理、作用?
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务。 功能:主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。 原理:Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
70、Dubbo特点和springcloud区别?
SpringCloud和Dubbo都是现在主流的微服务架构,
区别:1、Dubbo是阿里系的分布式服务框架;SpringCloud是Apache旗下的Spring体系下的微服务解决方案;
2、服务的调用方式:Dubbo使用的是RPC远程调用,而SpringCloud使用的是 Rest API; 3、服务的注册中心:Dubbo使用了第三方的ZooKeeper作为其底层的注册中心,SpringCloud使用Eureka实现注册中心
4、服务网关:Dubbo并没有本身的实现,只能通过其他第三方技术的整合,而SpringCloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发;
5、SpringCloud还支持断路器,与git完美集成分布式配置文件支持版本控制,事务总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素

71.如何保证线程安全
1、使用线程安全的类;
2、使用synchronized同步代码块,或者用Lock锁;
3、多线程并发情况下,线程共享的变量改为方法局部级变量;

  1. 内存溢出的原因和解决方法
    原因:
    1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
      2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
      3.代码中存在死循环或循环产生过多重复的对象实体;
      4.使用的第三方软件中的BUG;
      5.启动参数内存值设定的过小;
    解决方法:
    第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
      第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。
      第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。

  2. 单例模式的作用
    1、控制资源的使用,通过线程同步来控制资源的并发访问;
    2、控制实例产生的数量,达到节约资源的目的。
    3、作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。

  3. 数据库优化的方法
    1、选取最适用的字段属性
    2、使用连接(JOIN)来代替子查询(Sub-Queries)
    3、使用联合(UNION)来代替手动创建的临时表
    4、事务
    5、锁定表
    6、使用外键
    7、使用索引
    8、优化的查询语句

  4. hashMap原理
    HashMap是一个散列桶(数组和链表),它存储的内容是键值对(key-value)映射HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改

  5. finally final finaize的区别
    final是修饰符,修饰类、方法和变量,意为不可修改的。当修饰类的时候不可以派生出新的子类,因此一个类的修饰符不可以既是final和abstract;修饰方法的时候该方法不可以被重载;修饰变量的时候需要给变量赋初值,在接下来只能对其读取不可以重新赋值。

finally是在异常处理时提供finally块来执行任何清除操作的,如果try语句中发生了catch块中的异常,则跳转到catch中进行异常处理,而finally中的内容则是无论异常是否发生都要执行的。如果finally中有return,则会先执行finally再执行return,如果此时try中也有return,则try中的return不会执行,但是,如果只有try中有return也是先执行finally中的语句再执行return;

finalize是方法名,在垃圾回收器将对象从内存中清理出去之前做的必要工作。是由垃圾回收器在确定这个对象没有被引用的时候调用的,它是在Object中定义的,子类重写finalize方法整理系统资源或其他清理工作finalize方法是在垃圾收集器删除对象之前调用的。

  1. 连接池的作用是什么?
    连接池是将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对数据库进行访问。这样省略了创建连接和销毁连接的过程。这样性能上得到了提高。

  2. 什么是 JAVA 事务?
    事务是作为一个逻辑单元执行的一系列操作,一个逻辑工作单元必须有四个属性,称为 ACID(原子性、一致性、隔离性和持久性)属性,只有这样才能成为一个事务。

  3. 主键索引和普通索引的区别
    普通索引是最基本的索引类型,没有任何限制,值可以为空,仅加速查询。普通索引是可以重复的,一个表中可以有多个普通索引。
    主键索引是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值;索引列的所有值都只能出现一次,即必须唯一。简单来说:主键索引是加速查询 + 列值唯一(不可以有null)+ 表中只有一个。

  4. springmvc工作流程
    用户发送url请求 ,前端通过action 里面的映射地址 实现跳转到后端控制器Controller ,执行完成后返回modelandview 传入视图解析器中,返回view ,把view进行渲染,相应给用户

81.wait与sleep的区别

1、wait()方法属于Object类,sleep()属于Thread类;
2、wait()方法释放cpu给其他线程,自己让出资源进入等待池等待;sleep占用cpu,不让出资源;
3、sleep()必须指定时间,wait()可以指定时间也可以不指定;sleep()时间到,线程处于临时阻塞或运行状态;
4、wait()方法会释放持有的锁,不然其他线程不能进入同步方法或同步块,从而不能调用notify(),notifyAll()方法来唤醒线程,产生死锁,所以释放锁,可以执行其他线程,也可以唤醒自己,只是设置停止自己的时间时不确定的;sleep方法不会释放持有的锁,设置sleep的时间是确定的会按时执行的;
5、wait()方法只能在同步方法或同步代码块中调用,否则会报illegalMonitorStateException异常,如果没有设定时间,使用notify()来唤醒;而sleep()能在任何地方调用;

82.mysql执行计划
执行计划,简单的来说,是SQL在数据库中执行时的表现情况,通常用于SQL性能分析,优化等场景。在MySQL中使用 explain 关键字来查看。如下所示:
explain select*fromtablewheretable.id =1
运行上面的sql语句后你会看到,下面的表头信息:
table | type | possible_keys | key | key_len | ref | rows | Extra
解释下表头各列的意义。
Table:显示这一行的数据是关于哪张表的
Type:这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、index和ALL
不同连接类型的解释(按照效率高低的顺序排序):
system:表只有一行:system表。这是const连接类型的特殊情况。
const :表中的一个记录的最大值能够匹配这个查询(索引可以是主键或惟一索引)。因为只有一行,这个值实际就是常数,因为MYSQL先读这个值然后把它当做常数来对待。
eq_ref:在连接中,MYSQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或惟一键的全部时使用。
ref:这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好。
range:这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况。
index:这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)。
ALL:这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免。
possible_keys:显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句
key:实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引
key_len:使用的索引的长度。在不损失精确性的情况下,长度越短越好
ref:显示索引的哪一列被使用了,如果可能的话,是一个常数
rows:MYSQL认为必须检查的用来返回请求数据的行数
Extra:关于MYSQL如何解析查询的额外信息。举例返回值如:Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢
以下为extra列返回的一些值和其意义:
Distinct :一旦mysql找到了与行相联合匹配的行,就不再搜索了。
Notexists :mysql优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了。
RangecheckedforeachRecord(index map:#) :没有找到理想的索引,因此对从前面表中来的每一个行组合,mysql检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一。
Usingfilesort:看到这个的时候,查询就需要优化了。mysql需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行。
Usingindex :列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候。
Usingtemporary :看到这个的时候,查询需要优化了。这里,mysql需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上。
Whereused :使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题。

83.sql优化
1、注意通配符中Like的使用,以下写法会造成全表的扫描
2、避免在where子句中对字段进行函数操作
3、在子查询当中,尽量用exists代替in
4、where子句中尽量不要使用is null 或 is not null对字段进行判断,尽量在数据库字段中不出现null,如果查询的时候条件为 is null ,索引将不会被使用,造成查询效率低,因此数据库在设计的时候,尽可能将某个字段可能为空的时候设置默认值,那么查询的时候可以根据默认值进行查询,比如空字段设置为0
5、避免在where子句使用or作为链接条件
6、避免在 where 子句中使用 != 或 <> 操作符。
7、少用in 或 not in,对于连续的数值范围查询尽量使用BETWEEN AND

84.spring注入方式
1.构造器注入
2.setter注入
3.接口注入
构造器注入和setter注入是依赖注入的两种主要方式,接口注入是指从别的地方注入的方式。(通过在xml中描述,实现注入)

85.redis优点
Redis的特点:
• 内存数据库,速度快,也支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
• Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
• Redis支持数据的备份,即master-slave模式的数据备份。
• 支持事务
Redis的优势:
• 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
• 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
• 原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。(事务)
• 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

86.spring事务管理有几种
spring支持编程式事务管理和声明式事务管理两种方式:
①编程式事务管理使用TransactionTemplate。
②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。
声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

87.spring单例线程是否安全
在Spring中单例bean是在beanfactory中用反射机制动态创建的,被缓存到ioc容器中相对于new了一个对象。而这些创建的对象class,则是自己创建的。
所以是不是线程安全和Spring本身无关,和自己创建的类有关。
自己创建的是安全的那就是安全的,自己创建的不是安全的那就不是安全的。

88.除了SSM还用过什么框架
十大常用框架:一、SpringMVC。二、Spring三、Mybatis。四、Dubbo。五、Maven。六、RabbitMQ。七、Log4j。八、Ehcache。九、Redis。十、Shiro。
什么会说什么,不会不要说

89.spring核心库,功能
Spring三大核心功能
1、IOC(DI) IOC:Inversion of Control,DI:Dependency Injection
2、AOP:Aspect Oriented Programming
3、声明式事务

90.springIOC和AOP原理
IoC(Inversion of Control)
(1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系;IoC还有另外一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。
(2). 在Spring的工作方式中,所有的类都会在spring容器中登记,告诉spring这是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
(3). 在系统运行中,动态的向某个对象提供它所需要的其他对象。
(4). 依赖注入的思想是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。 总而言之,在传统的对象创建方式中,通常由调用者来创建被调用者的实例,而在Spring中创建被调用者的工作由Spring来完成,然后注入调用者,即所谓的依赖注入or控制反转。 注入方式有两种:依赖注入和设置注入; IoC的优点:降低了组件之间的耦合,降低了业务对象之间替换的复杂性,使之能够灵活的管理对象。
AOP(Aspect Oriented Programming)
(1). AOP面向方面编程基于IoC,是对OOP的有益补充;
(2). AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了 多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的 逻辑或责任封装起来,比如日志记录,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
(3). AOP代表的是一个横向的关 系,将“对象”比作一个空心的圆柱体,其中封装的是对象的属性和行为;则面向方面编程的方法,就是将这个圆柱体以切面形式剖开,选择性的提供业务逻辑。而 剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹,但完成了效果。
(4). 实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
(5). Spring实现AOP:JDK动态代理和CGLIB代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。 CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;需要引入包asm.jar和cglib.jar。 使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是通过动态代理实现的

91自己写会怎么写IOC,AOP
IOC:准备配置文件、由IOC容器进行解析元数据、实例化IOC容器
AOP:一是采用动态代理技术,二是采用静态织入的方式

92spring怎么注入
常用的有构造方法注入、setter注入、基于注解的注入

93在二班的课程大于3个的学生
SELECT name from student WHERE class=2 GROUP BY name HAVING count(lesson)>3

94在开发过程中遇到过对框架技术问题怎么解决
百度、论坛、翻墙谷歌

95对未来3年规则
未来三年主要以积累开发经验为主,后期会考虑往管理或架构师方向发展;

96对产品是否了解
?????

97加班出差怎么看
尽量优先满足公司的需求

98有没有需要问我们
从公司目前的项目,使用的技术方面切入

99解码格式
GBK、UTF-8
100接口
是一个抽象类型,是抽象方法的集合,通常以interface来声明。一个类通过集成接口的方式,从而来继承接口的抽象方法。

  1. 数据类型不匹配
    能强转的强转,不能强转的改成匹配的,

  2. 引用类型: 返回二进制名称。(java.lang.string,java.lang.Integer)

  3. 基本类型或void: 返回对应Java关键字相同的String。(int,void)

  4. 数组类型:返回’[‘字符加元素类型名,多维数组则多个’['字符;元素类型名对应如下;([B,[Ljava.lang.String)
    Element Type Encoding
    boolean Z
    byte B
    char C
    class or interface Lclassname;
    double D
    float F
    int I
    long J
    short S

  5. spring整个请求流程

  6. servlet的生命周期
    (1)init()方法:服务器初始化servlet。
    (2)service()方法:初始化完毕,servlet对象调用该方法响应客户的请求。
    (3)destroy()方法:调用该方法消灭servlet对象。
    其中,init()方法只在servlet第一次被请求加载的时候被调用一次,当有客户再请求servlet服务时,web服务器将启动一个新的线程,在该线程中,调用service方法响应客户的请求。

  7. 别人调用接口时中文乱码解决方式
    了解双方的字符编码格式,然后字符串打散,按照新的编码格式重新组合
    比如A的接口编码格式是UTF-8,B应用的编码格式是ISO-8859-1,B调用A的接口,先将字符串按UTF-8格式打散,再按ISO-8859-1格式重新组合,这样就b接收到的数据就不会乱码了

  8. web.xml的作用
    web.xml文件是用来初始化配置信息, 一个web中可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的。
    web.xml常用的一些标签元素及其功能:
    1、 指定欢迎页面
    2、 命名与定制URL。
    3、 定制初始化参数:可以定制servlet、JSP、Context的初始化参数,然后可以再servlet、JSP、Context中获取这些参数值。
    4、 指定错误处理页面,可以通过“异常类型”或“错误码”来指定错误处理页面
    5、 设置过滤器:比如设置一个编码过滤器,过滤所有资源
    6、 设置监听器
    7、 设置会话(Session)过期时间,其中时间以分钟为单位

  9. double和float的区别
    这两种都是浮点类型数据,double 和 float 的区别是double精度高,有效数字 16位,float精度7位。float数据占用32bit,double数据占用64bit,double消耗内存是float的两倍,double的运算速度比float慢得多

  10. ArrayList使用时有什么注意事项
    集合的元素的类型不能是基本数据类型,只能是引用数据类型。

  11. ArrayList和LinkedList区别
    ArrayList:
    0.ArrayList默认的初始缓冲空间是10个
    1.ArrayList的底层的数据结构采用的数组结构。(结构)
    2.存储数据的顺序和取出数据的顺序是一致的。(读写性质)
    3.ArrayList在处理读取和添加数据的效率非常高。(强项)
    4.ArrayList在执行插入和删除的操作时效率比较低,因为底层实现采用的 (弱项)是数组结构,所有每删除个元素n 则n元素之后的元素的下标都会向前移动一次。
    使用注意事项:
    集合的元素的类型不能是基本数据类型,只能是引用数据类型。

LinkedList:
0.LinkedList默认的初始缓冲空间是0个	
1.LinkedList的底层的数据结构采用的是链表结构。
2.LinkedList插入和删除效率比较高,因为删除元素值,只需要修改当前删除元素的前一个指针指向当前删除元素的下一个元素。
3.读取的效率相对于ArrayList比较低。
  1. 多态怎么实现
    实现多态的步骤:子类继承父类或实现某接口,父类引用指向子类对象。
  2. 重写注意点,怎么看调用的是父类还是子类,权限要求
    重写是在子类中出现和父类同名的方法。
    1.子类重写父类方法的方法范围必须大于等于父类类型,但是不能是private类型。
    2.父类私有的方法是不能被子类重写。
    3.子类中的同名方法除了范围修饰符不同,其他的都必须相同。
    111重载的返回值要求
  3. 重载与返回值无关;2.只有返回值类型不同的方法,不构成重载

112对redis的理解
简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以存写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
优势:
1.速度快:因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1),每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。
2.支持丰富数据类型:支持string,list,set,sorted set,hash
3.单个value的最大限制是1GB,不像 memcached只能保存1MB的数据
4.支持事务:操作不是原子性的,即使某些操作失败,也不会影响别的操作的执行
5.丰富的特性:可用于缓存,按key设置过期时间,过期后将会自动删除

113使用spring的好处

  1.  轻量级框架 
    

Spring是轻量级框架,基本的版本大约2M

  1.  控制反转   
    

Spring通过控制反转实现松散耦合,对象们给它们的依赖,而不是创建或者查找依赖的对象们 方便解耦,简化开发

  1.  面相切面的编程 AOP
    

Spring支持面相切面的编程,并且把应用业务逻辑和系统分开

  1.  容器 
    

Spring 包含并管理应用中对象的生命周期和配置

  1.  MVC框架 
    

Spring的WEB框架是个精心设计的框架,是WEB框架的一个很好的替代品

  1.  事务管理 
    

Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)

  1.  异常处理 
    

Spring 提供方便的API把具体技术的相关异常(比如由JDBC Hibernate or JDO 抛出的) 转化为一致的 unchecked异常

114数据库调用
1.加载(注册)数据库
2.建立链接
3.执行SQL语句
4.处理结果集
5.关闭数据库

115mybatis中的#和 的 区 别 , 的区别, ,的应用场景
应用场景:
#{ } :#代表占位符,用来传递参数;
: { } : 用来拼接sql 语句的;
区别:
1、#是预编译的方式,KaTeX parse error: Expected 'EOF', got '#' at position 10: 是直接拼接; 2、#̲不需要关注数据类型,mybat…不做数据类型转换,需要自行判断数据类型;
3、#可以防止sql注入;KaTeX parse error: Expected 'EOF', got '#' at position 44: …e 只有一个参数,默认情况下,#̲{ }中可以写任意的名字;{ }中只能用value来接收。

116接口和抽象类的区别和各自的应用场景
相同点:1.都不能被实例化2.都可以定义抽象方法

不同点:1.抽象类是一种类只能单继承 接口可以多实现抽象;2.接口只能有抽象方法,抽象类可以有非抽象方法;
3.抽象类中可以有普通变量 接口中的变量都是由final修饰的
4.抽象类可以有构造器和主方法(抽象类中的构造器主要是在子类的构造方法中调用 负责初始化抽象类中的参数) 接口中不可以有构造器和主方法
5.抽象类中的方法普通可以由public private protected 和默认修饰 抽象方法可以由 public protected(或者不加修饰符)修饰 抽象方法必须由abstract修饰 接口方法默认由public修饰 接口中的抽象方法只能由public修饰 default在接口中只能修饰带有方法体的方法

使用场景:
当需要一些默认的方法实现时需要使用抽象类
当需要多继承时使用接口
当需要不断增加基础功能的时候使用抽象类 当使用接口时 增加功能就需要修改每个实现了该接口的实现类

117solr怎么建立索引
1.启动数据数据库
2.在solr中配置数据源
3.启动tomcat,建立索引
4.登录solr控制台检测索引

  1. 基础

  2. 面对对象的三大特性,五大原则
    三大基本特性:封装,继承,多态
    封装,就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
    继承,指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过 “继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用 基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。
    多态,是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
    五大基本原则:SPR, OCP, LSP, DIP, ISP
    单一职责原则SRP(dSingle Responsibility Principle)
    开放封闭原则OCP(Open-Close Principle)
    里式替换原则LSP(the Liskov Substitution Principle LSP)
    依赖倒置原则DIP(the Dependency Inversion Principle DIP)
    接口分离原则ISP(the Interface Segregation Principle ISP)

  3. 创建类的方法:
    1.用new语句创建对象,这是最常用的创建对象的方式。
    2.运用反射手段,调用Java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
    3.调用对象的clone()方法。
    4.运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法.

  4. ==与equals的区别
    ==是指对内存地址进行比较 , equals()是对字符串的内容进行比较

  5. &与&&的区别
    &和&&都是双边为对才对,但是&&单边错误,另一边就不判断了直接错误。

  6. 设计模式
    工厂模式:spring的IOC容器就是一个大的Bean实列的工厂,复制Bean的周期管理
    单列模式:和spring的IOC 是一起的,既然IOC是一个大工程,那么Bean对象为了减少内存开销就需要提供单列特征。
    代理模式:为其他对象提供一种代理访问的机制
    观察者模式:当对象发生变化时,则会通知他的依赖对象,属于行为型模式
    MVC模式:Model-View-Controller(模型-视图-控制器)模式,这种模式用于应用程序的分层开发,Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。

  7. 排序方法
    冒泡排序、快速排序、插入排序、选择排序

  8. JDK、JRE、JVM是什么
    JDK:Java开发工具包,是整个JAVA开发的核心,包括了JRE,JAVA基本类库和一堆JAVA工具(比如说编译器等等)
    JRE:Java运行时环境,包含了JVM和JAVA运行时基本类库
    JVM:Java虚拟机,它是Java实现跨平台最核心的部分,所有的java文件被编译成.class文件后,通过JVM进行识别执行

8.HTTP和TCP
TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。
HTTP:超文本传输协议,是应用层的协议,以TCP为基础
TCP:传输控制协议,是传输层的协议,以IP协议为基础

9.Gc(垃圾回收机制)的四种算法
及时清除不再使用的对象,将内存清理出来,
①引用计数法:
②标记清除法:
为每个对象存储一个标记位,记录对象的状态(活着或者死亡),死亡则进行清除
③标记压缩法:
是标记清楚法的改进版,该算法不会对死亡的对象直接清理,而是将所有存活的对 象整理一下,放到另一个空间,然后把剩下的对象全部清除
优点: 该算法不会产生大量的碎片空间
缺点: 如果存活对象过多,整理阶段将会执行过多的复制操作,导致算法效率
④复制算法:
将内存评分分成两部分,然后每次只使用其中一部分,当这部分内存满的时候,将 内存中存活的对象复制到另一个内存中,然后将之前的内存清空,只使用这部分内 存,循环下去。

2.数据

  1. 八大基础类型:
    byte(字节) 1bit (8位) 、shot(短整型) 2bit (16位)、int(整型) 4bit (32位)、long(长整型) 8bit (64位)、float(浮点型) 4bit (32位)、double(双精度) 8bit (64位)、char(字符型) 2bit (16位)、boolean(布尔型) 1位
  2. 集合
    Connection接口:
    — List 有序,可重复
    ArrayList
    优点: 底层数据结构是数组,查询快,增删慢。
    缺点: 线程不安全,效率高
    Vector
    优点: 底层数据结构是数组,查询快,增删慢。
    缺点: 线程安全,效率低
    LinkedList
    优点: 底层数据结构是链表,查询慢,增删快。
    缺点: 线程不安全,效率高
    —Set 无序,唯一
    HashSet
    底层数据结构是哈希表。(无序,唯一)
    如何来保证元素唯一性?
    1.依赖两个方法:hashCode()和equals()
    LinkedHashSet
    底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
    1.由链表保证元素有序
    2.由哈希表保证元素唯一
    TreeSet
    底层数据结构是红黑树。(唯一,有序)
  3. 如何保证元素排序的呢?
    自然排序
    比较器排序
    2.如何保证元素唯一性的呢?
    根据比较的返回值是否是0来决定
    Map接口有三个比较重要的实现类,分别是HashMap、TreeMap和HashTable。

TreeMap是有序的,HashMap和HashTable是无序的。
Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。
这就意味着:
Hashtable是线程安全的,HashMap不是线程安全的。
HashMap效率较高,Hashtable效率较低。
如果对同步性或与遗留代码的兼容性没有任何要求,建议使用HashMap。 查看Hashtable的源代码就可以发现,除构造函数外,Hashtable的所有 public 方法声明中都有 synchronized关键字,而HashMap的源码中则没有。
Hashtable不允许null值,HashMap允许null值(key和value都允许)
父类不同:Hashtable的父类是Dictionary,HashMap的父类是AbstractMap
3多线程

  1. 线程池的工作原理
    先启动若干数量的线程,并让这些线程都处于睡眠状态,当客户端有一个新请求时,就会唤醒线程池中的某一个睡眠线程,让它来处理客户端的这个请求,当处理完这个请求后,线程又处于睡眠状态

  2. 多线程中安全集合:
    线程安全(Thread-safe)的集合对象:
    Vector 线程安全:
    HashTable 线程安全:
    StringBuffer 线程安全:

  3. 锁的类型
    重量级锁
    内置锁在Java中被抽象为监视器锁(monitor)。在JDK 1.6之前,监视器锁可以认为直接对应底层操作系统中的互斥量(mutex)。这种同步方式的成本非常高,包括系统调用引起的内核态与用户态切换、线程阻塞造成的线程切换等。因此,后来称这种锁为“重量级锁”。
    偏向锁
    是一种编译解释锁。如果代码中不可能出现多线程兵法争抢同一个锁的时候,JVM编译代码,解释执行的时候,会自动放弃同步信息。消除synchronized的同步代码结果。使用锁标记的形式记录锁状态。再Monitor中有变量ACC_SYNCHRONIZED。当变量值使用的时候,代表偏向锁锁定。可以避免锁的争抢和锁池状态的维护,提高效率。
    轻量级锁
    过度锁。当偏向锁不满足,也就是有多线程并发访问,锁定同一个对象的时候,先提升为轻量级锁。也是使用标记ACC_SYNCHRONIZED标记记录的。ACC_UNSYNCHRONIZED标记记录未获取到锁信息的线程。就是只有两个线程争抢锁标记的时候,优先使用轻量级锁。
    两个线程也可能出现重量级锁。
    自旋锁
    是一个过渡锁,是偏向锁和轻量级锁的过渡。
    当获取锁的过程中,未获取到。为了提高效率,JVM自动执行若干次空循环,在次申请锁,而不是进入阻塞状态的情况。称为自旋锁。

  4. 悲观锁和乐观锁:
    悲观锁:总是假设最坏的情况发生,因此每次在取数据的时候就会加锁,操作完成后才释放锁。
    乐观锁:假设大数据情况下不会发生数据冲突,因此在取数据的时候不加锁,只有在更新的时候判断该数据在此期间释放被修改过.实现机制是CAS。

  5. 线程的生命周期
    New(初始化状态)
    Runnable(可运行/运行状态)
    Blocked(阻塞状态)
    Waiting(无时间限制的等待状态)
    Timed_Waiting(有时间限制的等待状态)
    Terminated(终止状态)

  6. 实现多线程方法
    1.继承Thread类,重写run()方法
    2.实现Runnable接口并实例化一个线程
    3.使用ExecutorService、Callable、Future实现有返回结果的多线程
    7.如何防止死锁
    1.设置加锁顺序
    如果一个线程需要锁,那么就需要按照锁的顺序来获得锁。比如说,线程1占据着锁A,,线程2和线程3只有在获取锁A后才能获取到锁B(锁A是锁B的必要条件),所以线程2或3需要等待线程A释放锁之后才可以进行加锁操作
    缺点:按照顺序加锁是一个很有效的死锁预防机制,但是按序加锁也就意味着需要清楚所有可能用到的锁以及锁之间的先后顺序
    2.设置加锁时长
    若一个线程在给定的时间内没有成功的获取到所需要的锁,则会进行回退并释放其所占用的的锁,然后等待一段随机的时间后在进行尝试
    缺点:有些线程可能需要花很长时间去执行任务而导致了锁的超时,所以并不能确定一定发生了死锁
    3.设置死锁检测
    当一个线程获取锁后,会对其进行记录,记录在数据结构中,如果有线程对某锁进行请求,也会进行记录。当一个线程请求锁失败后,这个线程会去遍历锁的关系图,如果发现发生了死锁,线程则会进行回退和等待,当然,也有可能发生回退后大量线程抢占同一批锁的情况,继而又发生了死锁,这里可以对线程设置优先级,让部分线程先进行回退操作

  7. 线程安全
    线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
    线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

4.Spring

  1. Spring的工作原理
    (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系;IoC还有另外一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。
    (2). 在Spring的工作方式中,所有的类都会在spring容器中登记,告诉spring这是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
    (3). 在系统运行中,动态的向某个对象提供它所需要的其他对象。
    (4). 依赖注入的思想是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。 总而言之,在传统的对象创建方式中,通常由调用者来创建被调用者的实例,而在Spring中创建被调用者的工作由Spring来完成,然后注入调用者,即所谓的依赖注入or控制反转。 注入方式有两种:依赖注入和设置注入; IoC的优点:降低了组件之间的耦合,降低了业务对象之间替换的复杂性,使之能够灵活的管理对象。
    AOP(Aspect Oriented Programming)
    (1). AOP面向方面编程基于IoC,是对OOP的有益补充;
    (2). AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了 多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的 逻辑或责任封装起来,比如日志记录,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
    (3). AOP代表的是一个横向的关 系,将“对象”比作一个空心的圆柱体,其中封装的是对象的属性和行为;则面向方面编程的方法,就是将这个圆柱体以切面形式剖开,选择性的提供业务逻辑。而 剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹,但完成了效果。
    (4). 实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
    (5). Spring实现AOP:JDK动态代理和CGLIB代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。 CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;需要引入包asm.jar和cglib.jar。 使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是通过动态代理实现的
    IOC:准备配置文件、由IOC容器进行解析元数据、实例化IOC容器
    AOP:一是采用动态代理技术,二是采用静态织入的方式

  2. Spring的注入方式
    构造器注入
    构造器注入依赖于构造方法的实现,构造方法可以是有参数的,也可以是无参数的 。
    setter注入
    setter注入利用JAVA Bean规范所定 首先将构造方法设置为无参的构造方法,然后利用setter注入为其设置新的值,这是通过java的反射技术得以实现的
    接口注入
    有时候资源并非来自于自身的系统,而是来自于外界,比如说数据库连接资源完全可以在Tomcat下配置,然后通过JNDI的方式去获取它,这样的数据库连接资源就属于开发工程外的资源。

  3. Spring的事务管理
    1.编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
    2.基于 TransactionProxyFactoryBean的声明式事务管理
    3.基于 @Transactional 的声明式事务管理
    4.基于Aspectj AOP配置事务

  4. Spring单例线程是否安全
    spring框架里的bean获取实例的时候都是默认单例模式,所以在多线程开发里就有可能会出现线程不安全的问题。当多个用户同时请求一个服务器时,容器(tomcat)会给每一个请求分配一个线程,这时多个线程会并发执行该请求所对应的业务逻辑(controller里的方法),此时就要注意啦,如果controller(是单例对象)里有全局变量并且又是可以修改的,那么就需要考虑线程安全的问题。解决方案有很多,比如设置@scope(“prototype”)为多例模式,为每个线程创建一个controller,还可以使用ThreadLocal。

  5. Spring请求过程

  6. Spring的优缺点
    优点:
    有了IOC容器,对象间依赖关系交给spring,更专注业务逻辑代码。
    有了AOP对应OOP,很多功能更方便简单使用
    像一个胶水一样,把一些好的框架粘合在一起方便实用(数据方面使用MyBatis,controller选择struts2,直接用spring粘在一起使用。)
    缺点:
    对比新出的springboot,肯定没人家好用(这是知乎的一个解释,觉得有道理)
    spring像一个胶水,将框架黏在一起,后面拆分的话就不容易拆分了(这是面试官的一个回答解释,表示是一个思路。)
    springJSP代码过多,过于灵活缺乏一个公用的控制器,不适合分布式(这个是CSDN上几个博客说的,不知道谁抄谁的,前半部分不说,后面的分布式你知道spring boot ,spring cloud吗,这都是什么时候的事了。)
    5.Springmvc
    1.Springmvc的工作原理
    1.用户发送请求给点的控制器DispatcherServlet
    2.DispatcherServlet接收到用户请求后,通过HandlerMapping处理器映射器寻找合理的处理器进行处理
    3.处理器映射器找到具体的处理器后,生成处理器对象以及处理器拦截器,并返回给前端控制器
    4.前端控制器调用处理器适配器,将请求交给处理器处理
    5.处理器适配器调用具体的处理器对请求进行处理
    6.处理器处理完成后放回ModelAndView
    7.处理器适配器将放回的ModelAndView返回给前端控制器
    8.前端控制器将ModelAndView交给视图解析器进行解析
    9.视图解析器解析之后返回具体的View
    10.前端控制器根据具体的View进行渲染
    11.前端控制器响应用户请求

6.mybatis
1.mybatis中#和$区别,以及应用场景
应用场景:
#{ } :#代表占位符,用来传递参数;
: { } : 用来拼接sql 语句的;
区别:
1、#是预编译的方式,KaTeX parse error: Expected 'EOF', got '#' at position 10: 是直接拼接; 2、#̲不需要关注数据类型,mybat…不做数据类
型转换,需要自行判断数据类型;
3、#可以防止sql注入;KaTeX parse error: Expected 'EOF', got '#' at position 44: …e 只有一个参数,默认情况下,#̲{ }中可以写任意 的名字;{ }中只能用value来接收。

  1. mybatis的标签

https://blog.csdn.net/weixin_40950778/article/details/78655288
7.springboot
1.springboot常用的注解
@Service: 注解在类上,表示这是一个业务层bean
@Controller:注解在类上,表示这是一个控制层bean
@Repository: 注解在类上,表示这是一个数据访问层bean
@Component: 注解在类上,表示通用bean ,value不写默认就是类名首字母小写
@Autowired:按类型注入
@Resource: 按名称装配
@Configuration:注解在类上,表示这是一个IOC容器,
@Bean: 注解在方法上,声明当前方法返回一个Bean
@Scope:注解在类上,描述spring容器如何创建Bean实例。
@Value:注解在变量上,从配置文件中读取。
@ConfigurationProperties: 赋值,将注解转换成对象。
@EnableAutoConfiguration启用 Spring 应用程序上下文的自动配置,试图猜测和配置您可能需要的bean。
@SpringBootApplication=@ComponentScan+@Configuration+@EnableAutoConfiguration:约定优于配置
@ComponentScan:注解在类上,扫描标注了@Controller等注解的类,注册 为bean 。
@RestController @RestController 是一个结合了 @ResponseBody 和 @Controller 的注解
@Responsebody:表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上@Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。
@PathVariable、@RequestParam:两者的作用都是将request里的参数的值绑定到contorl里的方法参数里的,区别在于,URL写法不同。
@EnablCaching:pring framework中的注解驱动的缓存管理功能。
@suppresswarnings: 抑制警告
@Modifying :增,改,删加注解

  1. springboot的优缺点
    优点:
    快速构建项目、对主流开发框架的无配置集成、项目可独立运行,无须外部依赖Servlet容器、提供运行时的应用监控、极大地提高了开发效率,部署效率、
    与云计算的天然集成、使编码,配置,部署,监控变得更简单。
    缺点:
    集成度较高,使用过程中不太容易了解底层、因为不要自己做配置,项目有的时候会报错,不容易解决
    8.redis
    1.redis的数据类型还有应用场景
    String:string 类型进行数据存储的时候主要有get,set,incr(increase加一递增),decr(decrease减一递减)等操作。incr等指令本身具有原子操作,所以我们可以利用redis的incr,incrby,decr,decrby来实现原子计数操作。例如:在某场景下面有三个用户同事访问,然后对其进行加一操作,那么最后的值一定会加三。可以利用这一特性来实现业务上的统计数据的需求。
    Llists:redis的list底层不是数组,而是链表。lists常用的操作有lpush(左边插入),rpush(右边插入),lrange(取数据,lranger key 开始下标 结束下标)。每往lists中插入一条数据,这条数据将作为下标为0的数据。栈后进先出的那种形式。
    例如:我们可以利用list来实现一个消息队列,而且可以确保先后顺序,可以利用lrange来实现分页功能。在博客系统中,每篇博文的评论都可以放在单独一个list中。
    set:reids的集合,是一种无序的集合,集合中的元素没有先后顺序。集合中相关的操作也很丰富,如添加元素,删除已有元素,取交集,取并集,取差集。
      例如:QQ有一个社交功能叫“好友标签”,大家可以给你的好友贴标签,这时候就可以用redis集合来实现,把用户的每个集合存在一个集合中。如果要查看共同好友,也可以把好友存在集合中,比较交集。
    zset: redis的有序集合,每个集合都提供了一个序号,赭石排序的依据。
    hash:hashes存的是字符串和字符串之间的映射,比如一个用户要存储其全名,姓氏,年龄等,就适合用hash。hash比较像map。

2.redis的持久化
ROB:在指定的时间间隔能对你的数据进行快照存储
AOF:记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据
用一句话可以将持久化概括为:将数据(如内存中的对象)保存到可永久保存的存储设备中。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、 XML 数据文件中等等
为什么要做持久化:因为redis的数据是缓存在内存中的,当你重启或者关闭系统后,缓存在内存中的数据就会消失殆尽,再也找不回来,所以,为了能让数据长期保存,就一号将Redis缓存在内存中的数据做持久化成操作。
怎么实现持久化:
1、RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。
2、AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。
3、如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化。
4、你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

  1. redis的优点
    速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
    支持丰富数据类型,支持string,list,set,sorted set,hash
    支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
    丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

  2. redis哨兵模式
    哨兵是redis集群架构中非常重要的一个组件,主要功能如下:
    集群监控:负责监控redis master和slave进程是否正常工作
    消息通知:如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
    故障转移:如果master node挂掉了,会自动转移到slave node上
    配置中心:如果故障转移发生了,通知client客户端新的master地址
    哨兵的核心知识
    故障转移时,判断一个master node是宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题。哨兵至少需要3个实例,来保证自己的健壮性。哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性

9.solr
1.solr的数据知识点

2.solr和其他的区别

ElasticSearch vs Solr 总结
(1)es基本是开箱即用,非常简单。Solr安装略微复杂一丢丢
(2)Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能。
  (3)Solr 支持更多格式的数据,比如JSON、XML、CSV,而 Elasticsearch 仅支持json文件格式。
  (4)Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kibana友好支撑
  (5)Solr 查询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用;ES建立索引快(即查询慢),即实时性查询快,用于facebook新浪等搜索。Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用。
  (6)Solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而 Elasticsearch相对开发维护者较少,更新太快,学习使用成本较高。
https://www.cnblogs.com/blueskyli/p/8326229.html

3.solr怎么建立索引
在schema.xml中,配置标签《field》,建立索引名,并且其中 indexed=“true” 这个属性,就代表建立了索引。
10.dubbo
1.dubbo的特点和springcloud的区别
SpringCloud和Dubbo都是现在主流的微服务架构,
区别:1、Dubbo是阿里系的分布式服务框架;SpringCloud是Apache旗下的Spring体系下的微服务解决方案;
3、服务的调用方式:Dubbo使用的是RPC远程调用,而SpringCloud使用的是 Rest API;
3、服务的注册中心:Dubbo使用了第三方的ZooKeeper作为其底层的注册中心,SpringCloud使用Eureka实现注册中心
5、服务网关:Dubbo并没有本身的实现,只能通过其他第三方技术的整合,而SpringCloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发;
5、SpringCloud还支持断路器,与git完美集成分布式配置文件支持版本控制,事务总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素

2.dubbo用户信息怎么获得

用dubbox搭建的微服各模块注册信息从zookeeper注册中心获取,
用springcloud搭建的微服各模块注册信息从eureka注册中心获取。

11.nginx
1.nginx的作用
nginx 是轻量级的Web服务器。由于配置简单,容量小被应用于各个项目。在java企业级开发中,常常作为前端静态资源的代理的服务器,如果配置的好可支持5W并发量。作用:反向代理、正向代理、负载均衡、HTTP服务器(包含动静分离)
区别及意义:
正向代理,代理介于 client 与 service 之间, client 通过proxy 去访问service 返回资源 (代理客户端) 想象你挂VPN的代理并设置一些东西就可以通过某台机器翻墙了。
反响代理:proxyService代理service,client 不知道service 的存在,将访问service 全全交给了proxyService (代理原始服务器)
理解:nginx代理服务器这样你就不用去编写任何配置,交给nginx 去配置就好了,nginx收到你的请求会自动根据配置转发到对应的服务器去。
均衡负载:(多用于服务器集群)其实和ZUUL比较像
均衡负载表示通过代理服务器统一去管理其他服务器,然后client 访问代理服务器(proxyService),proxyService去均衡的分发请给个其他服务器,保证每个服务器得到均衡的并发。nginx 通过反向代理实现均衡负载。实现均衡负载的处理方式:
round-robin:轮询。以轮询方式将请求分配到不同服务器上
least-connected:最少连接数。将下一个请求分配到连接数最少的那台服务器上
ip-hash :基于客户端的IP地址。散列函数被用于确定下一个请求分配到哪台服务器
动静分离:Nginx提供的动静分离是指把动态请求和静态请求分离开,合适的服务器处理相应的请求,使整个服务器系统的性能、效率更高。
Nginx可以根据配置对不同的请求做不同转发,这是动态分离的基础。静态请求对应的静态资源可以直接放在Nginx上做缓冲,更好的做法是放在相应的缓冲服务器上。动态请求由相应的后端服务器处理。
12.mysql
1.mysql数据库的存储结构、数据库锁
Mysql底层用是B树结构,mysql的数据是放到外部存储的,因此我们必须减低磁盘的IO次数,因此我们需要尽量降低树的高度,树的分叉越多越好,因此B树正好符合我们的要求。
数据库锁:共享锁(S锁)、排它锁(X锁)。共享锁只和自身兼容,排它锁都不兼容。
2.mysql语句优化
1.框架自带的模型查询比原生的sql要慢
2.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描
3.in 和 not in 也要慎用,否则会导致全表扫描
4.对于连续的数值,能用 between 就不要用 in ;
5.count优化:
6.%abc%的查询将导致全表扫描
7.sql子句中尽量不要进行函数操作,表达式操作
8.尽可能的使用 varchar 代替 char,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
9.尽量不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库,对于varchar 字段来说 null 是不占用任何空间的,查询起来反而还要快,但是对于char(100)来说,哪怕是null也会占用100字节空间
10.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的字段。
11.尽量避免向客户端返回大数据量,若数据量过大,可分批处理
12.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描
13.尽量使用union all替换union,因为union all不过滤,效率高(union去重代价非常高,尽可能的放在程序中去重)
14.能够用DISTINCT的就不用GROUP BY
15.大数据量的limit操作,使用延迟关联技巧:select id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10; 对于复杂的场景,我们可以建立符合索引(有where 条件,又想走索引用limit的,必须设计一个索引,将where 放第一位,limit用到的主键放第2位,而且只能select 主键)
16.向数据库中插入多条数据,拼接成一条sql语句最快
17. 尽量不要用SELECT INTO语句。SELECT INTO 语句会导致表锁定,阻止其他用户访问该表。
3.mysql与oracle的对比
1、本质的区别
Oracle数据库是一个对象关系数据库管理系统(ORDBMS)。它通常被称为Oracle RDBMS或简称为Oracle,是一个收费的数据库。
MySQL是一个开源的关系数据库管理系统(RDBMS)。它是世界上使用最多的RDBMS,作为服务器运行,提供对多个数据库的多用户访问。它是一个开源、免费的数据库。
2、数据库安全性
MySQL使用三个参数来验证用户,即用户名,密码和位置;Oracle使用了许多安全功能,如用户名,密码,配置文件,本地身份验证,外部身份验证,高级安全增强功能等。
3、SQL语法的区别
Oracle的SQL语法与MySQL有很大不同。Oracle为称为PL / SQL的编程语言提供了更大的灵活性。Oracle的SQL * Plus工具提供了比MySQL更多的命令,用于生成报表输出和变量定义。
4、存储上的区别:
与Oracle相比,MySQL没有表空间,角色管理,快照,同义词和包以及自动存储管理。
5、对象名称的区别:
虽然某些模式对象名称在Oracle和MySQL中都不区分大小写,例如列,存储过程,索引等。但在某些情况下,两个数据库之间的区分大小写是不同的。
Oracle对所有对象名称都不区分大小写;而某些MySQL对象名称(如数据库和表)区分大小写(取决于底层操作系统)。
6、运行程序和外部程序支持:
Oracle数据库支持从数据库内部编写,编译和执行的几种编程语言。此外,为了传输数据,Oracle数据库使用XML。
MySQL不支持在系统内执行其他语言,也不支持XML。
7、MySQL和Oracle的字符数据类型比较:
两个数据库中支持的字符类型存在一些差异。对于字符类型,MySQL具有CHAR和VARCHAR,最大长度允许为65,535字节(CHAR最多可以为255字节,VARCHAR为65.535字节)。
而,Oracle支持四种字符类型,即CHAR,NCHAR,VARCHAR2和NVARCHAR2; 所有四种字符类型都需要至少1个字节长; CHAR和NCHAR最大可以是2000个字节,NVARCHAR2和VARCHAR2的最大限制是4000个字节。可能会在最新版本中进行扩展。
8、MySQL和Oracle的额外功能比较:
MySQL数据库不支持其服务器上的任何功能,如Audit Vault。另一方面,Oracle支持其数据库服务器上的几个扩展和程序,例如Active Data Guard,Audit Vault,Partitioning和Data Mining等。
9、临时表的区别:
Oracle和MySQL以不同方式处理临时表。
在MySQL中,临时表是仅对当前用户会话可见的数据库对象,并且一旦会话结束,这些表将自动删除。
Oracle中临时表的定义与MySQL略有不同,因为临时表一旦创建就会存在,直到它们被显式删除,并且对具有适当权限的所有会话都可见。但是,临时表中的数据仅对将数据插入表中的用户会话可见,并且数据可能在事务或用户会话期间持续存在。
10、MySQL和Oracle中的备份类型:
Oracle提供不同类型的备份工具,如冷备份,热备份,导出,导入,数据泵。Oracle提供了最流行的称为Recovery Manager(RMAN)的备份实用程序。使用RMAN,我们可以使用极少的命令或存储脚本自动化我们的备份调度和恢复数据库。
MySQL有mysqldump和mysqlhotcopy备份工具。在MySQL中没有像RMAN这样的实用程序。
11、Oracle和MySQL的数据库管理:
在数据库管理部分,Oracle DBA比MySQL DBA更有收益。与MySQL相比,Oracle DBA有很多可用的范围。
12、数据库的认证:
MySQL认证比Oracle认证更容易。
与Oracle(设置为使用数据库身份验证时)和大多数仅使用用户名和密码对用户进行身份验证的其他数据库不同,MySQL在对用户进行身份验证location时会使用其他参数。此location参数通常是主机名,IP地址或通配符。
使用此附加参数,MySQL可以进一步将用户对数据库的访问限制为域中的特定主机或主机。此外,这还允许根据进行连接的主机为用户强制实施不同的密码和权限集。因此,从abc.com登录的用户scott可能与从xyz.com登录的用户scott相同或不同。
4.mysql的执行计划(EXPLAIN)

13.zookeeper
1.zookeeper原理和作用
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务。 功能:主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。 原理:Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

14.其他基础
1.MQ
各种MQ的比较
ActiveMQ:
优点: 技术成熟,功能齐全,历史悠久,有大量公司在使用
缺点: 偶尔会有较低概率丢失数据,而且社区已经不怎么维护5.15.X版本
适用场景: 主要用于系统解耦和异步处理,不适用与大数据量吞吐情况。互联网公司很少适用
rabitMQ:
优点: 吞吐量高,功能齐全,管理界面易用,社区活跃,性能极好
缺点: 吞吐量只是万级,erlang难以二次开发和掌控;集群动态扩展非常麻烦
适用场景: 吞吐量不高而要求低延迟,并且不会频繁调整和扩展的场景。非常适合国内中小型互联网公司适用,因为管理界面非常友好,可以在界面进行配置和优化/集群监控
rocketMQ
优点: 支持百千级大规模topic。吞吐量高(十万级,日处理上百亿)。接口易用。,分布式易扩展,阿里支持。java开发易于掌控
缺点: 与阿里(社区)存在绑定。不兼容JMS规范
适用场景: 高吞吐量
Kafka
优点: 超高吞吐量,超高可用性和可靠性,分布式易扩展
缺点: topic支持少,MQ功能简单,消息可能会重复消费影响数据精确度
适用场景: 超高吞吐量场景而数据精确度没那么高,天然适合大数据实时计算和日志采集场景

2.为什么要用消息队列?
解耦:A系统调用B系统、C系统,传统的调用是直接调用,但是当B系统说我不需要你提供数据了,这时候A需要改代码,C系统说我不需要某个字段了,这时候A也要改代码,如果又多了一个D系统,A又要写代码。为了实现解耦,引入消息队列,A将产生的数据丢到消息队列中,哪个系统需要,哪个系统就去取;
异步:A系统调用B系统,B系统由于某个需要调用第三方接口超时,导致A系统响应速度慢,而B系统的好坏又不会影响业务逻辑,所以可以改为A异步调用B,A将消息丢到消息队列中,B系统订阅消息,实现A的快速响应;
削峰:当大量流量请求到系统A时,由于数据库的处理能力有限,造成数据库连接异常。使用消息队列,大量请求先丢到消息队列中,系统A使用按批拉数据的方式,批量处理数据,生产中,高峰期短暂的消息积压是允许的。
3.使用消息队列有什么缺点
系统复杂性增加:需要考虑消息的处理,包括消息幂等性(重复消费问题),消息保序性(一个订单多条消息问题),以及消息中间件本身的持久化和稳定性可靠性
系统的可用性降低:解耦后,多个系统通过消息中间件交互,消息中间件挂了整个系统就挂了
4.什么是分布式、集群?
多台服务器合起来跑的才是一套完整代码,这就叫分布式;多台服务器跑的都是一套完整的代码,这就叫集群
目录
一、恒生电子面试题 4
1、JVM原理 4
2、事务如何主动回滚? 4
3、dubbo的优点 5
4、spring作用 6
5、事务ACID 7
6、最近在看什么书? 7
7、最近学会什么技术? 7
8、消费者调用提供者如果网络断了怎么办? 8
二、软通动力面试题 8
1、说几个线程安全的类 9
2、介绍springMVC 9
3、讲讲栈内存和堆内存 10
4、Oracle常用函数 10
1.单行函数 10
2.数值函数 11
3.转换函数 11
4.聚合函数 11
5、数据库视图的优化,存储过程 12
数据库优化方式有: 12
使用存储过程实现优化,因为存储过程的优点很多: 13
如何保证接口的安全可靠, 13
6、常用的集合和区别 13
1.Collection 13
2.LinkedList类 14
3.AyyayList类 14
4.Vector类 14
5.Set接口 15
6.TreeSet 15
7.Map接口 15
7、gc如何调用 15
8、多表连接注意事项 16
9、视图优缺点 16
1.视图的优点: 16
2.视图的缺点: 16
10、用户登录注销之后要做什么事 17
11、Linux 命令 17
三、公司面试题 19
1、说说你项目中为什么使用Springboot,dubbo,redis,activeMQ? 19
1.Spring Boot作为微服务的入门级微框架,有四点好处 19
2、Redis 持久化的原理 20
3、IOC的原理 20
4、如何反射生成一个对象? 21
5、spring注解开发了解一下 21
6、前端获取数据有几种方式 22
7、Jquery 22
8、盒子模型 22
9、锁的用法还有注意事项 22
1.减少锁持有时间 23
2.减小锁粒度 23
3.锁分离 23
4.锁粗化 23
5.锁消除 23
四、有赞面试题 23
1、redis常用命令: 24
1)连接操作命令 24
2)持久化 24
3)远程服务控制 24
4)对value操作的命令 24
5)String 24
6)List 25
7)Set 25
8)Hash 25
2、你了解hashMap吗? 底层实现方式?线程安全吗?如何实现安全?CocurrentHashMap了解吗? 26
3、如何创建多线程?线程池的作用? 26
4、线程池 26
一个线程池包括以下四个基本组成部分: 26
5、 Object类的常用方法 27
五、海康威视面试题 27
1、Arraylist 调用方法注意事项 27
2、支付过程中断网怎么办 27
3、一个项目如何支持两个数据库通用,修改哪些部分的代码 28
4、Hibernate 和mybstis 差异性 28
5、Spring内部实现机制 29
6、Ioc和aop底层如何实现 29
1.IoC(Inversion of Control) 29
2.AOP(Aspect Oriented Programming) 30
7、注解开发代码怎么写的,问注解里面是怎么实现的? 30
8、JQuery 和ext的区别 30
9、Ext 能实现哪些jQuery 实现不了的 31
10、Ioc通过一个注解实现依赖注入,里面代码是怎么实现的? 31
11、前端向后端可以发请求,后端怎么向前端抛消息? 31
六、昆山妈妈好面试题 31
1、线程的启动停止,如何同步 31
2、保证线程同步的方式可以通过以下7种方式: 32
1.同步方法 32
2.同步代码块 32
3.使用特殊域变量(volatile)实现线程同步 32
4.使用重入锁实现线程同步 32
5.使用局部变量实现线程同步 32
6.使用阻塞队列实现线程同步 33
7.使用原子变量实现线程同步 33
3、springmvc的请求流程 33
4、前端是否使用静态页面 34
5、前端框架 34
6、springboot介绍 34
7、web.xml的作用 34
8、线程在非同步方法的停止方法 34
8、过滤器的作用 35
9、cloud 35
10、数据库读写分离的实现 35
11、主从数据库同步的实现思路: 35
七、支付宝蚂蚁金服 36
1、String Stringbuffer Stringbuilder 36
2、Dubbox工作原理 36
3、Nginx网段配置 37
4、数据表索引的必要性 37
5、分布式不使用redis和cookie和session怎么多服务器共享用户登录状态 38
6、数据库存储模式 38
7、InnoDB是哪种读取类型 39
8、数据库中事务锁 39
9、乐观锁的优势和劣势 40
10、互联网高并发小轻快如何实现 40
11、数据库优化 40
12、Docker 42
1、简化程序: 42
2、避免选择恐惧症: 42
3、节省开支: 42
八、公司笔试题 42
1、多线程Hashmap死循环的操作是由于哪一步 42
2、讲述一下Hashmap的实现原理 43
3、List的实现类有哪些 43
4、微信支付宝银联的接入流程 44
5、Maven的操作命令你知道的有哪些 45
6、谈谈高并发的测试 45
7、你知道哪些算法 45
1.快速排序算法 45
2.动态规划算法 45
8、Mybatis分页插件有了解吗 45
9、全局异常怎么实现 46
10、进行抢购时你们redis的键是怎么设计的 46
11、锁的原理 46
12、同步代码块和方法加锁的区别 46
13、mybatis懒加载的原理 46
14用什么技术代替存储过程 47
其他面试题 47
1、高并发解决方案: 47
2、数据库优化思路: 48
3、常用的中间件: 48
4、关于事务的面试题: 48
一、什么是事务?有什么用?事务的特性ACID 48
二 事务的并发会产生的问题有哪些 48
三 不可重复读和幻读的区别 49
四、spring 事务隔离级别 49
五、spring事务的传播行为 49
六 Spring声明式事务的回滚机制 50
七 分布式环境下如何处理事务 50
5、微服务架构下处理分布式事务,你必须知道的事儿 50
一致性理论 51
一致性模型 52
分布式事务解决方案 52
选择建议 56

一、恒生电子面试题
1、JVM原理
内容见<面试必问之JVM原理>,参考地址
JVM->java虚拟机,解释器,负责将程序员编写的.java文件编译为多平台通用的字节码(.class)文件,最终将字节码解释给计算机执行
[JVM内存区域主要划分为“线程共享区”“非线程共享区”,比如,Method Area(方法区,non-heap)与Heap(堆),Direct Memory(运行时数据区域)是线程共享的,VM Stack(java方法栈,虚拟机栈),Native Method Stack(本地方法栈)和Program Counter Register(程序计数器)是非线程共享的]

  1. 工作过程:

:JVM运行时初始分配方法区与堆,遇到线程时,分配程序计数器,虚拟机栈,本地方法栈,线程终止时,三者的内存空间会被释放(生命周期==所属线程生命周期),这也是为什么GC机制只会发生在“线程共享区”的原因。
2、事务如何主动回滚?
3. 在spring框架的声明式事务处理中,只要抛出的异常是属于运行时异常的,spring的异常处理机制会自动回滚事务.
↑所属情景:java中的框架处理
如果是数据库中的事务,在你commit提交前执行rollback命令就好了,如果是已经commit的事务就不好恢复了。

3、dubbo的优点
首先Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。
1.远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
2.软负载均衡及容错机制: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持.可在内网替代F5等硬件负载均衡器,降低成本,减少单点
3.服务自动注册与发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器
4.提供完善的管理控制台dubbo-admin与简单的控制中心dubbo-monitor
5.Dubbo提供了伸缩性很好的插件模型,很方便进行扩展(ExtensionLoader)
6.支持多协议
使用方法:
Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。

太长不看,背不下来的建议回答如下:
Dubbo,作为阿里的优秀开源框架,确实比较好用,跟spring兼容度也不错,它本身有很多优点,比如负载均衡跟容错之类做的都比较好,但我觉得最好的一点是它提供了伸缩性很好的插件模型,这点可以让你很方便的进行扩展,给了我们更多的可能性。
(接下来可以尝试绕过这个话题了)
4. dubbo中消费者调用提供者原理
Provider:暴露服务方称之为“服务提供者”
Consumer:调用远程服务方称之为“服务消费者”
Registry:服务注册与发现的中心目录服务称之为“服务注册中心”
Monitor:统计服务的调用次调和调用时间的日志服务称之为“服务监控中心”
Provider发布后会在Registry中注册,Consumer从Registry订阅服务,一旦注册中心提供了Provider, Consumer就可以异步得到通知,从而调用Provider的功能,这两者都会在Monitor监控中心中被记录调用的信息.
看起来绕口,其实描述不如画图↓↓↓↓↓

4、spring作用
Spring框架主要用于与其他技术(struts,hibernate等)进行整合,可将 应用程序中的Bean组件实现低耦合关联.最终可以提高系统扩展和维护 性.将来我们利用Spring框架管理系统的各个组件(Action,Service,DAO)采 用Spring的IOC和AOP机制实现各组件的关联.从而实现了低耦合调用. 增强了系统可维护性和扩展性.
降低组件耦合性,实现程序各层解耦;
主流框架集成,如XXX;
低侵入式设计,不影响代码;
最主要的还是IOC与AOP,让我们更加方便快捷的进行开发。
主要解释IOC与AOP:
IOC:依赖注入(控制反转),将所需要用到的类以注解或配置文件的方式提供给spring,由spring生成(默认为单例)对象,更简单的实现业务对象。 [注入方式有两种,第一种是设置注入,比较直观,自然。第二种是构造注入,可以在构造器中指定依赖关系顺序]
(底层实现基本就是反射机制那一套,熟的可以BB两句)
AOP:切面编程,基于OOP面向对象的一种补充。主要是提供一个更好更方便的事务管理方式,同时也支持我们自定义切面。[面向对象是将程序分解为各个层次的对象,面向切面是将程序运行过程分解为各个切面。] [OOP是静态的抽象,AOP是动态的,对应用执行过程中的步骤进行抽象,从而获得步骤之间的逻辑划分。]
(*主要特性) AOP以步骤划分,各个步骤之间有非常好的隔离型,并且与源代码没有什么关联性。你可以很方便的在某个步骤前后加上自己想要的操作。
5、事务ACID
ACID,指数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。一个支持事务(Transaction)的数据库,必须要具有这四种特性,否则在事务过程(Transaction processing)当中无法保证数据的正确性,交易过程极可能达不到交易方的要求。
原子性:要么不谈,要谈就要结婚。
一致性:恋爱时,什么方式爱我;结婚后还得什么方式爱我;
隔离性:闹完洞房后,是俩人的私事。
持久性:一旦领了结婚证,无法后悔。

6、最近在看什么书?
<JVM虚拟机原理><java设计模式><重构>
Java高并发编程模式与原则
7、最近学会什么技术?
Shiro框架,还了解了一些SpringCloud体系的Eureka, Config, Bus,Hadoop生态圈MapRecude,HBASE,Spark,Kafka的知识点,正准备深入
SpringCloud:
Q:什么是springcloud?
A:springcloud是一套完整的微服务解决方案,基于springboot框架。但准确来说,它并不是一个框架,而更像是一个大的容器,将市面上成型比较好的微服务框架集成进来,简化了开发者的代码;
Q:spring核心组件:
A:分两类
一类是融合在微服务中,依赖其他组件并为其提供服务:
Ribbon客户端负载均衡;
Hystrix客户端容错保护;
Feign声明式服务调用,本质上是Ribbon+Hystrix;
Stream 消息驱动;
Bus消息总线;
Sleuth分布式服务追踪
第二类是独自启动,不需要依赖其他组件的:
Eureka 服务注册中心;
Dashboard Hystrix仪表盘;
Zuul API服务网关
Config 分布式配置中心
8、消费者调用提供者如果网络断了怎么办?
三种方案1,dubbo部署集群,当前网络中断可在集群中匹配到其它提供者实现,如果没有找到其它提供者, 服务提供者和服务消费者仍能通过本地缓存通讯,直到网络恢复.2 消费者在调用过程中如果得不到提供者的回馈则设定时间取消操作,事务进行回滚处理.保证事务完整性3将请求消息放入消息队列中,提示用户操作,当提供者正常服务后进行消费,从而保证事务完整性.
如果是客户网断的情况大多不用担心,根据当前环境判断是否回滚,给出通知让用户上线后知道刚才做了什么,保留了什么,业务进行到哪。
如果是服务器断网(环境肯定是分布式了)
判断是否有集群,有则直接切换。没有集群的话消费者读取本地缓存,继续提供服务,实在获取不到服务的情况下,为了保证数据安全,消费者将在设定时间后进行事务回滚,除此之外,请求消息可暂时放入消息队列,在提供者上线后再进行操作。
二、软通动力面试题

1、说几个线程安全的类
Timer,TimerTask,Vector,Stack,HashTable,ConcurrentHashMap,StringBuffer
2、介绍springMVC
Spring MVC框架是有一个MVC框架,通过实现Model-View-Controller模式来很好地将数据、业务与展现进行分离。从这样一个角度来说,Spring MVC和Struts、Struts2非常类似。Spring MVC的设计是围绕DispatcherServlet展开的,DispatcherServlet负责将请求派发到特定的handler。通过可配置的handler mappings、view resolution、locale以及theme resolution来处理请求并且转到对应的视图,具体的请求流程如下:
1、用户发送请求至前端控制器DispatcherServlet
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器查找Handler。HandlerMapping可以根据xml配置、注解配置进行查询。
3、处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、DispatcherServlet通过HandlerAdapter处理器适配器调用处理器,处理器在实际开发中习惯称为controller(另一种说法处理器是后端控制器,最终调用service进行业务处理)。
5、HandlerAdapter调用处理器Handler
6、Handler执行完成返回ModelAndView,ModelAndView是springmvc的封装对象,将模型和视图封装在一个对象中。
7、HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器,ViewReslover根据逻辑视图名解析View逻辑视图名:如果指定具体的jsp完整地址不方便,将完整的地址简化为逻辑的视图名(串)。view:是一个接口,接口实现了很多类型的view(比如:jstlView、pdfView、freemarker、报表的view)ViewReslover:不同的视图解析器可以解析出上边不同的view.
9、ViewReslover返回View
10、DispatcherServlet对View进行渲染视图(即将模型数据填充至request域)。
11、DispatcherServlet响应用户(将jsp转发给用户,最终由tomcat解析servlet生成html,最终响应)
它在程序中可以设置成单例,因为没有全局的数据域.
3、讲讲栈内存和堆内存
栈:主要是用来执行程序的,堆:主要用来存放对象的
栈(stack):有编译器自动分配和释放,存放函数的参数、局部变量、临时变量、函数返回地址等;
堆(heap):一般有程序员分配和释放,如果没有手动释放,在程序结束时可能由操作系统自动释放(?这个可能针对Java那样的有回收机制的语言而说的,对于c/c++,这样的必须要手动释放开辟的堆内存),稍有不慎会引起内存泄漏。

栈:只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:在记录空闲内存地址的链表中寻找一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。另外,对于大多数系统会在这块内存空间的首地址出记录本次分配空间的大小,这样代码中的delete 才能正确释放本内存空间。系统会将多余的那部分重新空闲链表中。
栈:由系统自动分配,速度较快。但程序员是无法控制的。
堆:由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
4、Oracle常用函数
1.单行函数
(1)concat(str1,str2)字符串拼接函数
(2)initcap(str)将每个单词首字母大写,其他字母小写
(3)instr(x,find_string[,start][,occurrence])返回指定字符串在某字符串中的位置,可以指定搜索的开始位置和返回第几次搜索出来的结果
(4)length(str)返回表达式中的字符数
(5)lengthb(str)返回表达式中的字节数
(6)lower(str)将字符串转换为小写
(7)upper(str)将字符串转换为大写
(8)lpad(str,width[,pad_string])当字符串长度不够时,左填充补齐,可以指定补齐时用什么字符补齐,若不指定,则以空格补齐
(9)rpad(str,width[,pad_string])当字符串长度不够时,右填充补齐,原理同左填充
(10)ltrim(x[,trim_string])从字符串左侧去除指定的所有字符串,若没有指定去除的字符串,则默认去除左侧空白符
(11)rtrim(x[,trim_string])从字符串右侧去除指定的所有字符串,原理同ltrim()
(12)trim(trim_string from x)从字符串两侧去除指定的所有字符串
(13)nvl(x,value)将一个NULL转换为另外一个值,如果x为NULL,则返回value,否则返回x值本身
(14)nvl2(x,value1,value2),如果x不为NULL,返回value1,否则,返回value2
(15)replace(x,search_string,replace_string),从字符串x中搜索search_string字符串,并使用replace_string字符串替换。并不会修改数据库中原始值
(16)substr(x,start[,length])返回字符串中的指定的字符,这些字符从字符串的第start个位置开始,长度为length个字符;如果start是负数,则从x字符串的末尾开始算起;如果       length省略,则将返回一直到字符串末尾的所有字符
2.数值函数
(1)abs(value)返回value的绝对值
(2)ceil(value)返回大于等于value的最小整数
(3)floor(value)返回小于等于value的最大整数
(4)trunc(value,n)对value进行截断,如果n>0,保留n位小数;n<0,则保留-n位整数位;n=0,则去掉小数部分
(5)round(value,n)对value进行四舍五入,保存小数点右侧的n位。如果n省略的话,相当于n=0的情况
3.转换函数
(1)to_char(x[,format]):将x转化为字符串。 format为转换的格式,可以为数字格式或日期格式
(2)to_number(x [, format]):将x转换为数字。可以指定format格式
(3)cast(x as type):将x转换为指定的兼容的数据库类型
(4)to_date(x [,format]):将x字符串转换为日期
4.聚合函数
(1)avg(x):返回x的平均值
(2)count(x):返回统计的行数
(3)max(x):返回x的最大值
(4)min(x):返回x的最小值
(5)sum(x):返回x的总计值
5、数据库视图的优化,存储过程
视图是指计算机数据库中的视图,是一个虚拟表,其内容由查询定义。对于复杂的连表查询,可以利用创建视图来使SQL语句变得简单。
数据库优化方式有:
1.给适当的列加上索引。
2尽量避免全表扫描,首先应考虑在where及order by涉及的列上建立索引。
3.避免使用 select * 从数据库里读出越多的数据,那么查询就会变得越慢
4永远为每张表设置一个ID使用VARCHAR类型来当主键会使得性能下降
5使用ENUM而不是VARCHAR
sex ENUM(‘男’,‘女’)
如果一个列只含有有限树木的特定值,比如:性别、状态等,尽量采用ENUM列举出所有可能的取值作为数据类型,enum列的值都是以标识数值标识,mysql会处理的更快。
6.尽量避免在where子句中使用or来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描
7.模糊查询不要以通配符开始,否则会导致索引失效而进行全表扫描
select from t_student where sName like ‘a%’
8.尽量避免在where子句中对字段进行表达式操作,这会导致引擎失效放弃使用索引而进行全表扫描。
select id from t where num/2=100
应该改为 select id from t where num=100
2
9.In和not in要慎用,否则可以导致全表扫描,可以用exists代替In。
Select num from a where num in(select num from b)
用下面的语句替换
Select num from a where exists(select 1 from b where num=a.num)
10.一个表的索引最好不要超过6个,若太多则应考虑删除不常使用的索引
11.尽量避免大事务操作,提高系统并发能力
12.并不是所有索引对查询都有效,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如果一表中有字段sex,male,female几乎各一半,那么即使在sex上建了索引页会查询效率起不了太大作用
使用存储过程实现优化,因为存储过程的优点很多:
1存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
2当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。
3存储过程可以重复使用,可减少数据库开发人员的工作量。
4安全性高,可设定只有某些用户才具有对指定存储过程的使用权
如何保证接口的安全可靠,
题意不清.什么接口?如果是指HTTP接口那么有如下方式可供选择
1、选择拦截过滤器。
在请求的时候对请求方法进行一次拦截处理。比如非正常访问的方法已经注入插入可执行语句参数验证等在拦截中进行一次安全校验保证请求不是非法请求。
2、数据加密。我们知道目前大部分APP接口都是通过Http协议进行调用的容易被抓包拦截。我们可以对客户端和服务端都对数据传输的时候进行一个加密处理。常用的MD5 AES等。
3、签名
根据用户名或者用户id,结合用户的ip或者设备号,生成一个token。在请求后台,后台获取http的head中的token,校验是否合法(和数据库或者Redis中记录的是否一致,在登录或者初始化的时候,存入数据库/redis)爱旅行项目中就采用的Token方式.
4、使用第三方框架与技术整合支持比如spring的框架中的oauth模块。还有Shiro框架等.
6、常用的集合和区别
1.Collection
Collection是最基本的集合类型,所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个共的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。若要检查Collection中的元素,可以使用foreach进行遍历,也可以使用迭代器,Collection支持iterator()方法,通过该方法可以访问Collection中的每一个元素。

Set和List是由Collection派生的两个接口.List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引的位置来访问List中的元素,类似于Java数组。List允许有相同的元素存在。
实现List接口的常用类有LinkedList、ArrayList、Vector和Stack
2.LinkedList类
LinkedList实现了List类接口,允许null元素。此外LinkedList提供额外的get、remove、insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)
LinkedList没有同步方法。如果多个线程想访问同一个List,则必须自己实现访问同步。
3.AyyayList类
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。size(),isEmpty(),get(),set()方法运行时间为常数。但是add()方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。每个ArrayList实例都有一个容量(Capactity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入之前可以调用ensureCapacity()方法来增加ArrayList容量已提高插入效率
4.Vector类
Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的iterator,虽然和ArrayLsit创建的iterator是同一接口,但是,因为Vector是同步的,当一个iterator被创建而且这在被使用,另一个线程改变了Vector状态,这时调用iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。
Stack类
Stack继承自Vector,实现了一个后进先出的堆栈。Stack提供了5个额外的方法使得Vector得以被当做堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,serach方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

5.Set接口
Set是一种不包含重复元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。请注意:必须小心操作可变对象。如果一个Set中的可变元素改变了自身的状态导致Object.equals(Object)=true将导致一些问题
HashSet
HashSet调用对象的hashCode(),获得哈希码,然后在集合中计算存放对象的位置。通过比较哈希码与equals()方法来判别是否重复。所以,重载了equals()方法同时也要重载hashCode();
6.TreeSet
TreeSet 继承SortedSet接口,能够对集合中对象排序。默认排序方式是自然排序,但该方式只能对实现了Comparable接口的对象排序,java中对Integer、Byte、Double、Character、String等数值型和字符型对象都实现了该接口。
7.Map接口
Map没有继承Collection接口,Map提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个value。Map接口提供了3中集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key–value映射。
HashTable类
HashTable继承Map接口,实现了一个key–value映射的哈希表。任何非空的对象都可作为key或者value。添加数据使用put(key,value),取出数据使用get(key),这两个基本操作的时间开销为常数。 HashTable通过initial caoacity和load factor两个参数调整性能。通常缺省的load factor 0.75较好地实现了时间和空间的均衡。增大了load factor可以节省空间但相应的查找时间将增大,这会影响像get和put这样的操作.HashTable是同步的.
HashMap类
HashMap和HashTable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null key,但是将HashMap视为Collection时,其迭子操作时间开销和HahMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设的过高,或者load factor过低

7、gc如何调用
通过System.gc()方法可以进行调用垃圾回收器(GC),但Java的GC是由JVM自行调动的,在需要的时候才执行,上面的指令只是告诉JVM尽快GC一次,但不会立即执行GC。也可以通过对需要回收的对象通过close()或者赋值成null,通知GC尽快回收.
8、多表连接注意事项
.在数据库中,通常可以通过查看执行计划了解sql语句的执行顺序,以及花费的时间等,但在使用left join时,需要特别注意的是,如果第二张表有筛选条件,应该将连接条件写在join里面,而不是写在where后面.
9、视图优缺点
1.视图的优点:
第一点:使用视图,可以定制用户数据,聚焦特定的数据。
解释:在实际过程中,公司有不同角色的工作人员,我们以销售公司为例的话,采购人员,可以需要一些与其有关的数据,而与他无关的数据,对他没有任何意义,我们可以根据这一实际情况,专门为采购人员创建一个视图,以后他在查询数据时,只需select * from view_caigou 就可以啦。
第二点:使用视图,可以简化数据操作。
解释:我们在使用查询时,在很多时候我们要使用聚合函数,同时还要显示其它字段的信息,可能还会需要关联到其它表,这时写的语句可能会很长,如果这个动作频繁发生的话,我们可以创建视图,这以后,我们只需要select * from view1就可以啦,这样很方便。
第三点:使用视图,基表中的数据就有了一定的安全性因为视图是虚拟的,物理上是不存在的,只是存储了数据的集合,我们可以将基表中重要的字段信息,可以不通过视图给用户,视图是动态的数据的集合,数据是随着基表的更新而更新。同时,用户对视图,不可以随意的更改和删除,可以保证数据的安全性。
第四点:可以合并分离的数据,创建分区视图
随着社会的发展,公司的业务量的不断的扩大,一个大公司,下属都设有很多的分公司,为了管理方便,我们需要统一表的结构,定期查看各公司业务情况,而分别看各个公司的数据很不方便,没有很好的可比性,如果将这些数据合并为一个表格里,就方便多啦,这时我们就可以使用union关键字,将各分公司的数据合并为一个视图。
2.视图的缺点:
1)性能差
数据库必须把视图查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,数据库也要把它变成一个复杂的结合体,需要花费一定的时间。
2)修改限制
当用户试图修改试图的某些信息时,数据库必须把它转化为对基本表的某些信息的修改,对于简单的试图来说,这是很方便的,但是,对于比较复杂的试图,可能是不可修改的。
10、用户登录注销之后要做什么事
通常清除用户会话状态, 视业务需求而定是否在客户写入端cookie信息在数据保存注销时间等业务.
11、Linux 命令
ls  显示文件或目录
mkdir 创建目录
cd 切换目录
touch 创建空文件
echo 创建带有内容的文件。
cat 查看文件内容
cp 拷贝
mv 移动或重命名
rm 删除文件
find 在文件系统中搜索某文件
wc 统计文本中行数、字数、字符数
grep 在文本文件中查找某个字符串
rmdir 删除空目录
tree 树形结构显示目录,需要安装tree包
pwd 显示当前目录
ln 创建链接文件
more、less 分页显示文本文件内容
head、tail 显示文件头、尾内容
stat 显示指定文件的详细信息,比ls更详细
who 显示在线登陆用户
whoami 显示当前操作用户
hostname 显示主机名
uname 显示系统信息
top 动态显示当前耗费资源最多进程信息
ps 显示瞬间进程状态 ps -aux
du 查看目录大小 du -h /home带有单位显示目录信息
df 查看磁盘大小 df -h 带有单位显示磁盘信息
ifconfig 查看网络情况
ping 测试网络连通
netstat 显示网络状态信息
man 命令不会用了,找男人如:man ls
clear 清屏
alias 对命令重命名如:alias showmeit=“ps -aux”
kill 杀死进程,可以先用ps 或 top命令查看进程的id
tar: 打包压缩
shutdown 关机重启
halt 关机
reboot 重启
sudo dpkg -i tree_1.5.3-1_i386.deb 安装软件
sudo dpkg -r tree 卸载软件
sudo apt-get install tree 安装tree
sudo apt-get remove tree 卸载tree
sudo apt-get update 更新软件
sudo apt-get upgrade
vim三种模式:命令模式、插入模式、编辑模式。使用ESC或i或:来切换模式。
命令模式下:
:q 退出
:q! 强制退出
:wq 保存并退出
:set number 显示行号
:set nonumber 隐藏行号
yyp 复制光标所在行,并粘贴
passwd root 给root设置密码
/etc/profile 系统环境变量
bash_profile 用户环境变量
.bashrc 用户环境变量
su user 切换用户,加载配置文件.bashrc
su - user 切换用户,加载配置文件/etc/profile ,加载bash_profile
sudo chown [-R] owner[:group] {File|Directory}更改文件的用户及用户组
sudo chmod 777 filename 更改权限
三、公司面试题
1、说说你项目中为什么使用Springboot,dubbo,redis,activeMQ?

1.Spring Boot作为微服务的入门级微框架,有四点好处

  1. Spring Boot使编码变简单
  2. Spring Boot使配置变简单
  3. Spring Boot使部署变简单
  4. Spring Boot使监控变简单
    Dubbo是一种服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成。
    在项目中使用redis,主要是从两个角度去考虑:性能和并发。当然,redis还具备可以做分布式锁,消息队列等其他功能,但还有其他中间件(如zookpeer,activeMQ等)代替,并不是非要使用redis。因此,主要从性能和并发两个角度出发去考虑的。
    (一)性能
    在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。这样,后面的通过请求就去缓存中读取放入到activeMQ,使得请求能够迅速响应。
    (二)并发
    在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问数据库。
    ActiveMQ的特性主要管理消息的事务,以及消息持久化,即使在出错时也不会漏掉一条消息。消息服务器需要进行信息持久化,一个服务器集群可以提高其可用性,ActiveMQ正式这样的一个高可用性的消息服务器,典型的情况就是当一个Server Node掉线的时候,它上面的所有消息都会被保存下来,以便在它重新上线时继续处理。ActiveMQ的的另一个特性是高性能的数据分发,主要关注的是消息的吞吐率以及高效的消息投递路由,中心思想就是在一个大的网络中尽可能快的传递大量的并且快速改变的消息数据。鉴于大量的数据和频繁的数据数据交换负荷很高,所以这种情况下很少使用数据持久化,在失败时丢失几条数据也是可以接受的因为老的数据通常都不再被需要了,最新的数据才是真正我们关心的.
    2、Redis 持久化的原理
    由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
    3、IOC的原理
    Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,其中BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范,在容器初始化时创建程序所需的对象,实现控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系,这就IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等这个描述最具体表现就是我们可配置的文件。
    4、如何反射生成一个对象?
    反射是java特有的一种机制,可以在程序运行的过程中,动态的获取类的属性和方法,可以通过类的全限定名,对象本身,类本身获取字节码对象。通过字节码对象获取构造器,字段,方法等对象。
  1. 会用什么开发软件?
    IDE :IDEA,Eclipse,MyEclipse,NetBean,DreamWare
    Server:Tomcat,WebLogic,Jetty,
    OS:Linux,Ubuntu,Centos,Windows
    DB:mysql ,Oracle,SQL Server
    5、spring注解开发了解一下
    springboot是纯以注解开发的,基础的springmvc注解有
    @Configuration把一个类作为一个IoC容器,它的某个方法头上如果 注册了@Bean,就会作为这个Spring容器中的Bean。
    @Scope注解作用域
    @Lazy(true) 表示延迟初始化
    @Service用于标注业务层组件、
    @Controller用于标注控制层组件(如struts中的action)
    @RestController 相当于Controller+@ResponseBody
    @Repository用于标注数据访问组件,即DAO组件。
    @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
    @Scope用于指定scope作用域的(用在类上)
    @PostConstruct用于指定初始化方法(用在方法上)
    @PreDestory用于指定销毁方法(用在方法上)
    @DependsOn:定义Bean初始化及销毁时的顺序
    @Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
    @Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。如下:
    @Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用
    @Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
    @PostConstruct 初始化注解
    @PreDestroy 摧毁注解默认单例启动就加载
    @Async异步方法调用
    6、前端获取数据有几种方式
    1通过URL发送请求,可以POST或GET形式,获得服务器响应
    2 服务器响应的方式可以是xml格式,JSON 格式,如果使用的模板引擎还可以是JAVA对象。前端通过JS处理数据
    3 也可以通过cookies的形式保存在客户端由前端通过JS解析
    7、Jquery
    jQuery 是一个 JavaScript 库,极大地简化了 JavaScript 编程。jQuery 很容易学习,以面向对象的形式进行操作,做为后端开发常用的方法有html(),append(),val(),click(),ready(),ajax(),get(),getJson()等等。
    8、盒子模型
    盒子模型,英文即box model。无论是div、span、还是a都是盒子。但是,图片、表单元素一律看作是文本,它们并不是盒子。这个很好理解,比如说,一张图片里并不能放东西,它自己就是自己的内容。盒子中的区域主要的属性就5个:width、height、padding、border、margin:
    width和height:内容的宽度、高度(不是盒子的宽度、高度)。
    padding:内边距。
    border:边框。
    margin:外边距。
    9、锁的用法还有注意事项
    一旦用到锁,就说明这是阻塞式的,所以在并发度上一般来说都会比无锁的情况低一点。因此需要注意锁的优化。锁优化,是指在阻塞式的情况下,如何让性能不要变得太差。但是再怎么优化,一般来说性能都会比无锁的情况差一点。
    锁优化的思路和方法总结一下,有以下几种。
    1.减少锁持有时间
    只用在有线程安全要求的程序上加锁,减少其他线程等待的时间
    2.减小锁粒度
    将大对象(这个对象可能会被很多线程访问),拆成小对象,大大增加并行度,降低锁竞争。降低了锁的竞争,偏向锁,轻量级锁成功率才会提高。
    3.锁分离
    最常见的锁分离就是读写锁ReadWriteLock,根据功能进行分离成读锁和写锁,这样读读不互斥,读写互斥,写写互斥,即保证了线程安全,又提高了性能
    4.锁粗化
    通常情况下,为了保证多线程间的有效并发,会要求每个线程持有锁的时间尽量短,即在使用完公共资源后,应该立即释放锁。只有这样,等待在这个锁上的其他线程才能尽早的获得资源执行任务。但是,凡事都有一个度,如果对同一个锁不停的进行请求、同步和释放,其本身也会消耗系统宝贵的资源,反而不利于性能的优化
    5.锁消除
    锁消除是在编译器级别的事情。在即时编译器时,如果发现不可能被共享的对象,则可以消除这些对象的锁操作。
    四、有赞面试题

1、redis常用命令:
1)连接操作命令
quit:关闭连接(connection)
auth:简单密码认证
help cmd:查看cmd帮助,例如:help quit
2)持久化
save:将数据同步保存到磁盘
bgsave:将数据异步保存到磁盘
lastsave:返回上次成功将数据保存到磁盘的Unix时戳
shundown:将数据同步保存到磁盘,然后关闭服务
3)远程服务控制
info:提供服务器的信息和统计
monitor:实时转储收到的请求
slaveof:改变复制策略设置
config:在运行时配置Redis服务器
4)对value操作的命令
exists(key):确认一个key是否存在
del(key):删除一个key
type(key):返回值的类型
keys(pattern):返回满足给定pattern的所有key
randomkey:随机返回key空间的一个
keyrename(oldname, newname):重命名key
dbsize:返回当前数据库中key的数目
expire:设定一个key的活动时间(s)
ttl:获得一个key的活动时间
select(index):按索引查询
move(key, dbindex):移动当前数据库中的key到dbindex数据库
flushdb:删除当前选择数据库中的所有key
flushall:删除所有数据库中的所有key
5)String
set(key, value):给数据库中名称为key的string赋予值value
get(key):返回数据库中名称为key的string的value
getset(key, value):给名称为key的string赋予上一次的value
mget(key1, key2,…, key N):返回库中多个string的value
setnx(key, value):添加string,名称为key,值为value
setex(key, time, value):向库中添加string,设定过期时间time
mset(key N, value N):批量设置多个string的值
msetnx(key N, value N):如果所有名称为key i的string都不存在
incr(key):名称为key的string增1操作
incrby(key, integer):名称为key的string增加integer
decr(key):名称为key的string减1操作
decrby(key, integer):名称为key的string减少integer
append(key, value):名称为key的string的值附加value
substr(key, start, end):返回名称为key的string的value的子串
6)List
rpush(key, value):在名称为key的list尾添加一个值为value的元素
lpush(key, value):在名称为key的list头添加一个值为value的元素
llen(key):返回名称为key的list的长度
lrange(key, start, end):返回名称为key的list中start至end之间的元素
ltrim(key, start, end):截取名称为key的list
lindex(key, index):返回名称为key的list中index位置的元素
lset(key, index, value):给名称为key的list中index位置的元素赋值
lrem(key, count, value):删除count个key的list中值为value的元素
lpop(key):返回并删除名称为key的list中的首元素
rpop(key):返回并删除名称为key的list中的尾元素
blpop(key1, key2,… key N, timeout):lpop命令的block版本。
brpop(key1, key2,… key N, timeout):rpop的block版本。
rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部
7)Set
sadd(key, member):向名称为key的set中添加元素member
srem(key, member) :删除名称为key的set中的元素member
spop(key) :随机返回并删除名称为key的set中一个元素
smove(srckey, dstkey, member) :移到集合元素
scard(key) :返回名称为key的set的基数
sismember(key, member) :member是否是名称为key的set的元素
sinter(key1, key2,…key N) :求交集
sinterstore(dstkey, (keys)) :求交集并将交集保存到dstkey的集合
sunion(key1, (keys)) :求并集
sunionstore(dstkey, (keys)) :求并集并将并集保存到dstkey的集合
sdiff(key1, (keys)) :求差集
sdiffstore(dstkey, (keys)) :求差集并将差集保存到dstkey的集合
smembers(key) :返回名称为key的set的所有元素
srandmember(key) :随机返回名称为key的set的一个元素
8)Hash
hset(key, field, value):向名称为key的hash中添加元素field
hget(key, field):返回名称为key的hash中field对应的value
hmget(key, (fields)):返回名称为key的hash中field i对应的value
hmset(key, (fields)):向名称为key的hash中添加元素field
hincrby(key, field, integer):将名称为key的hash中field的value增加integer
hexists(key, field):名称为key的hash中是否存在键为field的域
hdel(key, field):删除名称为key的hash中键为field的域
hlen(key):返回名称为key的hash中元素个数
hkeys(key):返回名称为key的hash中所有键
hvals(key):返回名称为key的hash中所有键对应的value
hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value

2、你了解hashMap吗? 底层实现方式?线程安全吗?如何实现安全?CocurrentHashMap了解吗?

了解一点,HashMap的主干是一个Entry数组。Entry是HashMap的基本组成单元,每一个Entry包含一个key-value键值对。 HashMap中有一个静态内部类Entry。所以,HashMap的整体结构简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。HashMap有4个构造器,其他构造器如果用户没有传入initialCapacity 和loadFactor这两个参数,会使用默认值。initialCapacity默认为16,loadFactory默认为0.75。是线程不安全的。如果需要安全就选择HashTable或者CocurrentHashMap,这两个都是安全的。
3、如何创建多线程?线程池的作用?
在JDK1.5之前,创建线程就只有两种方式,即继承java.lang.Thread类和实现java.lang.Runnable接口;而在JDK1.5以后,增加了两个创建线程的方式,即实现java.util.concurrent.Callable接口和线程池。
1继承Thread类
2实现Runnable接口
3实现Callable接口
相较于实现Runnable 接口的实现,方法可以有返回值,并且抛出异常。
4、线程池
线程池提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应速度。
java.util.concurrent.Executors提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池,多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
1、 线程池管理器(ThreadPool):用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务;

2、 工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;

3、 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;

4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。
5、 Object类的常用方法
Object类是一个特殊的类,是所有类的父类,如果一个类没有用extends明确指出继承于某个类,那么它默认继承Object类。Object类中的常用方法:
1.取得对象信息的方法:toString()
2.对象相等判断方法:equals()
3.对象签名:hashCode()
4.获得字节码对象方法:getClass();
5.等待方法:wait()
6.唤醒方法:notify()
7.唤醒所有其它方法:notifyAll()

五、海康威视面试题
1、Arraylist 调用方法注意事项
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。size(),isEmpty(),get(),set()方法运行时间为常数。但是add()方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。每个ArrayList实例都有一个容量(Capactity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入之前可以调用ensureCapacity()方法来增加ArrayList容量已提高插入效率,
2、支付过程中断网怎么办
从单服务应用程序断网角度分析
1在用户还没输入密码之前:网络原因支付失败
2用户输入密码过程中:网络原因支付失败
3密码已经输入,第三方支付服务器已经接收到正确密码并且确认支付成功。这时,第三方支付服务器确认支付成功,通知应用程序,但应用程序断网,此时需要在连接后主动或手动读取第三方支付服务器的信息进行后续处理。
在分布式集群中的部署可以在其中某台主机断网时匹配集群中其它应用进行处理。但很多时候,一个请求,会调用很多service服务,如果service之间是串行的话,那么一个service超时,很可能会引起连锁反应,所以在调用别的接口的时候(不管是第三方支付接口,还是分布式接口),都需要加一个超时时间,超过这个时间,就不在等待了,视作失败,或者处理中,然后再后续处理。
3、一个项目如何支持两个数据库通用,修改哪些部分的代码
mybatis框架3.1以上版本支持多数据库兼容操作,只要修改spring的数据源配置代码或者或者mybatis的databaseIdProvider 节点和mapper映射文件代码,项目中以一种数据库为主, 如MySQL为主, Oracle则是某些模块使用, 即写mapper的xml时, 一般都直接不写databaseId, 唯有Oracle那个模块才写上 databaseId=”oracle” . 而另一种情况则是, 整个项目都需要兼容, 那修改量就相对大一些, 需要2个statement分别标明不同的databaseId.
4、Hibernate 和mybstis 差异性
myBatis加载的字段很干净,没有太多多余的字段,直接映射入关联中。而hibernate则将整个表的字都会加载到对象中,其中还包括关联的user字段。hibernate这种情况下有好有坏,要看具体的场景,对于管理平台,需要展现的信息较多,并发要求不高时,hibernate比较有优势。然而在一些小活动,互联网网站,高并发情况下,hibernate的方案太不太适合,myBatis+VO则是首选。总体初观,myBatis在所有情况下,特别是插入与单表查询,都会微微优于hibernate。不过差异情况并不明显,可以基本忽略差异。差异比较大的是关联查询时,hibernate为了保证POJO的数据完整性,需要将关联的数据加载,需要额外地查询更多的数据。这里hibernate并没有提供相应的灵活性。关联时一个差异比较大的地方则是懒加载特性。其中hibernate可以特别地利用POJO完整性来进行缓存,可以在一级与二级缓存上保存对象,如果对单一个对象查询比较多的话,会有很明显的性能效益。以后关于单对象关联时,可以通过懒加载加二级缓存的方式来提升性能。最后,数据查询的性能与orm框架关无太大的关系,因为orm主要帮助开发人员将关系数据转化成对象型数据模型,对代码的深析上来看,hibernate设计得比较重量级,对开发来说可以算是重新开发了一个数据库,不让开发去过多关心数据库的特性,直接在hibernate基础上进行开发,执行上分为了sql生成,数据封装等过程,这里花了大量的时间。然而myBatis则比直接,主要是做关联与输出字段之间的一个映射。其中sql基本是已经写好,直接做替换则可,不需要像hibernate那样去动态生成整条sql语句。myBatis相对Hibernate 等封装较为严密的ORM 实现而言,因为hibernate对数据对象的操作实现了较为严密的封装,可以保证其作用范围内的缓存同步,而ibatis 提供的是半封闭的封装实现,因此对缓存的操作难以做到完全的自动化同步。以上的缓存配置测试仅为性能上的分析,没有加入可用性上的情况,因为myBatis直接配置缓存的话,可能会出现脏数据,。在关联查询数据的情况下,hiberntae的懒加载配二级缓存是个比较好的方案(无脏数据),也是与myBatis相比有比较明显的优势。此情景下,性能与myBatis持平。在真实情况下,myBatis可能不会在这个地方上配置缓存,会出现脏数据的情况,因而很有可能在此hibernate性能会更好。
5、Spring内部实现机制
Spring 从创建到销毁bean,
1.ResourceLoader 加载配置文件
2.BeanDefinitionReader 解析配置文件,并将其注册到BeanDefinitonRegistry中,此时的beanDefinition是半成品,因为此时还无法对占位符进行解析
3.BeanFactoryPostProcessor从beanDefinitionRegistry中进行进一步加工(解析占位符),并且将实现了PropertyEditor接口的bean注册到PropertyEditorRegistry中
4.通过InstantiationStrategy 和BeanWrapper 完成bean的实例化,并进行属性的注入
5.通过BeanPostProcessor对bean进行进一步加工一个完整的bean就诞生
6、Ioc和aop底层如何实现
1.IoC(Inversion of Control)
(1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系;IoC还有另外一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。
(2). 在Spring的工作方式中,所有的类都会在spring容器中登记,告诉spring这是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
(3). 在系统运行中,动态的向某个对象提供它所需要的其他对象。
(4). 依赖注入的思想是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。总而言之,在传统的对象创建方式中,通常由调用者来创建被调用者的实例,而在Spring中创建被调用者的工作由Spring来完成,然后注入调用者,即所谓的依赖注入or控制反转。注入方式有两种:依赖注入和设置注入; IoC的优点:降低了组件之间的耦合,降低了业务对象之间替换的复杂性,使之能够灵活的管理对象。
2.AOP(Aspect Oriented Programming)
(1). AOP面向方面编程基于IoC,是对OOP的有益补充;
(2). AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,比如日志记录,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
(3). AOP代表的是一个横向的关系,将“对象”比作一个空心的圆柱体,其中封装的是对象的属性和行为;则面向方面编程的方法,就是将这个圆柱体以切面形式剖开,选择性的提供业务逻辑。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹,但完成了效果。
(4). 实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
(5). Spring实现AOP:JDK动态代理和CGLIB代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。 CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;需要引入包asm.jar和cglib.jar。使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是通过动态代理实现的。
7、注解开发代码怎么写的,问注解里面是怎么实现的?
注解的定义通过@interface符号,注解中有属性,可以设置默认值,value是特殊属性,可以在单个赋值省略。注解是用来取代配置文件的的,通过反射获取注解属性后进行操作。
8、JQuery 和ext的区别
JQuery是现在世界上使用最多的javascript库。是对JS的封装,很多前端框架是基于jQuery实现的比如,EasyUI,LayUI等,是免费的。而Ext是一套富客户端(rich client)框架,源自Yahoo UI社区。EXT完全基于JavaScript、css和HTML实现,与主流浏览器完全兼容,并且无需安装任何插件即可在常用浏览器中创建出绚丽的页面效果。商业收费版本功能更为强大。是重量级的前端框架。说的更通俗一点就是:Jquery是一款轻量级的js库,适用于前台web动态页面的设计,而ExtJS则是一款重量级的富客户端js库,更适用于类似后台管理页面的那种动态页面效果的设计。

9、Ext 能实现哪些jQuery 实现不了的
Jquery适合小型灵活的web应用,比如新闻发布系统动态页面设计,门户网站动态页面设计,SNS动态页面等web系统设计;特点是使用简单明了,可以简单快捷的实现某个效果,比如为了实现某一个动态特效,我们可以迅速定位到使用jquery的某一技术或者找到相应的插件来实现。Jquery的设计理念就是写最少的代码实现更多的功能。缺点是插件缺乏统一的管理,用户往往为了实现某一个特效而苦苦纠结与css,还有js的效果逻辑。
而Ext则提供了丰富的完整的一套UI组件,以及组件对应的CSS包(这里强调一下,是一套),就必须深入理解ext的中心思想,理解组件之间嵌套后的关系,以及理解ext生成DOM对象的顺序。特点是功能提供全,使得开发者解放于界面设计,更多的工作去实现业务逻辑方面的事情,缺点是要想灵活运用有一定的难度,尤其是当遇到Ext的Bug的时候。ExtJS适用于那些富客户端应用:比如OA系统,ERP系统,MIS系统等富客户端应用的动态页面设计。
10、Ioc通过一个注解实现依赖注入,里面代码是怎么实现的?
五步:1通过读取配置文件bean节点信息获取class
2 反射创建对象信息
3 获取字节码中的私有字段或者公有属性
4判断是否有指定注解类型
5 有指定就反射赋值
11、前端向后端可以发请求,后端怎么向前端抛消息?
看起来响应的方式有很多,但本质上只有流的形式传输,比如文件下载,XML数据响应,JSON数据,由前端JS解析数据,如果是java中还可以传输对象数据给模板引擎,由模板引擎解析数据。
六、昆山妈妈好面试题
1、线程的启动停止,如何同步
线程的启动是通过start()方法,区别与run(),停止线程的方式有四种:
1 使用stop方法强行终止,但是不推荐这个方法,因为stop()和suspend()及resume()一样都是过期作废的方法。
2 使用interrupt方法中断线程。
3 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
4 wait(),sleep()暂时停止线程
2、保证线程同步的方式可以通过以下7种方式:
1.同步方法
即有synchronized关键字修饰的方法。
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,
内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类
2.同步代码块
即有synchronized关键字修饰的语句块。
被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
注:同步是一种高开销的操作,因此应该尽量减少同步的内容。
通常没必要同步整个方法,使用synchronized代码块同步关键代码即可。
3.使用特殊域变量(volatile)实现线程同步
a.volatile关键字为域变量的访问提供了一种免锁机制,
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它不能用来修饰final类型的变量
4.使用重入锁实现线程同步
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁,
它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力
5.使用局部变量实现线程同步
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
6.使用阻塞队列实现线程同步
前面5种同步方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。使用javaSE5.0版本中新增的java.util.concurrent包的LinkedBlockingQueue来实现线程的同步将有助于简化开发。
7.使用原子变量实现线程同步
需要使用线程同步的根本原因在于对普通变量的操作不是原子的。

  1. 同步用final修饰的区别
    final修饰过后的同步方法子类不能重写
    3、springmvc的请求流程
    第一步:发起请求到前端控制器(DispatcherServlet)
    第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找)
    第三步:处理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多个HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略
    第四步:前端控制器调用处理器适配器去执行Handler
    第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
    第六步:Handler执行完成给适配器返回ModelAndView
    第七步:处理器适配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一个底层对象,包括 Model和view)
    第八步:前端控制器请求视图解析器去进行视图解析(根据逻辑视图名解析成真正的视图(jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
    第九步:视图解析器向前端控制器返回View
    第十步:前端控制器进行视图渲染(视图渲染将模型数据(在ModelAndView对象中)填充到request域)
    第十一步:前端控制器向用户响应结果
    4、前端是否使用静态页面
    是的,因为使用静态页面会提高响应的速度,为实现前后端的分离提供可能性。
    5、前端框架
    VUE,React,Bootstrap,Jquery,JqueryEasyUI,Ext等
    6、springboot介绍
    springboot是纯以注解开发的,配置文件默认application.properties/yml,
    Spring Boot作为微服务的入门级微框架,有四点好处
  1. Spring Boot使编码变简单
  2. Spring Boot使配置变简单
  3. Spring Boot使部署变简单
  4. Spring Boot使监控变简单
    7、web.xml的作用
    web.xml文件是用来初始化配置信息:比如Welcome页面、servlet、servlet-mapping、filter、listener、启动加载级别等。当web工程没用到这些时,可以不用web.xml文件来配置的Application。也可以使用注解取代。每个xml文件都有定义它书写规则的Schema文件,也就是说javaEE的定义web.xml所对应的xml Schema文件中定义了多少种标签元素,web.xml中就可以出现它所定义的标签元素,也就具备哪些特定的功能。web.xml的模式文件是由Sun 公司定义的,每个web.xml文件的根元素为中,必须标明这个web.xml使用的是哪个模式文件。
    web.xml的模式文件中定义的标签并不是定死的,模式文件也是可以改变的,一般来说,随着web.mxl模式文件的版本升级,里面定义的功能会越来越复杂,标签元素的种类肯定也会越来越多。
    8、线程在非同步方法的停止方法
    停止线程的方式有四种:
    1 使用stop方法强行终止,但是不推荐这个方法,因为stop()和suspend()及resume()一样都是过期作废的方法。
    2 使用interrupt方法中断线程。
    3 使用thread.interrupt退出标志,使线程正常退出,也就是当run方法完成后线程终止
    4 wait(),sleep()暂时停止线程
    8、过滤器的作用
    过滤器就是可以对浏览器向控制器资源发出请求和服务器回应给浏览器的内容进行过滤。这个过滤过程中可以拦截浏览器发出的请求和服务器回应给浏览器的内容。拦截之后,就可以进行查看,并且可以对拦截内容进行提取,或者进行修改。过滤器拦截请求和响应,以便查看,提取或操作客户机和服务器之间交换数据。
    9、cloud
    云是什么?通常云计算。云计算是分布式处、并行处理和网格计算的发展。云是云技术的意思,是分布式计算技术的一种,云技术(Cloud technology)是基于云计算商业模式应用的网络技术、信息技术、整合技术、管理平台技术、应用技术等的总称,可以组成资源池,按需所用,灵活便利。
    云技术最基本的概念,是透过网络将庞大的计算处理程序自动分拆成无数个较小的子程序,再交由多部服务器所组成的庞大系统经搜寻、计算分析之后将处理结果回传给用户。透过这项技术,网络服务提供者可以在数秒之内,达成处理数以千万计甚至亿计的信息,达到和“超级计算机”同样强大效能的网络服务。
    云计算技术体系结构分为4层:物理资源层、资源池层、管理中间件层和SOA构建层,如图所示。物理资源层包括计算机、存储器、网络设施、数据库和软件等。
    10、数据库读写分离的实现
    随着用户量的增多,数据库操作往往会成为一个系统的瓶颈所在,而且一般的系统“读”的压力远远大于“写”,因此我们可以通过实现数据库的读写分离来提高系统的性能。实现思路
    通过设置主从数据库实现读写分离,主数据库负责“写操作”,从数据库负责“读操作”,根据压力情况,从数据库可以部署多个提高“读”的速度,借此来提高系统总体的性能。
    要实现读写分离,就要解决主从数据库数据同步的问题,在主数据库写入数据后要保证从数据库的数据也要更新。
    11、主从数据库同步的实现思路:
    主服务器master记录数据库操作日志到Binary log,从服务器开启i/o线程将二进制日志记录的操作同步到relay log(存在从服务器的缓存中),另外sql线程将relay log日志记录的操作在从服务器执行。
    主从数据库设置的具体步骤
    首先要有两个数据库服务器配置主从关系master、slave(也可以用一个服务器安装两套数据库环境运行在不同端口,slave也可以举一反三设置多个) ,接下来的问题就是在业务代码里面实现读写分离,在配置文件配置两个具体的数据源master、slave,继承了abstractDataSource,这里面就配置了数据库连接的具体属性,然后配置了动态数据源,他将决定使用哪个具体的数据源,这里面的关键就是DataSourceSelector,接下来实现这个bean。下一步设置了数据源的懒加载,保证在数据源加载的时候其他依赖的bean已经加载完成。
    七、支付宝蚂蚁金服
    1、String Stringbuffer Stringbuilder
    String类被final修饰,所以不可继承,String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间;
    StringBuffer是可变类和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量,用于多线程操作字符串
    StringBuilder是可变类和线程不安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量,用于单线程操作字符串
    2、Dubbox工作原理
    通过配置中心,和每个Server/Client之间会作一个实时的心跳检测(因为它们都是建立的Socket长连接),比如几秒钟检测一次。收集每个Server提供的服务的信息,每个Client的信息,整理出一个服务列表,当某个Server不可用,那么就更新受影响的服务对应的serverAddressList,即把这个Server从serverAddressList中踢出去(从地址列表中删除),同时将推送serverAddressList给这些受影响的服务的clientAddressList里面的所有Client。如:192.168.0.3挂了,那么UserService和ProductService的serverAddressList都要把192.168.0.3删除掉,同时把新的列表告诉对应的Client,当某个Client挂了,那么更新受影响的服务对应的clientAddressLis,ConfigServer根据服务列表,就能提供一个web管理界面,来查看管理服务的提供者和使用者。新加一个Server时,由于它会主动与ConfigServer取得联系,而ConfigServer又会将这个信息主动发送给Client,所以新加一个Server时,只需要启动Server,然后几秒钟内,Client就会使用上它提供的服务Client调用服务的机器,每个Client启动时,主动与ConfigServer建立Socket长连接,并将自己的IP等相应信息发送给ConfigServer。Client在使用服务的时候根据服务名称去ConfigServer中获取服务提供者信息(这样ConfigServer就知道某个服务是当前哪几个Client在使用),Client拿到这些服务提供者信息后,与它们都建立连接,后面就可以直接调用服务了,当有多个服务提供者的时候,Client根据一定的规则来进行负载均衡,如轮询,随机,按权重等。一旦Client使用的服务它对应的服务提供者有变化(服务提供者有新增,删除的情况),ConfigServer就会把最新的服务提供者列表推送给Client,Client就会依据最新的服务提供者列表重新建立连接,新增的提供者建立连接,删除的提供者丢弃连接,Server真正提供服务的机器,每个Server启动时,主动与ConfigServer建立Scoket长连接,并将自己的IP,提供的服务名称,端口等信息直接发送给ConfigServer,ConfigServer就会收集到每个Server提供的服务的信息。
    3、Nginx网段配置
    通过nginx模块ngx_http_access_module的指令deny和allow控制某个uri或者一个路径不让人访问。这个模块内置在了nginx中,nginx的访问控制模块语法很简单,
    allow
    语法: allow address | CIDR | unix: | all;
    默认值: —
    配置段: http, server, location, limit_except
    允许某个ip或者一个ip段访问.如果指定unix:,那将允许socket的访问.注意:unix在1.5.1中新加入的功能,如果你的版本比这个低,请不要使用这个方法。
    deny
    语法: deny address | CIDR | unix: | all;
    默认值: —
    配置段: http, server, location, limit_except
    禁止某个ip或者一个ip段访问.如果指定unix:,那将禁止socket的访问.注意:unix在1.5.1中新加入的功能,如果版本比这个低,请不要使用这个方法。
    4、数据表索引的必要性
    索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。表里面的记录数量越多,这个操作的代价就越高。如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置。如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍。
    索引是对数据库表中一个或多个列(例如,employee表的姓氏(lname)列)的值进行排序的结构。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。
    索引提供指针以指向存储在表中指定列的数据值,然后根据指定的排序次序排列这些指针。数据库使用索引的方式与使用书的目录很相似:通过搜索索引找到特定的值,然后跟随指针到达包含该值的行。
    在数据库关系图中,可以为选定的表创建、编辑或删除索引/键属性页中的每个索引类型。当保存附加在此索引上的表或包含此表的数据库关系图时,索引同时被保存。
    通常情况下,只有当经常查询索引列中的数据时,才需要创建索引。索引将占用磁盘空间,并且降低添加、删除和更新行的速度。不过在多数情况下,索引所带来的数据检索速度的优势大大超过它的不足之处。然而,如果应用程序非常频繁地更新数据,或磁盘空间有限,那么最好限制索引的数量。
    5、分布式不使用redis和cookie和session怎么多服务器共享用户登录状态
    分布式下无法使用cookiea实现多服务器共享用户登录状态,因此分布式环境下需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录。单点登录全称Single Sign On(以下简称SSO),是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,包括单点登录与单点注销两部分,相比于单系统登录,sso需要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。这个过程,也就是单点登录的原理。
    6、数据库存储模式
    数据库系统采用三级模式结构,这是数据库管理系统内部的系统结构。
    数据库系统设计员可在视图层、逻辑层和物理层对数据抽象,通过外模式、概念模式和内模式来描述不同层次上的数据特性。

概念模式也称模式,是数据库中全部数据的逻辑结构和特征的描述,它由若干个概念记录类型组成,只涉及行的描述,不涉及具体的值。概念模式的一个具体值称为模式的一个实例,同一个模式可以有很多实例。
概念模式反映的是数据库的结构及其联系,所以是相对稳定的;而实例反映的是数据库某一时刻的状态,所以是相对变动的。
需要说明的是,概念模式不仅要描述概念记录类型,还要描述记录间的联系、操作、数据的完整性和安全性等要求。但是,概念模式不涉及存储结构、访问技术等细节。只有这样,概念模式才算做到了“物理数据独立性”。
描述概念模式的数据定义语言称为“模式DDL”
外模式也称用户模式或子模式,是用户与数据库系统的接口,是用户用到的那部分数据的描述。它由若干个外部记录类型组成。用户使用数据操纵语言对数据库进行操作,实际上是对外模式的外部记录进行操作。
描述外模式的数据定义语言称为“外模式DDL”。有了外模式后,程序员不必关心概念模式,只与外模式发生联系,按外模式的结构存储和操作数据。
内模式也称为存储模式,是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。需要定义所以的内部记录类型、索引和文件的组织方式,以及数据控制方面的细节。
例如,记录的存储方式是顺序存储、B树结构存储还是Hash方法存储;索引按照什么方式组织;数据是否压缩存储,是否加密;数据的存储记录结构有何规定。
需要说明的是,内部记录并不涉及物理记录,也不涉及设备的约束。比内模式更接近于物理存储和访问的那些软件机制是操作系统的一部分(即文件系统)。例如,从磁盘上读、写数据。
描述内模式的数据定义语言称为“内模式DDL”。
总之,数据按外模式的描述提供给用户;按内模式的描述存储在磁盘上;而概念模式提供了连接这两级模式的相对稳定的中间层,并使得两级中任意一级的改变都不受另一级的牵制。
数据库系统在三级模式之间提供了两级映像:模式/内模式的映像、外模式/模式的映像。这两级映射保证了数据库中的数据具有较高的物理独立性和逻辑独立性。
7、InnoDB是哪种读取类型
InnoDB给MySQL的表提供了事务处理、回滚、崩溃修复能力和多版本并发控制的事务安全。在MySQL从3.23.34a开始包含InnnoDB。它是MySQL上第一个提供外键约束的表引擎。而且InnoDB对事务处理的能力,也是其他存储引擎不能比拟的。靠后版本的MySQL的默认存储引擎就是InnoDB。
InnoDB的优势在于提供了良好的事务处理、崩溃修复能力和并发控制。缺点是读写效率较差,占用的数据空间相对较大。

  1. 复合索引只选择一部分,查询是否能命中
    看情况,因为联合索引是由多个字段组成的索引,查询时使用联合索引的一个字段,如果这个字段在联合索引中所有字段的第一个,那就会用到索引,否则就无法使用到索引。
    8、数据库中事务锁
    事务和锁的存在都是为了更好的解决并发访问造成的数据不一致性的的问题乐观锁和悲观锁都是为了解决并发控制问题,乐观锁可以认为是一种在最后提交的时候检测冲突的手段,而悲观锁则是一种避免冲突的手段。乐观锁:是应用系统层面和数据的业务逻辑层次上的(实际上并没有加锁,只不过大家一直这样叫而已),利用程序处理并发,它假定当某一个用户去读取某一个数据的时候,其他的用户不会来访问修改这个数据,但是在最后进行事务的提交的时候会进行版本的检查,以判断在该用户的操作过程中,没有其他用户修改了这个数据。开销比较小乐观锁的实现大部分都是基于版本控制实现的,除此之外,还可以通过时间戳的方式,通过提前读取,事后对比的方式实现
    9、乐观锁的优势和劣势
    优势:如果数据库记录始终处于悲观锁加锁状态,可以想见,如果面对几百上千个并发,那么要不断的加锁减锁,而且用户等待的时间会非常的长,乐观锁机制避免了长事务中的数据库加锁解锁开销,大大提升了大并发量下的系统整体性能表现所以如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以建议就要选择乐观锁定的方法,而如果并发量不大,完全可以使用悲观锁定的方法。乐观锁也适合于读比较多的场景。
    劣势:但是乐观锁也存在着问题,只能在提交数据时才发现业务事务将要失败,如果系统的冲突非常的多,而且一旦冲突就要因为重新计算提交而造成较大的代价的话,乐观锁也会带来很大的问题,在某些情况下,发现失败太迟的代价会非常的大。而且乐观锁也无法解决脏读的问题
    10、互联网高并发小轻快如何实现
    不是很清楚,能跟我说说吗?拆分业务使用微服架构变小?使用成熟框架变轻?使用各种优化提高性能变快?
    11、数据库优化
    随着系统规模的不断增加,数据量和并发量不断增大,整个系统架构中最先受到冲击而形成瓶颈的,定然是数据库,因此数据库层面的优化,是一个程序员不可或缺的技能,下面就是一些优化方式:
    1、索引,建立索引是数据库优化各种方案之中成本最低,见效最快的解决方案,一般来讲,数据库规模在几十万和几百万级别的时候见效最快,即便是有不太复杂的表关联,也能大幅度提高sql的运行效率,这个在我们以前的项目应用中,有非常深刻的体会,本来耗时50s的sql,在增加索引后可以提升到1-2s,而且不需要有代码改动,成本低廉,见效明显
    2、分库分表分区
    分库,可以按照业务分库,分流数据库并发压力,使数据库表更加有条理性,最起码更加好找吧,我们当时是把查询库和系统库(增删改比较频繁的表)分开了,这样如果有大查询,不影响系统库
    分表,刚才说了,索引适合应对百万级别的数据量,千万级别数据量使用的好,勉强也能凑合,但如果是上亿级别的数据量,索引就无能为力了,因为单索引文件可能就已经上百兆或者更多了,那么,轮到我们的分表分区登场了
    分区
    分区的实现道理和分表一样,也是将相应规则的数据放在一起,唯一不同的是分区你只需要设定好分区规则,插入的数据会被自动插入到指定的区里,当然查询的时候也能很快查询到需要区,相当于是分表对外透明了,出现跨表数据库自动帮我们合并做了处理,使用起来比分表更加方便,但是分区也有自己的问题,每一个数据库表的并发访问是有上限的,也就是说,分表能够抗高并发,而分区不能,如何选择,要考虑实际情况

3、数据库引擎
mysql比较常用的数据库引擎有两种,一种是innodb、一种是myisam 一个千万级数据量复杂sql测试,myisam的效率大概能够比innodb快1-2倍,虽然效率提升不是很明显,但是也有提——之所以mysiam快,是因为他的数据存储结构、索引存储结构和innodb不一样的,mysiam的索引结构是在内存中存的当然,mysiam也有弱点,那就是是表级锁,而innodb是行级锁,所以,mysiam适用于一次插入,多次查询的表,或者是读写分离中的读库中的表,而对于修改插入删除操作比较频繁的表,就很不合适了

4、预处理
一般来说,实时数据(当天的数据)还是比较有限的,真正数据量比较大的是历史数据,基于大表历史数据的查询,如果再涉及一些大表关联,这种sql是非常难以优化的
5、like查询
大家都知道,like “%str%” 不支持索引,"str%"号是支持索引的因此,如果业务允许,可以使用前匹配的方法是数据库快速定位到数据,在结果集中再进行like匹配,如果这个结果集不是很大,是可以大幅提升运行效率的,这个需要对业务和程序有灵活的变通,如果业务实在不允许前匹配,那就可以采用solr或者elastisearch来进行模糊匹配,但是进行模糊匹配有个前提,原始数据是字符串的话,不要带有特殊符号,如#,&,% 等,这样会造成分词不准,最终导致查询结果不正确
6、读写分离
在数据库并发大的情况下,最好的做法就是进行横向扩展,增加机器,以提升抗并发能力,而且还兼有数据备份功能
12、Docker
Docker 是一个开源的应用容器引擎,基于 Go 语言并遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。它的好处是:
1、简化程序:
Docker 让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,便可以实现虚拟化。Docker改变了虚拟化的方式,使开发者可以直接将自己的成果放入Docker中进行管理。方便快捷已经是 Docker的最大优势,过去需要用数天乃至数周的 任务,在Docker容器的处理下,只需要数秒就能完成。
2、避免选择恐惧症:
如果你有选择恐惧症,还是资深患者。Docker 帮你 打包你的纠结!比如 Docker 镜像;Docker 镜像中包含了运行环境和配置,所以 Docker 可以简化部署多种应用实例工作。比如 Web 应用、后台应用、数据库应用、大数据应用比如 Hadoop 集群、消息队列等等都可以打包成一个镜像部署。
3、节省开支:
一方面,云计算时代到来,使开发者不必为了追求效果而配置高额的硬件,Docker 改变了高性能必然高价格的思维定势。Docker 与云的结合,让云空间得到更充分的利用。不仅解决了硬件管理的问题,也改变了虚拟化的方式。
2. MySQL 是哪种读取方式
不好意思,能给我谈谈什么是数据库的读取方式吗?如果说是存储引擎的话,我知道MYSQL有 MYISAM 存储引擎,是没有事务的,适合做查询,比较快,还有一种的数据存储引擎innodb,是有事务的,适合做增删改。
八、公司笔试题

1、多线程Hashmap死循环的操作是由于哪一步
HashMap是采用链表解决Hash冲突,因为是链表结构,那么就很容易形成闭合的链路,这样在循环的时候只要有线程对这个HashMap进行get操作就会产生死循环。 在单线程情况下,只有一个线程对HashMap的数据结构进行操作,是不可能产生闭合的回路的。那就只有在多线程并发的情况下才会出现这种情况,那就是在put操作的时候,如果size>initialCapacity*loadFactor,那么这时候HashMap就会进行rehash操作,随之HashMap的结构就会发生翻天覆地的变化。很有可能就是在两个线程在这个时候同时触发了rehash操作,产生了闭合的回路。
2、讲述一下Hashmap的实现原理
HashMap的工作原理:HashMap是基于散列法(又称哈希法hashing)的原理,使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket(桶)位置来储存Entry对象。”HashMap是在bucket中储存键对象和值对象,作为Map.Entry。并不是仅仅只在bucket中存储值。
3、List的实现类有哪些
1、ArrayList非线程安全 基于对象数组
get(int index)不需要遍历数组,速度快;
iterator()方法中调用了get(int index),所以速度也快
set(int index, E e)不需要遍历数组,速度快
add方法需要考虑扩容与数组复制问题,速度慢
remove(Object o)需要遍历数组,并复制数组元素,速度慢
remove(int index)不需要遍历数组,需要复制数组元素,但不常用
contain(E)需要遍历数组
2、LinkedList 非线程安全 基于环形双向链表
get(int index)需要遍历链表,速度慢;
iterator()方法中调用了get(int index),所以速度也慢
set(int index, E e)方法中调用了get(int index),所以速度也慢
add方法不需要考虑扩容与数组复制问题,只需创建新对象,再将新对象的前后节点的指针指向重新分配一下就好,速度快
remove(Object o)需要遍历链表,但不需要复制元素,只需将所要删除的对象的前后节点的指针指向重新分配一下以及将所要删除的对象的三个属性置空即可,速度快
remove(int index)需要遍历链表,但不需要复制元素,只需将所要删除的对象的前后节点的指针指向重新分配一下以及将所要删除的对象的三个属性置空即可,但不常用
contain(E)需要遍历链表
3、Vector(线程安全的ArrayList)
扩容机制与ArrayList不同
4、Stack(继承于Vector)线程安全
效率低下,可采用双端队列Deque或LinkedList来实现,Deque用的较多

  1. Redis有哪些数据类型
    Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
  2. 消息队列是如何进行消费的
    JMS规范目前支持两种消息模型:点对点(point to point, queue)和发布/订阅(publish/subscribe,topic)在点对点模式中,消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息。消息被消费以后,queue中不再有存储,所以消息消费者不可能消费到已经被消费的消息。Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。
    4、微信支付宝银联的接入流程
  3. 使用Dobbox开发如何提供http协议的接口
  4. Springboot如何用最简单的方法读其它的配置文件
    使用注解@PropertySource@Value
  5. Dobbox如何优化
    先查看资源使用有没有出现瓶颈的地方。根据监控信息显示从以下几个方面来分析问题。
    •整体环境
    •CPU:
    •内存:
    •网络:
    •线上网络利用率
    •程序环境
    5、Maven的操作命令你知道的有哪些
    七大常用,三大生命周期,clean,compile,test,package,site,install,deploy
    6、谈谈高并发的测试
    通过Apache的JMetty高并发测试软件工具实现测试
    7、你知道哪些算法
    1.快速排序算法
    归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
    二分查找算法是一种在有序数组中查找某一特定元素的搜索算法。搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。折半搜索每次把搜索区域减少一半,时间复杂度为Ο(logn) 。
    BFPRT算法解决的问题十分经典,即从某n个元素的序列中选出第k大(第k小)的元素,通过巧妙的分析,BFPRT可以保证在最坏情况下仍为线性时间复杂度。该算法的思想与快速排序思想相似。
    2.深度优先搜索算法(Depth-First-Search),是搜索算法的一种。
    广度优先搜索算法(Breadth-First-Search),是一种图形搜索算法。简单的说,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。BFS同样属于盲目搜索。一般用队列数据结构来辅助实现BFS算法。
    戴克斯特拉算法(Dijkstra’s algorithm)是由荷兰计算机科学家艾兹赫尔·戴克斯特拉提出。迪科斯彻算法使用了广度优先搜索解决非负权有向图的单源最短路径问题,算法最终得到一个最短路径树。该算法常用于路由算法或者作为其他图算法的一个子模块。
    2.动态规划算法
    朴素贝叶斯分类算法
  6. 使用的ORM框架有什么
    hibernate全自动化ORM,ibatis,Mybatis半自动化ORM,Jfinal等
    8、Mybatis分页插件有了解吗
    有,PageHelper实现了通用的分页查询,其支持的数据有,mysql、Oracle、DB2、PostgreSQL等主流的数据库
    9、全局异常怎么实现
    springMVC中配置全局异常解析器SimpleMappingExceptionResolver即可对所有异常进行统一处理。
    10、进行抢购时你们redis的键是怎么设计的
    用设备来源拼接用户信息拼接商品主键拼接随机串,比如pc-2ad67f912a7a87a-1-adf5da5,用来存储用户信息和商品信息保证唯一性
    九、公司面试题
    11、锁的原理
    为了保证共享数据在同一时刻只被一个线程使用,我们有一种很简单的实现思想,就是在共享数据里保存一个锁,当没有线程访问时,锁是空的。当有第一个线程访问时,就在锁里保存这个线程的标识并允许这个线程访问共享数据。在当前线程释放共享数据之前,如果再有其他线程想要访问共享数据,就要等待锁释放。
    12、同步代码块和方法加锁的区别
    同步方法是直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好
    13、mybatis懒加载的原理
    mybatis 其实第一步是解析配置文件,把配置文件映射为 mybatis 的 Configuration 类,把配置文件的 xml 属性都映射为 Java 对象中的属性值。xml mapper 文件的处理比较复杂,< resultMap/>标签映射为 ResultMap 对象,标签中的< id/>、< result/>、< association/>等映射为 ResultMapping 对象。接着再讲创建好 result 对象之后,mybatis 会循环 resultMappings(标签中的每个子标签都映射为一个 resultMapping,这些 resultMapping 组成了一个集合就是 resultMappings)集合,看有没有需要懒加载的属性,如果有的话,则会为这个 result 对象创建一个代理对象。什么情况下才会出现需要懒加载的属性呢?只有< association property=”author” column=”author_id” select=”selectAuthor” fetchType=”lazy”/>和< collection property=”xxx” column=”xxx” select=”xxxx” fetchType=”lazy”/>作为一个子标签出现在< resultMap/>标签(也不一定只是< resultMap/>标签,< collection/>等标签事实上也算是一个< resultMap/>标签)之内才会出现需要懒加载的属性。select 属性和 fetchType=”lazy” 必须同时出现在< collection/>或< association/>属性中才需要懒加载,select 表示的是嵌套查询语句的 id ,fetchType=”lazy” 表示的是懒加载。
    14用什么技术代替存储过程
    为什么要取代存储过程?如果不用存储过程,那只要java技术好,逻辑严谨,业务规范,就可以通过代码的形式控制业务从而用来代替存储过程

其他面试题

1、高并发解决方案:
参考文档:https://www.cnblogs.com/cn-sbo/p/10853469.html
https://www.cnblogs.com/donghang/p/9233796.html

  1. 流量优化:防盗链处理

Web资源防盗链处理解决方案:
通过请求头中的referer或者签名,网站可以检测目标网页访问的来源网页.

  1. 前端优化:减少HTTP请求,合并css或js,添加异步请求,启用浏览器缓存和文件压缩,CDN加速,建立独立图片服务器.

2.1. 减少HTTP请求次数
2.2. 浏览器缓存和数据压缩优化
2.3. CDN加速
2.4. 建立独立的图片服务器

  1. 服务端优化:页面静态化,并发处理,队列处理,集群和分布式

页面静态化:服务器返回json格式数据
并发处理:线程池分布式锁
队列处理:Kafka,ActiveMQ,ZeroMQ,RabbitMQ,Redis
集群和分布式:采用微服务架构

  1. 数据库优化:数据库缓存,分库分表,分区操作,读写分离,负载均衡

数据库中间件MyCat

  1. web服务器优化:负载均衡,nginx反向代理,7,4层LVS软件

反向代理:就是客户端访问的服务器不直接提供资源,该服务器从别的服务器获取资源并返回给用户主要由3个作用
  1.可以负载均衡
  2.可以转发请求
  3.可以作为前端服务器和实际请求服务器集成。

2、数据库优化思路:

  1. 根据服务层面:配置mysql性能优化参数;
  2. 从系统层面增强mysql的性能:优化数据表结构、字段类型、字段索引、分表,分库、读写分离等等。
  3. 从数据库层面增强性能:优化SQL语句,合理使用字段索引
  4. 从代码层面增强性能:使用缓存和NoSQL数据库方式存储
    MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力
  5. 不常使用的数据迁移备份,避免每次都在海量数据中去检索。
  6. 提升数据库服务器硬件配置,或者搭建数据库集群

3、常用的中间件:

  1. 数据库中间件mycat druid
  2. 消息中间件rabbitmq ActiveMQ

4、关于事务的面试题:
一、什么是事务?有什么用?事务的特性ACID
事务提供了一种机制,可用来将一系列数据库更改归入一个逻辑操作。更改数据库后,所做的更改可以作为一个单元进行提交或取消。事务可确保遵循原子性、一致性、隔离性和持续性(ACID)这几种属性,以使数据能够正确地提交到数据库中。
1)原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作 要么都发生,要么都不发生。
2)一致性(Consistency)一个事务中,事务前后数据的完整性必须保持一致。
3)隔离性(Isolation)多个事务,事务的隔离性是指多个用户并发访问数据库时, 一个用户的 事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
4)持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变 就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

二 事务的并发会产生的问题有哪些
1.脏读
一个事务正在对数据进行更新操作,但是更新还未提交,另一个事务这时也来操作这组数据,并且读取了前一个事务还未提交的数据,而前一个事务如果操作失败进行了回滚,后一个事务读取的就是错误的数据,这样就造成了脏读
2.不可重复读
一个事务多次读取同一个数据,在该事务还未结束时,另一个事务也对该数据进行 了操作,而且在第一个事务两次读取之间,第二个事务对数据进行了更新,那么第一个 事务前后两个读取到的数据是不同的,这样就造成了不可重复读
3.幻读
第一个数据正在查询某一条数据,这时,另一个事务又插入了一条符合条件的数据,第一个事务在第二次查询符合同一条件的数据时,发现多了一条前一次查询时没有的数据,仿佛幻觉一样,这就是幻读

三 不可重复读和幻读的区别
不可重复读是指在同一查询事务中多次进行,由于其他提交事务所做的修改和删除,每次返回不同的结果集,此时发生不可重复读
幻读是指在同一查询事务中多次进行,由于其他提交的事务所做的插入操作,每次返回不同的结果集,此时发生幻读表面上看,区别就在于不可重复读能看见其他事务提交的修改和删除,而幻读能看见其他事务提交的插入

四、spring 事务隔离级别
1.default:(默认)
默认隔离级别,使用数据库默认的事务隔离级别
2.read_uncommitted:(读未提交)
这是事务最低的隔离级别,他允许另外一个事务可以看到这个事务未提交的数据,这种隔离级别会产生脏读,不可重复读和幻读
3.read_committed(读已提交)
保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据.这种事务隔离级别可以避免脏读,但是可能会出现不可重复读和幻读
4.repeatable_read(可重复读)
这种事务级别可以防止脏读,不可重复读.但是可能出现幻读.他除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读
5.Serializable 串行化
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。防止了脏读、不可重复读、幻读

总结:
脏读 不可重复读 幻读
读未提交 会 会 会
读已提交 不会 会 会
可重复读 不会 不会 会
串行化 不会 不会不会

五、spring事务的传播行为
1.requierd
如果有事务那么加入事务,没有的话新建一个
2.not_supported
不开启事务
3.requires_new
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完,继续执行老事务
4.mandatory
必须在一个已有的事务中执行,否则抛出异常
5.never
必须在一个没有的事务中执行,否则抛出异常
6.supports
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务那就不用事务

六 Spring声明式事务的回滚机制
在Spring 的事务框架中推荐的事务回滚方法是,在当前执行的事务上下文中抛出一个异常。如果异常未被处理,当抛出异常调用堆栈的时候,Spring 的事务框架代码将捕获任何未处理的异常,然后并决定是否将此事务标记为回滚。
在默认配置中,Spring 的事务框架代码只会将出现runtime, unchecked 异常的事务标记为回滚;也就是说事务中抛出的异常时RuntimeException或者是其子类,这样事务才会回滚(默认情况下Error也会导致事务回滚)。在默认配置的情况下,所有的 checked 异常都不会引起事务回滚。如果有需要,可以通过rollback-for 和no-rollback-for进行指定。

七 分布式环境下如何处理事务
分布式事务处理是很难保证acid的。一般做法是牺牲一致性,满足可用性和分区容错。采用的方式可以是二阶段提交,由于二阶段提交存在着诸如同步阻塞、单点问题、数据不一致、宕机等缺陷,所以还可以采用TCC(补偿事务)的方式实现,TCC核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段,本质也是2阶段提交,缺点也比较明显的,在确认和补偿时都有可能失败,一些业务流程可能用TCC不太好定义及处理。分布式事务还可以基于 mq(消息队列)/rpc(远程方法调用)实现最终一致性。还有Mycat可以通过用户会话Session中设置autocommit=false启动事务,通过设置ServerConnection中变量txInterrupted=true来控制是否事务异常需要回滚。在Mycat中的事务是一种二阶段提交事务方式,但是从实际应用场景出发这种出现故障的概率还是比较小的,因此这种实现方式可以满足很多应用需求,但如果出现问题,会很麻烦。但在分库分表,立即可见的应用上是不能满足业务需求的,所以分布式事务需要根据具体业务的需要权衡取舍的。

------------------面试能用自己的语言用自己的理解描述清楚这个---------------
5、微服务架构下处理分布式事务,你必须知道的事儿
根据微服务架构的鼻祖 Martin Fowler 的忠告,微服务架构中应当尽量避免分布式事务。然而,在某些领域,分布式事务如同宿命中的对手无法避免。
根据微服务架构的鼻祖 Martin Fowler 的忠告,微服务架构中应当尽量避免分布式事务。然而,在某些领域,分布式事务如同宿命中的对手无法避免。
在工程领域,分布式事务的讨论主要聚焦于强一致性和最终一致性的解决方案。
典型方案包括:
• 两阶段提交(2PC, Two-phase Commit)方案。
• eBay 事件队列方案。
• TCC 补偿模式。
• 缓存数据最终一致性。
一致性理论
分布式事务的目的是保障分库数据一致性,而跨库事务会遇到各种不可控制的问题,如个别节点永久性宕机,像单机事务一样的 ACID 是无法奢望的。
另外,业界著名的 CAP 理论也告诉我们,对分布式系统,需要将数据一致性和系统可用性、分区容忍性放在天平上一起考虑。
两阶段提交协议(简称2PC)是实现分布式事务较为经典的方案,但 2PC 的可扩展性很差,在分布式架构下应用代价较大,eBay 架构师 Dan Pritchett 提出了 BASE 理论,用于解决大规模分布式系统下的数据一致性问题。
BASE 理论告诉我们:可以通过放弃系统在每个时刻的强一致性来换取系统的可扩展性。
01.CAP 理论
在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)3 个要素最多只能同时满足两个,不可兼得。其中,分区容忍性又是不可或缺的。

• 一致性:分布式环境下,多个节点的数据是否强一致。
• 可用性:分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果。
• 分区容忍性:特指对网络分区的容忍性。
举例:Cassandra、Dynamo 等,默认优先选择 AP,弱化 C;HBase、MongoDB 等,默认优先选择 CP,弱化 A。
02.BASE 理论
核心思想:
• 基本可用(Basically Available):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用。
• 软状态(Soft State):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性。
• 最终一致性(Eventual Consistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态。
一致性模型
数据的一致性模型可以分成以下三类:
• 强一致性:数据更新成功后,任意时刻所有副本中的数据都是一致的,一般采用同步的方式实现。
• 弱一致性:数据更新成功后,系统不承诺立即可以读到最新写入的值,也不承诺具体多久之后可以读到。
• 最终一致性:弱一致性的一种形式,数据更新成功后,系统不承诺立即可以返回最新写入的值,但是保证最终会返回上一次更新操作的值。
分布式系统数据的强一致性、弱一致性和最终一致性可以通过 Quorum NRW 算法分析。
分布式事务解决方案
01.2PC 方案——强一致性
2PC 的核心原理是通过提交分阶段和记日志的方式,记录下事务提交所处的阶段状态,在组件宕机重启后,可通过日志恢复事务提交的阶段状态,并在这个状态节点重试。
如 Coordinator 重启后,通过日志可以确定提交处于 Prepare 还是 Prepare All 状态。若是前者,说明有节点可能没有 Prepare 成功,或所有节点 Prepare 成功但还没有下发 Commit,状态恢复后给所有节点下发 RollBack。
若是 Prepare All 状态,需要给所有节点下发 Commit,数据库节点需要保证 Commit 幂等。

2PC 方案的三个问题:
• 同步阻塞。
• 数据不一致。
• 单点问题。
升级的 3PC 方案旨在解决这些问题,主要有两个改进:
• 增加超时机制。
• 两阶段之间插入准备阶段。
但三阶段提交也存在一些缺陷,要彻底从协议层面避免数据不一致,可以采用 Paxos 或者 Raft 算法。
02.eBay 事件队列方案——最终一致性
eBay 的架构师 Dan Pritchett,曾在一篇解释 BASE 原理的论文《Base:An Acid Alternative》中提到一个 eBay 分布式系统一致性问题的解决方案。
它的核心思想是将需要分布式处理的任务通过消息或者日志的方式来异步执行,消息或日志可以存到本地文件、数据库或消息队列,再通过业务规则进行失败重试,它要求各服务的接口是幂等的。
描述的场景为,有用户表 user 和交易表 transaction,用户表存储用户信息、总销售额和总购买额。交易表存储每一笔交易的流水号、买家信息、卖家信息和交易金额。如果产生了一笔交易,需要在交易表增加记录,同时还要修改用户表的金额。

论文中提出的解决方法是将更新交易表记录和用户表更新消息放在一个本地事务来完成,为了避免重复消费用户表更新消息带来的问题,增加一个操作记录表 updates_applied 来记录已经完成的交易相关的信息。

这个方案的核心在于第二阶段的重试和幂等执行。失败后重试,这是一种补偿机制,它是能保证系统最终一致的关键流程。
03.TCC (Try-Confirm-Cancel)补偿模式——最终一致性
某业务模型如图,由服务 A、服务 B、服务 C、服务 D 共同组成的一个微服务架构系统。服务 A 需要依次调用服务 B、服务 C 和服务 D 共同完成一个操作。
当服务 A 调用服务 D 失败时,若要保证整个系统数据的一致性,就要对服务 B 和服务 C 的 invoke 操作进行回滚,执行反向的 revert 操作。回滚成功后,整个微服务系统是数据一致的。

实现的三个关键要素:
• 服务调用链必须被记录下来。
• 每个服务提供者都需要提供一组业务逻辑相反的操作,互为补偿,同时回滚操作要保证幂等。
• 必须按失败原因执行不同的回滚策略。
实现的两个难点:
• 补偿模式的特点是实现简单,但是想形成一定程度的通用方案比较困难,特别是服务链的记录,因为大部分时候,业务参数或者业务逻辑千差万别。
• 很多业务特征使得该服务无法提供一个安全的回滚操作。
04.缓存数据最终一致性
在我们的业务系统中,缓存(Redis 或者 Memcached)通常被用在数据库前面,作为数据读取的缓冲,使得 I/O 操作不至于直接落在数据库上。
以商品详情页为例,假如卖家修改了商品信息,并写回到数据库,但是这时候用户从商品详情页看到的信息还是从缓存中拿到的过时数据,这就出现了缓存系统和数据库系统中的数据不一致的现象。
要解决该场景下缓存和数据库数据不一致的问题,我们有以下两种解决方案:
• 为缓存数据设置过期时间。当缓存中数据过期后,业务系统会从数据库中获取数据,并将新值放入缓存。这个过期时间就是系统可以达到最终一致的容忍时间。
• 更新数据库数据后,同时清除缓存数据。数据库数据更新后,同步删除缓存中数据,使得下次对商品详情的获取直接从数据库中获取,并同步到缓存。
选择建议
在面临数据一致性问题的时候,首先要从业务需求的角度出发,确定我们对于三种一致性模型的接受程度,再通过具体场景来决定解决方案。
从应用角度看,分布式事务的现实场景常常无法规避,在有能力给出其他解决方案前,2PC 也是一个不错的选择。
对购物转账等电商和金融业务,中间件层的 2PC 最大问题在于业务不可见,一旦出现不可抗力或意想不到的一致性破坏。
如数据节点永久性宕机,业务难以根据 2PC 的日志进行补偿。金融场景下,数据一致性是命根,业务需要对数据有百分之百的掌控力。
建议使用 TCC 这类分布式事务模型,或基于消息队列的柔性事务框架,这两种方案都在业务层实现,业务开发者具有足够掌控力,可以结合 SOA 框架来架构,包括 Dubbo、Spring Cloud 等。

多线程面试题
38、Syngniazed锁的四种状态,怎么演化的

无锁状态、     多个线程同时修改资源,只有一个能成功。
偏向锁状态、   不存在多线程竞争,自动枷锁
轻量级锁状态、 处于偏向锁的状态中,被另一个线程访问,会升级为轻量级锁
重量级锁状态   一个线程获取锁后,其他等待获取线程的锁都会被阻塞。

synchronized原始采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。

高并发面试题:

1、高并发解决方案:
参考文档:https://www.cnblogs.com/cn-sbo/p/10853469.html
https://www.cnblogs.com/donghang/p/9233796.html

  1. 流量优化:防盗链处理

Web资源防盗链处理解决方案:
通过请求头中的referer或者签名,网站可以检测目标网页访问的来源网页.

  1. 前端优化:减少HTTP请求,合并css或js,添加异步请求,启用浏览器缓存和文件压缩,CDN加速,建立独立图片服务器.

7.1. 减少HTTP请求次数
7.2. 浏览器缓存和数据压缩优化
7.3. CDN加速
7.4. 建立独立的图片服务器

  1. 服务端优化:页面静态化,并发处理,队列处理,集群和分布式

页面静态化:服务器返回json格式数据
并发处理:线程池 分布式锁
队列处理:Kafka,ActiveMQ,ZeroMQ,RabbitMQ,Redis
集群和分布式:采用微服务架构

  1. 数据库优化:数据库缓存,分库分表,分区操作,读写分离,负载均衡

数据库中间件 MyCat

  1. web服务器优化:负载均衡,nginx反向代理,7,4层LVS软件

反向代理:就是客户端访问的服务器不直接提供资源,该服务器从别的服务器获取资源并返回给用户主要由3个作用
  1.可以负载均衡
  2.可以转发请求
   3.可以作为前端服务器和实际请求服务器集成。

2、数据库优化思路:
7. 根据服务层面:配置mysql性能优化参数;
8. 从系统层面增强mysql的性能:优化数据表结构、字段类型、字段索引、分表,分库、读写分离等等。
9. 从数据库层面增强性能:优化SQL语句,合理使用字段索引
10. 从代码层面增强性能:使用缓存和NoSQL数据库方式存储
MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力
11. 不常使用的数据迁移备份,避免每次都在海量数据中去检索。
12. 提升数据库服务器硬件配置,或者搭建数据库集群

3、常用的中间件:

  1. 数据库中间件 mycat druid
  2. 消息中间件 rabbitmq ActiveMQ

4、关于事务的面试题:
一、什么是事务?有什么用?事务的特性ACID
事务提供了一种机制,可用来将一系列数据库更改归入一个逻辑操作。更改数据库后,所做的更改可以作为一个单元进行提交或取消。事务可确保遵循原子性、一致性、隔离性和持续性(ACID)这几种属性,以使数据能够正确地提交到数据库中。
1)原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作 要么都发生,要么都不发生。
2)一致性(Consistency)一个事务中,事务前后数据的完整性必须保持一致。
3)隔离性(Isolation)多个事务,事务的隔离性是指多个用户并发访问数据库时, 一个用户的 事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
4)持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变 就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

二 事务的并发会产生的问题有哪些
1.脏读
一个事务正在对数据进行更新操作,但是更新还未提交,另一个事务这时也来操作这组数据,并且读取了前一个事务还未提交的数据,而前一个事务如果操作失败进行了回滚,后一个事务读取的就是错误的数据,这样就造成了脏读
2.不可重复读
一个事务多次读取同一个数据,在该事务还未结束时,另一个事务也对该数据进行 了操作,而且在第一个事务两次读取之间,第二个事务对数据进行了更新,那么第一个 事务前后两个读取到的数据是不同的,这样就造成了不可重复读
3.幻读
第一个数据正在查询某一条数据,这时,另一个事务又插入了一条符合条件的数据,第一个事务在第二次查询符合同一条件的数据时,发现多了一条前一次查询时没有的数据,仿佛幻觉一样,这就是幻读

三 不可重复读和幻读的区别
不可重复读是指在同一查询事务中多次进行,由于其他提交事务所做的修改和删除,每次返回不同的结果集,此时发生不可重复读
幻读是指在同一查询事务中多次进行,由于其他提交的事务所做的插入操作,每次返回不同的结果集,此时发生幻读表面上看,区别就在于不可重复读能看见其他事务提交的修改和删除,而幻读能看见其他事务提交的插入

四、spring 事务隔离级别
1.default:(默认)
默认隔离级别,使用数据库默认的事务隔离级别
2.read_uncommitted:(读未提交)
这是事务最低的隔离级别,他允许另外一个事务可以看到这个事务未提交的数据,这种隔离级别会产生脏读,不可重复读和幻读
3.read_committed(读已提交)
保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据.这种事务隔离级别可以避免脏读,但是可能会出现不可重复读和幻读
4.repeatable_read(可重复读)
这种事务级别可以防止脏读,不可重复读.但是可能出现幻读.他除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读
5.Serializable 串行化
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。防止了脏读、不可重复读、幻读

总结:
脏读 不可重复读 幻读
读未提交 会 会 会
读已提交 不会 会 会
可重复读 不会 不会 会
串行化 不会 不会 不会

五、spring事务的传播行为
1.requierd
如果有事务那么加入事务,没有的话新建一个
2.not_supported
不开启事务
3.requires_new
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完,继续执行老事务
4.mandatory
必须在一个已有的事务中执行,否则抛出异常
5.never
必须在一个没有的事务中执行,否则抛出异常
6.supports
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务那就不用事务

六 Spring声明式事务的回滚机制
在Spring 的事务框架中推荐的事务回滚方法是,在当前执行的事务上下文中抛出一个异常。如果异常未被处理,当抛出异常调用堆栈的时候,Spring 的事务框架代码将捕获任何未处理的异常,然后并决定是否将此事务标记为回滚。
在默认配置中,Spring 的事务框架代码只会将出现runtime, unchecked 异常的事务标记为回滚;也就是说事务中抛出的异常时RuntimeException或者是其子类,这样事务才会回滚(默认情况下Error也会导致事务回滚)。在默认配置的情况下,所有的 checked 异常都不会引起事务回滚。如果有需要,可以通过rollback-for 和no-rollback-for进行指定。

七 分布式环境下如何处理事务
分布式事务处理是很难保证acid的。一般做法是牺牲一致性,满足可用性和分区容错。采用的方式可以是二阶段提交,由于二阶段提交存在着诸如同步阻塞、单点问题、数据不一致、宕机等缺陷,所以还可以采用TCC(补偿事务)的方式实现,TCC核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段,本质也是2阶段提交,缺点也比较明显的,在确认和补偿时都有可能失败,一些业务流程可能用TCC不太好定义及处理。分布式事务还可以基于 mq(消息队列)/rpc(远程方法调用)实现最终一致性。还有Mycat可以通过用户会话Session中设置autocommit=false启动事务,通过设置ServerConnection中变量txInterrupted=true来控制是否事务异常需要回滚。在Mycat中的事务是一种二阶段提交事务方式,但是从实际应用场景出发这种出现故障的概率还是比较小的,因此这种实现方式可以满足很多应用需求,但如果出现问题,会很麻烦。但在分库分表,立即可见的应用上是不能满足业务需求的,所以分布式事务需要根据具体业务的需要权衡取舍的。

------------------面试能用自己的语言用自己的理解描述清楚这个---------------
5、微服务架构下处理分布式事务,你必须知道的事儿
根据微服务架构的鼻祖 Martin Fowler 的忠告,微服务架构中应当尽量避免分布式事务。然而,在某些领域,分布式事务如同宿命中的对手无法避免。
根据微服务架构的鼻祖 Martin Fowler 的忠告,微服务架构中应当尽量避免分布式事务。然而,在某些领域,分布式事务如同宿命中的对手无法避免。
在工程领域,分布式事务的讨论主要聚焦于强一致性和最终一致性的解决方案。
典型方案包括:
• 两阶段提交(2PC, Two-phase Commit)方案。
• eBay 事件队列方案。
• TCC 补偿模式。
• 缓存数据最终一致性。
一致性理论
分布式事务的目的是保障分库数据一致性,而跨库事务会遇到各种不可控制的问题,如个别节点永久性宕机,像单机事务一样的 ACID 是无法奢望的。
另外,业界著名的 CAP 理论也告诉我们,对分布式系统,需要将数据一致性和系统可用性、分区容忍性放在天平上一起考虑。
两阶段提交协议(简称2PC)是实现分布式事务较为经典的方案,但 2PC 的可扩展性很差,在分布式架构下应用代价较大,eBay 架构师 Dan Pritchett 提出了 BASE 理论,用于解决大规模分布式系统下的数据一致性问题。
BASE 理论告诉我们:可以通过放弃系统在每个时刻的强一致性来换取系统的可扩展性。
01.CAP 理论
在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)3 个要素最多只能同时满足两个,不可兼得。其中,分区容忍性又是不可或缺的。

• 一致性:分布式环境下,多个节点的数据是否强一致。
• 可用性:分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果。
• 分区容忍性:特指对网络分区的容忍性。
举例:Cassandra、Dynamo 等,默认优先选择 AP,弱化 C;HBase、MongoDB 等,默认优先选择 CP,弱化 A。
02.BASE 理论
核心思想:
• 基本可用(Basically Available):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用。
• 软状态(Soft State):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性。
• 最终一致性(Eventual Consistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态。
一致性模型
数据的一致性模型可以分成以下三类:
• 强一致性:数据更新成功后,任意时刻所有副本中的数据都是一致的,一般采用同步的方式实现。
• 弱一致性:数据更新成功后,系统不承诺立即可以读到最新写入的值,也不承诺具体多久之后可以读到。
• 最终一致性:弱一致性的一种形式,数据更新成功后,系统不承诺立即可以返回最新写入的值,但是保证最终会返回上一次更新操作的值。
分布式系统数据的强一致性、弱一致性和最终一致性可以通过 Quorum NRW 算法分析。
分布式事务解决方案
01.2PC 方案——强一致性
2PC 的核心原理是通过提交分阶段和记日志的方式,记录下事务提交所处的阶段状态,在组件宕机重启后,可通过日志恢复事务提交的阶段状态,并在这个状态节点重试。
如 Coordinator 重启后,通过日志可以确定提交处于 Prepare 还是 Prepare All 状态。若是前者,说明有节点可能没有 Prepare 成功,或所有节点 Prepare 成功但还没有下发 Commit,状态恢复后给所有节点下发 RollBack。
若是 Prepare All 状态,需要给所有节点下发 Commit,数据库节点需要保证 Commit 幂等。

2PC 方案的三个问题:
• 同步阻塞。
• 数据不一致。
• 单点问题。
升级的 3PC 方案旨在解决这些问题,主要有两个改进:
• 增加超时机制。
• 两阶段之间插入准备阶段。
但三阶段提交也存在一些缺陷,要彻底从协议层面避免数据不一致,可以采用 Paxos 或者 Raft 算法。
02.eBay 事件队列方案——最终一致性
eBay 的架构师 Dan Pritchett,曾在一篇解释 BASE 原理的论文《Base:An Acid Alternative》中提到一个 eBay 分布式系统一致性问题的解决方案。
它的核心思想是将需要分布式处理的任务通过消息或者日志的方式来异步执行,消息或日志可以存到本地文件、数据库或消息队列,再通过业务规则进行失败重试,它要求各服务的接口是幂等的。
描述的场景为,有用户表 user 和交易表 transaction,用户表存储用户信息、总销售额和总购买额。交易表存储每一笔交易的流水号、买家信息、卖家信息和交易金额。如果产生了一笔交易,需要在交易表增加记录,同时还要修改用户表的金额。

论文中提出的解决方法是将更新交易表记录和用户表更新消息放在一个本地事务来完成,为了避免重复消费用户表更新消息带来的问题,增加一个操作记录表 updates_applied 来记录已经完成的交易相关的信息。

这个方案的核心在于第二阶段的重试和幂等执行。失败后重试,这是一种补偿机制,它是能保证系统最终一致的关键流程。
03.TCC (Try-Confirm-Cancel)补偿模式——最终一致性
某业务模型如图,由服务 A、服务 B、服务 C、服务 D 共同组成的一个微服务架构系统。服务 A 需要依次调用服务 B、服务 C 和服务 D 共同完成一个操作。
当服务 A 调用服务 D 失败时,若要保证整个系统数据的一致性,就要对服务 B 和服务 C 的 invoke 操作进行回滚,执行反向的 revert 操作。回滚成功后,整个微服务系统是数据一致的。

实现的三个关键要素:
• 服务调用链必须被记录下来。
• 每个服务提供者都需要提供一组业务逻辑相反的操作,互为补偿,同时回滚操作要保证幂等。
• 必须按失败原因执行不同的回滚策略。
实现的两个难点:
• 补偿模式的特点是实现简单,但是想形成一定程度的通用方案比较困难,特别是服务链的记录,因为大部分时候,业务参数或者业务逻辑千差万别。
• 很多业务特征使得该服务无法提供一个安全的回滚操作。
04.缓存数据最终一致性
在我们的业务系统中,缓存(Redis 或者 Memcached)通常被用在数据库前面,作为数据读取的缓冲,使得 I/O 操作不至于直接落在数据库上。
以商品详情页为例,假如卖家修改了商品信息,并写回到数据库,但是这时候用户从商品详情页看到的信息还是从缓存中拿到的过时数据,这就出现了缓存系统和数据库系统中的数据不一致的现象。
要解决该场景下缓存和数据库数据不一致的问题,我们有以下两种解决方案:
• 为缓存数据设置过期时间。当缓存中数据过期后,业务系统会从数据库中获取数据,并将新值放入缓存。这个过期时间就是系统可以达到最终一致的容忍时间。
• 更新数据库数据后,同时清除缓存数据。数据库数据更新后,同步删除缓存中数据,使得下次对商品详情的获取直接从数据库中获取,并同步到缓存。
选择建议
在面临数据一致性问题的时候,首先要从业务需求的角度出发,确定我们对于三种一致性模型的接受程度,再通过具体场景来决定解决方案。
从应用角度看,分布式事务的现实场景常常无法规避,在有能力给出其他解决方案前,2PC 也是一个不错的选择。
对购物转账等电商和金融业务,中间件层的 2PC 最大问题在于业务不可见,一旦出现不可抗力或意想不到的一致性破坏。
如数据节点永久性宕机,业务难以根据 2PC 的日志进行补偿。金融场景下,数据一致性是命根,业务需要对数据有百分之百的掌控力。
建议使用 TCC 这类分布式事务模型,或基于消息队列的柔性事务框架,这两种方案都在业务层实现,业务开发者具有足够掌控力,可以结合 SOA 框架来架构,包括 Dubbo、Spring Cloud 等。

参考资料 https://www.cnblogs.com/cn-sbo/p/10853469.html

高并发的解决方案:

流量优化:防盗链处理

防止别人通过一些技术手段绕过本站的资源展示页面,盗用本站的资源,让绕开本站资源展示页面的资源链接失效,可以大大减轻服务器及带宽的压力

前端优化:减少HTTP请求,合并css或js,添加异步请求,启用浏览器缓存和文件压缩,CDN加速,建立独立图片服务器,
  服务端优化:页面静态化,并发处理,队列处理
  数据库优化:数据库缓存,分库分表,分区操作,读写分离,负载均衡
web服务器优化:负载均衡,nginx反向代理,7,4层LVS软件

数据库的优化问题
参考文件链接地址: https://www.cnblogs.com/ycqi/p/10833617.html
数据库的优化主要从一下8点出发
一、 根据服务层面:配置mysql性能优化参数
1、 目的:
湖州街29号时瑞大厦6层
通过根据服务器目前状况,修改Mysql的系统参数,达到合理利用服务器现有资源,最大合理的提高MySQL性能。

2、服务器参数:
32G内存、4个CPU,每个CPU 8核。
3、MySQL目前安装状况。
MySQL目前安装,用的是MySQL默认的最大支持配置。拷贝的是my-huge.cnf.编码已修改为UTF-8.具体修改及安装MySQL,可以参考<<Linux系统上安装MySQL 5.5>>帮助文档。
4、修改MySQL配置
参考文件的位置: https://www.cnblogs.com/angryprogrammer/p/6667741.html
打开MySQL配置文件my.cnf

vi /etc/my.cnf
4.1 MySQL非缓存参数变量介绍及修改
4.1.1修改back_log参数值:由默认的50修改为500.(每个连接256kb,占用:125M)
back_log=500

back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。也就是说,如果MySql的连接数据达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。将会报:unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待连接进程时.

back_log值不能超过TCP/IP连接的侦听队列的大小。若超过则无效,查看当前系统的TCP/IP连接的侦听队列的大小命令:cat /proc/sys/net/ipv4/tcp_max_syn_backlog目前系统为1024。对于Linux系统推荐设置为小于512的整数。
修改系统内核参数,)http://www.51testing.com/html/64/n-810764.html
查看mysql 当前系统默认back_log值,命令:
show variables like ‘back_log’; 查看当前数量

4.1.2修改wait_timeout参数值,由默认的8小时,修改为30分钟。(本次不用)
wait_timeout=1800(单位为妙)

我对wait-timeout这个参数的理解:MySQL客户端的数据库连接闲置最大时间值。
说得比较通俗一点,就是当你的MySQL连接闲置超过一定时间后将会被强行关闭。MySQL默认的wait-timeout 值为8个小时,可以通过命令show variables like 'wait_timeout’查看结果值;。
设置这个值是非常有意义的,比如你的网站有大量的MySQL链接请求(每个MySQL连接都是要内存资源开销的 ),由于你的程序的原因有大量的连接请求空闲啥事也不干,白白占用内存资源,或者导致MySQL超过最大连接数从来无法新建连接导致“Too many connections”的错误。在设置之前你可以查看一下你的MYSQL的状态(可用show processlist),如果经常发现MYSQL中有大量的Sleep进程,则需要 修改wait-timeout值了。
interactive_timeout:服务器关闭交互式连接前等待活动的秒数。交互式客户端定义为在mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。
wait_timeout:服务器关闭非交互连接之前等待活动的秒数。在线程启动时,根据全局wait_timeout值或全局 interactive_timeout值初始化会话wait_timeout值,取决于客户端类型(由mysql_real_connect()的连接选项CLIENT_INTERACTIVE定义).
这两个参数必须配合使用。否则单独设置wait_timeout无效

4.1.3修改max_connections参数值,由默认的151,修改为3000(750M)。
max_connections=3000
max_connections是指MySql的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySql会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。可以过’conn%'通配符查看当前状态的连接数量,以定夺该值的大小。
MySQL服务器允许的最大连接数16384;
查看系统当前最大连接数:
show variables like ‘max_connections’;

4.1…4修改max_user_connections值,由默认的0,修改为800
max_user_connections=800
max_user_connections是指每个数据库用户的最大连接
针对某一个账号的所有客户端并行连接到MYSQL服务的最大并行连接数。简单说是指同一个账号能够同时连接到mysql服务的最大连接数。设置为0表示不限制。
目前默认值为:0不受限制。
这儿顺便介绍下Max_used_connections:它是指从这次mysql服务启动到现在,同一时刻并行连接数的最大值。它不是指当前的连接情况,而是一个比较值。如果在过去某一个时刻,MYSQL服务同时有1000个请求连接过来,而之后再也没有出现这么大的并发请求时,则Max_used_connections=1000.请注意与show variables 里的max_user_connections的区别。默认为0表示无限大。
查看max_user_connections值
show variables like ‘max_user_connections’;

4.1.5修改thread_concurrency值,由目前默认的8,修改为64
thread_concurrency=64
thread_concurrency的值的正确与否, 对mysql的性能影响很大, 在多个cpu(或多核)的情况下,错误设置了thread_concurrency的值, 会导致mysql不能充分利用多cpu(或多核), 出现同一时刻只能一个cpu(或核)在工作的情况。
thread_concurrency应设为CPU核数的2倍. 比如有一个双核的CPU, 那thread_concurrency 的应该为4; 2个双核的cpu, thread_concurrency的值应为8.
比如:根据上面介绍我们目前系统的配置,可知道为4个CPU,每个CPU为8核,按照上面的计算规则,这儿应为:482=64
查看系统当前thread_concurrency默认配置命令:
show variables like ‘thread_concurrency’;

4.1.6添加skip-name-resolve,默认被注释掉,没有该参数。
skip-name-resolve
skip-name-resolve:禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项,则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求!
4.1.7 skip-networking,默认被注释掉。没有该参数。(本次无用)
skip-networking建议被注释掉,不要开启
开启该选项可以彻底关闭MySQL的TCP/IP连接方式,如果WEB服务器是以远程连接的方式访问MySQL数据库服务器则不要开启该选项!否则将无法正常连接!
4.1.8 default-storage-engine(设置MySQL的默认存储引擎)
default-storage-engine= InnoDB(设置InnoDB类型,另外还可以设置MyISAM类型)
设置创建数据库及表默认存储类型
show table status like ‘tablename’显示表的当前存储状态值
查看MySQL有哪些存储状态及默认存储状态
show engines;
创建表并指定存储类型
CREATE TABLE mytable (id int, title char(20)) ENGINE = INNODB;
修改表存储类型:
Alter table tableName engine =engineName

备注:设置完后把以下几个开启:

Uncomment the following if you are using InnoDB tables

innodb_data_home_dir = /var/lib/mysql
#innodb_data_file_path = ibdata1:1024M;ibdata2:10M:autoextend(要注释掉,否则会创建一个新的把原来的替换的。)
innodb_log_group_home_dir = /var/lib/mysql

You can set …_buffer_pool_size up to 50 - 80 %

of RAM but beware of setting memory usage too high

innodb_buffer_pool_size = 1000M
innodb_additional_mem_pool_size = 20M

Set …_log_file_size to 25 % of buffer pool size

innodb_log_file_size = 500M
innodb_log_buffer_size = 20M
innodb_flush_log_at_trx_commit = 0
innodb_lock_wait_timeout = 50
设置完后一定记得把MySQL安装目录地址(我们目前是默认安装所以地址/var/lib/mysql/)下的ib_logfile0和ib_logfile1删除掉。否则重启MySQL起动失败。

4.2 MySQL缓存变量介绍及修改
数据库属于IO密集型的应用程序,其主职责就是数据的管理及存储工作。而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘上读取一个 IO是在毫秒级别,二者相差3个数量级。所以,要优化数据库,首先第一步需要优化的就是IO,尽可能将磁盘IO转化为内存IO。本文先从MySQL数据库 IO相关参数(缓存参数)的角度来看看可以通过哪些参数进行IO优化

4.2.1全局缓存
启动MySQL时就要分配并且总是存在的全局缓存。目前有:key_buffer_size(默认值:402653184,即384M)、innodb_buffer_pool_size(默认值:134217728即:128M)、innodb_additional_mem_pool_size(默认值:8388608即:8M)、innodb_log_buffer_size(默认值:8388608即:8M)、query_cache_size(默认值:33554432即:32M)等五个。总共:560M.
这些变量值都可以通过命令如:show variables like ‘变量名’;查看到。

4.2.1.1:key_buffer_size,本系统目前为384M,可修改为400M
key_buffer_size=400M
key_buffer_size是用于索引块的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),对MyISAM(MySQL表存储的一种类型,可以百度等查看详情)表性能影响最大的一个参数。如果你使它太大,系统将开始换页并且真的变慢了。严格说是它决定了数据库索引处理的速度,尤其是索引读的速度。对于内存在4GB左右的服务器该参数可设置为256M或384M.
怎么才能知道key_buffer_size的设置是否合理呢,一般可以检查状态值Key_read_requests和Key_reads ,比例key_reads / key_read_requests应该尽可能的低,比如1:100,1:1000 ,1:10000。其值可以用以下命令查得:show status like ‘key_read%’;
比如查看系统当前key_read和key_read_request值为:
±------------------±------+
| Variable_name | Value |
±------------------±------+
| Key_read_requests | 28535 |
| Key_reads | 269 |
±------------------±------+
可知道有28535个请求,有269个请求在内存中没有找到直接从硬盘读取索引.
未命中缓存的概率为:0.94%=269/28535100%. 一般未命中概率在0.1之下比较好。目前已远远大于0.1,证明效果不好。若命中率在0.01以下,则建议适当的修改key_buffer_size值。
http://dbahacker.com/mysql/innodb-myisam-compare(InnoDB与MyISAM的六大区别)
http://kb.cnblogs.com/page/99810/(查看存储引擎介绍)
MyISAM、InnoDB、MyISAM Merge引擎、InnoDB、memory(heap)、archive
4.2.1.2:innodb_buffer_pool_size(默认128M)
innodb_buffer_pool_size=1024M(1G)
innodb_buffer_pool_size:主要针对InnoDB表性能影响最大的一个参数。功能与Key_buffer_size一样。InnoDB占用的内存,除innodb_buffer_pool_size用于存储页面缓存数据外,另外正常情况下还有大约8%的开销,主要用在每个缓存页帧的描述、adaptive hash等数据结构,如果不是安全关闭,启动时还要恢复的话,还要另开大约12%的内存用于恢复,两者相加就有差不多21%的开销。假设:12G的innodb_buffer_pool_size,最多的时候InnoDB就可能占用到14.5G的内存。若系统只有16G,而且只运行MySQL,且MySQL只用InnoDB,
那么为MySQL开12G,是最大限度地利用内存了。
另外InnoDB和 MyISAM 存储引擎不同, MyISAM 的 key_buffer_size 只能缓存索引键,而 innodb_buffer_pool_size 却可以缓存数据块和索引键。适当的增加这个参数的大小,可以有效的减少 InnoDB 类型的表的磁盘 I/O 。
当我们操作一个 InnoDB 表的时候,返回的所有数据或者去数据过程中用到的任何一个索引块,都会在这个内存区域中走一遭。
可以通过 (Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests * 100% 计算缓存命中率,并根据命中率来调整 innodb_buffer_pool_size 参数大小进行优化。值可以用以下命令查得:show status like ‘Innodb_buffer_pool_read%’;
比如查看当前系统中系统中
| Innodb_buffer_pool_read_requests | 1283826 |
| Innodb_buffer_pool_reads | 519 |
±--------------------------------------±--------+
其命中率99.959%=(1283826-519)/1283826
100% 命中率越高越好。
4.2.1.3:innodb_additional_mem_pool_size(默认8M)
innodb_additional_mem_pool_size=20M
innodb_additional_mem_pool_size 设置了InnoDB存储引擎用来存放数据字典信息以及一些内部数据结构的内存空间大小,所以当我们一个MySQL Instance中的数据库对象非常多的时候,是需要适当调整该参数的大小以确保所有数据都能存放在内存中提高访问效率的。
这个参数大小是否足够还是比较容易知道的,因为当过小的时候,MySQL会记录Warning信息到数据库的error log中,这时候你就知道该调整这个参数大小了。
查看当前系统mysql的error日志 cat /var/lib/mysql/机器名.error 发现有很多waring警告。所以要调大为20M.
根据MySQL手册,对于2G内存的机器,推荐值是20M。
32G内存的 100M
4.2.1.4:innodb_log_buffer_size(默认8M)
innodb_log_buffer_size=20M
innodb_log_buffer_size 这是InnoDB存储引擎的事务日志所使用的缓冲区。类似于Binlog Buffer,InnoDB在写事务日志的时候,为了提高性能,也是先将信息写入Innofb Log Buffer中,当满足innodb_flush_log_trx_commit参数所设置的相应条件(或者日志缓冲区写满)之后,才会将日志写到文件 (或者同步到磁盘)中。可以通过innodb_log_buffer_size 参数设置其可以使用的最大内存空间。
InnoDB 将日志写入日志磁盘文件前的缓冲大小。理想值为 1M 至 8M。大的日志缓冲允许事务运行时不需要将日志保存入磁盘而只到事务被提交(commit)。 因此,如果有大的事务处理,设置大的日志缓冲可以减少磁盘I/O。 在 my.cnf中以数字格式设置。
默认是8MB,系的如频繁的系统可适当增大至4MB~8MB。当然如上面介绍所说,这个参数实际上还和另外的flush参数相关。一般来说不建议超过32MB
注:innodb_flush_log_trx_commit参数对InnoDB Log的写入性能有非常关键的影响,默认值为1。该参数可以设置为0,1,2,解释如下:
0:log buffer中的数据将以每秒一次的频率写入到log file中,且同时会进行文件系统到磁盘的同步操作,但是每个事务的commit并不会触发任何log buffer 到log file的刷新或者文件系统到磁盘的刷新操作;
1:在每次事务提交的时候将log buffer 中的数据都会写入到log file,同时也会触发文件系统到磁盘的同步;
2:事务提交会触发log buffer到log file的刷新,但并不会触发磁盘文件系统到磁盘的同步。此外,每秒会有一次文件系统到磁盘同步操作。
实际测试发现,该值对插入数据的速度影响非常大,设置为2时插入10000条记录只需要2秒,设置为0时只需要1秒,而设置为1时则需要229秒。因此,MySQL手册也建议尽量将插入操作合并成一个事务,这样可以大幅提高速度。根据MySQL手册,在存在丢失最近部分事务的危险的前提下,可以把该值设为0。

4.5.1.5:query_cache_size(默认32M)
query_cache_size=40M
query_cache_size: 主要用来缓存MySQL中的ResultSet,也就是一条SQL语句执行的结果集,所以仅仅只能针对select语句。当我们打开了 Query Cache功能,MySQL在接受到一条select语句的请求后,如果该语句满足Query Cache的要求(未显式说明不允许使用Query Cache,或者已经显式申明需要使用Query Cache),MySQL会直接根据预先设定好的HASH算法将接受到的select语句以字符串方式进行hash,然后到Query Cache中直接查找是否已经缓存。也就是说,如果已经在缓存中,该select请求就会直接将数据返回,从而省略了后面所有的步骤(如SQL语句的解析,优化器优化以及向存储引擎请求数据等),极大的提高性能。根据MySQL用户手册,使用查询缓冲最多可以达到238%的效率。
当然,Query Cache也有一个致命的缺陷,那就是当某个表的数据有任何任何变化,都会导致所有引用了该表的select语句在Query Cache中的缓存数据失效。所以,当我们的数据变化非常频繁的情况下,使用Query Cache可能会得不偿失
Query Cache的使用需要多个参数配合,其中最为关键的是query_cache_size和query_cache_type,前者设置用于缓存 ResultSet的内存大小,后者设置在何场景下使用Query Cache。在以往的经验来看,如果不是用来缓存基本不变的数据的MySQL数据库,query_cache_size一般256MB是一个比较合适的大小。当然,这可以通过计算Query Cache的命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))来进行调整。 query_cache_type可以设置为0(OFF),1(ON)或者2(DEMOND),分别表示完全不使用query cache,除显式要求不使用query cache(使用sql_no_cache)之外的所有的select都使用query cache,只有显示要求才使用query cache(使用sql_cache)。如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲. 如果Qcache_hits的值也非常大,则表明查询缓冲使用非常频繁,此时需要增加缓冲大小;
根据命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))进行调整,一般不建议太大,256MB可能已经差不多了,大型的配置型静态数据可适当调大.
可以通过命令:show status like ‘Qcache_%’;查看目前系统Query catch使用大小
| Qcache_hits | 1892463 |
| Qcache_inserts | 35627
命中率98.17%=1892463/(1892463 +35627 )*100
4.2.2局部缓存
除了全局缓冲,MySql还会为每个连接发放连接缓冲。个连接到MySQL服务器的线程都需要有自己的缓冲。大概需要立刻分配256K,甚至在线程空闲时,它们使用默认的线程堆栈,网络缓存等。事务开始之后,则需要增加更多的空间。运行较小的查询可能仅给指定的线程增加少量的内存消耗,然而如果对数据表做复杂的操作例如扫描、排序或者需要临时表,则需分配大约read_buffer_size,
sort_buffer_size,read_rnd_buffer_size,tmp_table_size 大小的内存空间. 不过它们只是在需要的时候才分配,并且在那些操作做完之后就释放了。有的是立刻分配成单独的组块。tmp_table_size 可能高达MySQL所能分配给这个操作的最大内存空间了
。注意,这里需要考虑的不只有一点——可能会分配多个同一种类型的缓存,例如用来处理子查询。一些特殊的查询的内存使用量可能更大——如果在MyISAM表上做成批的插入
时需要分配 bulk_insert_buffer_size 大小的内存;执行 ALTER TABLE, OPTIMIZE TABLE, REPAIR TABLE 命令时需要分配 myisam_sort_buffer_size 大小的内存。
4.2.2.1:read_buffer_size(默认值:2097144即2M)
read_buffer_size=4M
read_buffer_size 是MySql读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分配一段内存缓冲区。read_buffer_size变量控制这一
缓冲区的大小。如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能.

4.2.2.2:sort_buffer_size(默认值:2097144即2M)
sort_buffer_size=4M
sort_buffer_size是MySql执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。如果不能,可以尝试增加sort_buffer_size变量的大小
4.2.2.3: read_rnd_buffer_size(默认值:8388608即8M)
read_rnd_buffer_size=8M
read_rnd_buffer_size 是MySql的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySql会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开
销过大。
4.2.2.4: tmp_table_size(默认值:8388608 即:16M)
tmp_table_size=16M
tmp_table_size是MySql的heap (堆积)表缓冲大小。所有联合在一个DML指令内完成,并且大多数联合甚至可以不用临时表即可以完成。大多数临时表是基于内
存的(HEAP)表。具有大的记录长度的临时表 (所有列的长度的和)或包含BLOB列的表存储在硬盘上。如果某个内部heap(堆积)表大小超过tmp_table_size,MySQL可以根据需要自
动将内存中的heap表改为基于硬盘的MyISAM表。还可以通过设置tmp_table_size选项来增加临时表的大小。也就是说,如果调高该值,MySql同时将增加heap表的大小,可达到提高
联接查询速度的效果。
4.2.2.5:record_buffer:(默认值:)
record_buffer每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描,你可能想要增加该值。默认数值是131072
(128K)
4.2.3其它缓存:
4.2.3.1:table_cache(默认值:512)

TABLE_CACHE(5.1.3及以后版本又名TABLE_OPEN_CACHE)
table_cache指定表高速缓存的大小。每当MySQL访问一个表时,如果在表缓冲区中还有空间,该表就被打开并放入其中,这样可以更快地访问表内容。通过检查峰值时间的状态值Open_tables和Opened_tables,可以决定是否需要增加table_cache的值。如果你发现open_tables等于table_cache,并且opened_tables在不断增长,那么你就需要增加table_cache的值了(上述状态值可以使用SHOW STATUS LIKE ‘Open%tables’获得)。注意,不能盲目地把table_cache设置成很大的值。如果设置得太高,可能会造成文件描述符不足,从而造成性能不稳定或者连接失败。
SHOW STATUS LIKE ‘Open%tables’;
±--------------±------+
| Variable_name | Value |
±--------------±------+
| Open_tables | 356 |
| Opened_tables | 0 |
±--------------±------+
2 rows in set (0.00 sec)
open_tables表示当前打开的表缓存数,如果执行flush tables操作,则此系统会关闭一些当前没有使用的表缓存而使得此状态值减小;
opend_tables表示曾经打开的表缓存数,会一直进行累加,如果执行flush tables操作,值不会减小。
在mysql默认安装情况下,table_cache的值在2G内存以下的机器中的值默认时256到512,如果机器有4G内存,则默认这个值 是2048,但这决意味着机器内存越大,这个值应该越大,因为table_cache加大后,使得mysql对SQL响应的速度更快了,不可避免的会产生 更多的死锁(dead lock),这样反而使得数据库整个一套操作慢了下来,严重影响性能。所以平时维护中还是要根据库的实际情况去作出判断,找到最适合你维护的库的 table_cache值。
由于MySQL是多线程的机制,为了提高性能,每个线程都是独自打开自己需要的表的文件描 述符,而不是通过共享已经打开的.针对不同存储引擎处理的方法当然也不一样
在myisam表引擎中,数据文件的描述符 (descriptor)是不共享的,但是索引文件的描述符却是所有线程共享的.Innodb中和使用表空间类型有关,假如是共享表空间那么实际就一个数 据文件,当然占用的数据文件描述符就会比独立表空间少.
mysql手册上给的建议大小 是:table_cache=max_connections*n
n表示查询语句中最大表数, 还需要为临时表和文件保留一些额外的文件描述符。
这个数据遭到很多质疑,table_cache够用就好,检查 Opened_tables值,如果这个值很大,或增长很快那么你就得考虑加大table_cache了.
table_cache:所有线程打开的表的数目。增大该值可以增加mysqld需要的文件描述符的数量。默认值是64.

4.2.3.2 thread_cache_size (服务器线程缓存)
thread_cache_size=64

默认的thread_cache_size=8,但是看到好多配置的样例里的值一般是32,64,甚至是128,感觉这个参数对优化应该有帮助,于是查了下:
根据调查发现以上服务器线程缓存thread_cache_size没有进行设置,或者设置过小,这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中,如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,增加这个值可以改善系统性能.通过比较 Connections 和 Threads_created 状态的变量,可以看到这个变量的作用。(–>表示要调整的值) 根据物理内存设置规则如下:
1G —> 8
2G —> 16
3G —> 32 >3G —> 64
mysql> show status like ‘thread%’;
+——————-+——-+
| Variable_name | Value |
+——————-+——-+
| Threads_cached | 0 | <—当前被缓存的空闲线程的数量
| Threads_connected | 1 | <—正在使用(处于连接状态)的线程
| Threads_created | 1498 | <—服务启动以来,创建了多少个线程
| Threads_running | 1 | <—正在忙的线程(正在查询数据,传输数据等等操作)
+——————-+——-+
查看开机起来数据库被连接了多少次?
mysql> show status like ‘%connection%’;
+———————-+——-+
| Variable_name | Value |
+———————-+——-+
| Connections | 1504 | –>服务启动以来,历史连接数
| Max_used_connections | 2 |
+———————-+——-+
通过连接线程池的命中率来判断设置值是否合适?命中率超过90%以上,设定合理。
(Connections - Threads_created) / Connections * 100 %
二、 从系统层面增强mysql的性能:优化数据表结构、字段类型、字段索引、分表,分库、读写分离等等
表结构:数据类型选择;字符编码;适当拆分;适度冗余;尽量使用 NOT NULL 详细, 读写分离

表结构的优化:
https://www.cnblogs.com/eeds-wangwei/p/8135771.html
由于MySQL数据库是基于行(Row)存储的数据库,而数据库操作 IO 的时候是以 page(block)的方式,也就是说,如果我们每条记录所占用的空间量减小,就会使每个page中可存放的数据行数增大,那么每次 IO 可访问的行数也就增多了。反过来说,处理相同行数的数据,需要访问的 page 就会减少,也就是 IO 操作次数降低,直接提升性能。此外,由于我们的内存是有限的,增加每个page中存放的数据行数,就等于增加每个内存块的缓存数据量,同时还会提升内存换中数据命中的几率,也就是缓存命中率。
一、数据类型选择
数据库操作中最为耗时的操作就是 IO 处理,大部分数据库操作 90% 以上的时间都花在了 IO 读写上面。所以尽可能减少 IO 读写量,可以在很大程度上提高数据库操作的性能。
我们无法改变数据库中需要存储的数据,但是我们可以在这些数据的存储方式方面花一些心思。下面的这些关于字段类型的优化建议主要适用于记录条数较多,数据量较大的场景,因为精细化的数据类型设置可能带来维护成本的提高,过度优化也可能会带来其他的问题:
  1.数字类型:非万不得已不要使用DOUBLE,不仅仅只是存储长度的问题,同时还会存在精确性的问题。同样,固定精度的小数,也不建议使用DECIMAL,建议乘以固定倍数转换成整数存储,可以大大节省存储空间,且不会带来任何附加维护成本。对于整数的存储,在数据量较大的情况下,建议区分开 TINYINT / INT / BIGINT 的选择,因为三者所占用的存储空间也有很大的差别,能确定不会使用负数的字段,建议添加unsigned定义。当然,如果数据量较小的数据库,也可以不用严格区分三个整数类型。
  2.字符类型:非万不得已不要使用 TEXT 数据类型,其处理方式决定了他的性能要低于char或者是varchar类型的处理。定长字段,建议使用 CHAR 类型,不定长字段尽量使用 VARCHAR,且仅仅设定适当的最大长度,而不是非常随意的给一个很大的最大长度限定,因为不同的长度范围,MySQL也会有不一样的存储处理。
  3.时间类型:尽量使用TIMESTAMP类型,因为其存储空间只需要 DATETIME 类型的一半。对于只需要精确到某一天的数据类型,建议使用DATE类型,因为他的存储空间只需要3个字节,比TIMESTAMP还少。不建议通过INT类型类存储一个unix timestamp 的值,因为这太不直观,会给维护带来不必要的麻烦,同时还不会带来任何好处。
  4.ENUM & SET:对于状态字段,可以尝试使用 ENUM 来存放,因为可以极大的降低存储空间,而且即使需要增加新的类型,只要增加于末尾,修改结构也不需要重建表数据。如果是存放可预先定义的属性数据呢?可以尝试使用SET类型,即使存在多种属性,同样可以游刃有余,同时还可以节省不小的存储空间。
  5.LOB类型:强烈反对在数据库中存放 LOB 类型数据,虽然数据库提供了这样的功能,但这不是他所擅长的,我们更应该让合适的工具做他擅长的事情,才能将其发挥到极致。在数据库中存储 LOB 数据就像让一个多年前在学校学过一点Java的营销专业人员来写 Java 代码一样。
二、字符编码
字符集直接决定了数据在MySQL中的存储编码方式,由于同样的内容使用不同字符集表示所占用的空间大小会有较大的差异,所以通过使用合适的字符集,可以帮助我们尽可能减少数据量,进而减少IO操作次数。
  1.纯拉丁字符能表示的内容,没必要选择 latin1 之外的其他字符编码,因为这会节省大量的存储空间。
  2.如果我们可以确定不需要存放多种语言,就没必要非得使用UTF8或者其他UNICODE字符类型,这回造成大量的存储空间浪费。
  3.MySQL的数据类型可以精确到字段,所以当我们需要大型数据库中存放多字节数据的时候,可以通过对不同表不同字段使用不同的数据类型来较大程度减小数据存储量,进而降低 IO 操作次数并提高缓存命中率。
三、适当拆分
有些时候,我们可能会希望将一个完整的对象对应于一张数据库表,这对于应用程序开发来说是很有好的,但是有些时候可能会在性能上带来较大的问题。
  当我们的表中存在类似于 TEXT 或者是很大的 VARCHAR类型的大字段的时候,如果我们大部分访问这张表的时候都不需要这个字段,我们就该义无反顾的将其拆分到另外的独立表中,以减少常用数据所占用的存储空间。这样做的一个明显好处就是每个数据块中可以存储的数据条数可以大大增加,既减少物理 IO 次数,也能大大提高内存中的缓存命中率。
  上面几点的优化都是为了减少每条记录的存储空间大小,让每个数据库中能够存储更多的记录条数,以达到减少 IO 操作次数,提高缓存命中率。下面这个优化建议可能很多开发人员都会觉得不太理解,因为这是典型的反范式设计,而且也和上面的几点优化建议的目标相违背。
四、适度冗余
为什么我们要冗余?这不是增加了每条数据的大小,减少了每个数据块可存放记录条数吗?
  确实,这样做是会增大每条记录的大小,降低每条记录中可存放数据的条数,但是在有些场景下我们仍然还是不得不这样做:
  1.被频繁引用且只能通过 Join 2张(或者更多)大表的方式才能得到的独立小字段。
  2.这样的场景由于每次Join仅仅只是为了取得某个小字段的值,Join到的记录又大,会造成大量不必要的 IO,完全可以通过空间换取时间的方式来优化。不过,冗余的同时需要确保数据的一致性不会遭到破坏,确保更新的同时冗余字段也被更新。
五、尽量使用 NOT NULL
NULL 类型比较特殊,SQL 难优化。虽然 MySQL NULL类型和 Oracle 的NULL 有差异,会进入索引中,但如果是一个组合索引,那么这个NULL 类型的字段会极大影响整个索引的效率。此外,NULL 在索引中的处理也是特殊的,也会占用额外的存放空间。
  很多人觉得 NULL 会节省一些空间,所以尽量让NULL来达到节省IO的目的,但是大部分时候这会适得其反,虽然空间上可能确实有一定节省,倒是带来了很多其他的优化问题,不但没有将IO量省下来,反而加大了SQL的IO量。所以尽量确保 DEFAULT 值不是 NULL,也是一个很好的表结构设计优化习惯。

主从配置读写分离
https://www.cnblogs.com/luckcs/articles/2543607.html
MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践
Mysql作为目前世界上使用最广泛的免费数据库,相信所有从事系统运维的工程师都一定接触过。但在实际的生产环境中,由单台Mysql作为独立的数据库是完全不能满足实际需求的,无论是在安全性,高可用性以及高并发等各个方面。
因此,一般来说都是通过 主从复制(Master-Slave)的方式来同步数据,再通过读写分离(MySQL-Proxy)来提升数据库的并发负载能力 这样的方案来进行部署与实施的。
如下图所示:

下面是我在实际工作过程中所整理的笔记,在此分享出来,以供大家参考。
一、MySQL的安装与配置
具体的安装过程,建议参考我的这一篇文章:http://heylinux.com/archives/993.html
值得一提的是,我的安装过程都是源码包编译安装的,并且所有的配置与数据等都统一规划到了/opt/mysql目录中,因此在一台服务器上安装完成以后,可以将整个mysql目录打包,然后传到其它服务器上解包,便可立即使用。
二、MySQL主从复制
场景描述:
主数据库服务器:192.168.10.130,MySQL已经安装,并且无应用数据。
从数据库服务器:192.168.10.131,MySQL已经安装,并且无应用数据。
2.1 主服务器上进行的操作
启动mysql服务
/opt/mysql/init.d/mysql start
通过命令行登录管理MySQL服务器
/opt/mysql/bin/mysql -uroot -p’new-password’
授权给从数据库服务器192.168.10.131
mysql> GRANT REPLICATION SLAVE ON . to ‘rep1’@‘192.168.10.131’ identified by ‘password’;
查询主数据库状态
Mysql> show master status;
±-----------------±---------±-------------±-----------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
±-----------------±---------±-------------±-----------------+
| mysql-bin.000005 | 261 | | |
±-----------------±---------±-------------±-----------------+
记录下 FILE 及 Position 的值,在后面进行从服务器操作的时候需要用到。
2.2 配置从服务器
修改从服务器的配置文件/opt/mysql/etc/my.cnf
将 server-id = 1修改为 server-id = 10,并确保这个ID没有被别的MySQL服务所使用。
启动mysql服务
/opt/mysql/init.d/mysql start
通过命令行登录管理MySQL服务器
/opt/mysql/bin/mysql -uroot -p’new-password’
执行同步SQL语句
mysql> change master to
master_host=’192.168.10.130’,
master_user=’rep1’,
master_password=’password’,
master_log_file=’mysql-bin.000005’,
master_log_pos=261;
正确执行后启动Slave同步进程
mysql> start slave;
主从同步检查
mysql> show slave status\G

**************** 1. row *******************
Slave_IO_State:
Master_Host: 192.168.10.130
Master_User: rep1
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000005
Read_Master_Log_Pos: 415
Relay_Log_File: localhost-relay-bin.000008
Relay_Log_Pos: 561
Relay_Master_Log_File: mysql-bin.000005
Slave_IO_Running: YES
Slave_SQL_Running: YES
Replicate_Do_DB:
……………省略若干……………
Master_Server_Id: 1
1 row in set (0.01 sec)

其中Slave_IO_Running 与 Slave_SQL_Running 的值都必须为YES,才表明状态正常。
如果主服务器已经存在应用数据,则在进行主从复制时,需要做以下处理:
(1)主数据库进行锁表操作,不让数据再进行写入动作
mysql> FLUSH TABLES WITH READ LOCK;
(2)查看主数据库状态
mysql> show master status;
(3)记录下 FILE 及 Position 的值。
将主服务器的数据文件(整个/opt/mysql/data目录)复制到从服务器,建议通过tar归档压缩后再传到从服务器解压。
(4)取消主数据库锁定
mysql> UNLOCK TABLES;
2.3 验证主从复制效果
主服务器上的操作
在主服务器上创建数据库first_db
mysql> create database first_db;
Query Ok, 1 row affected (0.01 sec)
在主服务器上创建表first_tb
mysql> create table first_tb(id int(3),name char(10));
Query Ok, 1 row affected (0.00 sec)
在主服务器上的表first_tb中插入记录
mysql> insert into first_tb values (001,’myself’);
Query Ok, 1 row affected (0.00 sec)
在从服务器上查看
mysql> show databases;

±-------------------+
| Database |
±-------------------+
| information_schema |
| first_db |
| mysql |
| performance_schema |
| test |
±-------------------+
5 rows in set (0.01 sec)

数据库first_db已经自动生成
mysql> use first_db
Database chaged
mysql> show tables;

±-------------------+
| Tables_in_first_db |
±-------------------+
| first_tb |
±-------------------+
1 row in set (0.02 sec)

数据库表first_tb也已经自动创建
mysql> select * from first_tb;

±-----±-----+
| id | name |
±-----±-----+
| 1 | myself |
±-----±-----+
1 rows in set (0.00 sec)

记录也已经存在
由此,整个MySQL主从复制的过程就完成了,接下来,我们进行MySQL读写分离的安装与配置。
三、MySQL读写分离
场景描述:
数据库Master主服务器:192.168.10.130
数据库Slave从服务器:192.168.10.131
MySQL-Proxy调度服务器:192.168.10.132
以下操作,均是在192.168.10.132即MySQL-Proxy调度服务器 上进行的。
3.1 MySQL的安装与配置
具体的安装过程与上文相同。
3.2 检查系统所需软件包
通过 rpm -qa | grep name 的方式验证以下软件包是否已全部安装。
gcc* gcc-c++* autoconf* automake* zlib* libxml* ncurses-devel* libmcrypt* libtool* flex* pkgconfig*
libevent* glib*
若缺少相关的软件包,可通过yum -y install方式在线安装,或直接从系统安装光盘中找到并通过rpm -ivh方式安装。
3.3 编译安装lua
MySQL-Proxy的读写分离主要是通过rw-splitting.lua脚本实现的,因此需要安装lua。
lua可通过以下方式获得
从http://www.lua.org/download.html下载源码包
从rpm.pbone.net搜索相关的rpm包
download.fedora.redhat.com/pub/fedora/epel/5/i386/lua-5.1.4-4.el5.i386.rpm
download.fedora.redhat.com/pub/fedora/epel/5/x86_64/lua-5.1.4-4.el5.x86_64.rpm
这里我们建议采用源码包进行安装
cd /opt/install
wget http://www.lua.org/ftp/lua-5.1.4.tar.gz
tar zvfx lua-5.1.4.tar.gz
cd lua-5.1.4
vi src/Makefile
在 CFLAGS= -O2 -Wall
(MYCFLAGS)这一行记录里加上−fPIC,更改为CFLAGS=−O2−Wall−fPIC
(MYCFLAGS)这一行记录里加上−fPIC,更改为CFLAGS=−O2−Wall−fPIC
(MYCFLAGS) 来避免编译过程中出现错误。
make linux
make install
cp etc/lua.pc /usr/lib/pkgconfig/
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/pkgconfig
3.4 安装配置MySQL-Proxy
MySQL-Proxy可通过以下网址获得:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/
推荐采用已经编译好的二进制版本,因为采用源码包进行编译时,最新版的MySQL-Proxy对automake,glib以及libevent的版本都有很高的要求,而这些软件包都是系统的基础套件,不建议强行进行更新。
并且这些已经编译好的二进制版本在解压后都在统一的目录内,因此建议选择以下版本:
32位RHEL5平台:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
64位RHEL5平台:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-64bit.tar.gz
测试平台为RHEL5 32位,因此选择32位的软件包
wget http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
tar xzvf mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
mv mysql-proxy-0.8.1-linux-rhel5-x86-32bit /opt/mysql-proxy
创建mysql-proxy服务管理脚本
mkdir /opt/mysql-proxy/init.d/
vim mysql-proxy

01
#!/bin/sh
02

03

mysql-proxy This script starts and stops the mysql-proxy daemon

04

05

chkconfig: - 78 30

06

processname: mysql-proxy

07

description: mysql-proxy is a proxy daemon to mysql

08

09

Source function library.

10
. /etc/rc.d/init.d/functions
11

12
#PROXY_PATH=/usr/local/bin
13
PROXY_PATH=/opt/mysql-proxy/bin
14

15
prog=“mysql-proxy”
16

17

Source networking configuration.

18
. /etc/sysconfig/network
19

20

Check that networking is up.

21
[ ${NETWORKING} = “no” ] && exit 0
22

23

Set default mysql-proxy configuration.

24
#PROXY_OPTIONS="–daemon"
25
PROXY_OPTIONS="–admin-username=root --admin-password=password --proxy-read-only-backend-addresses=192.168.10.131:3306 --proxy-backend-addresses=192.168.10.130:3306 --admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua --proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua"
26
PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid
27

28

Source mysql-proxy configuration.

29
if [ -f /etc/sysconfig/mysql-proxy ]; then
30
. /etc/sysconfig/mysql-proxy
31
fi
32

33
PATH= P A T H : / u s r / b i n : / u s r / l o c a l / b i n : PATH:/usr/bin:/usr/local/bin: PATH:/usr/bin:/usr/local/bin:PROXY_PATH
34

35

By default it’s all good

36
RETVAL=0
37

38

See how we were called.

39
case “$1” in
40
start)
41
# Start daemon.
42
echo -n $"Starting $prog: "
43

NICELEVEL
NICELEVEL
PROXY_PATH/mysql-proxy P R O X Y O P T I O N S − − d a e m o n − − p i d − f i l e = PROXY_OPTIONS --daemon --pid-file= PROXYOPTIONSdaemonpidfile=PROXY_PID --user=mysql --log-level=warning --log-file=/opt/mysql-proxy/log/mysql-proxy.log
44
RETVAL=$?
45
echo
46
if [ $RETVAL = 0 ]; then
47
touch /var/lock/subsys/mysql-proxy
48
fi
49
;;
50
stop)
51
# Stop daemons.
52
echo -n $"Stopping $prog: "
53
killproc p r o g 54 R E T V A L = prog 54 RETVAL= prog54RETVAL=?
55
echo
56
if [ $RETVAL = 0 ]; then
57
rm -f /var/lock/subsys/mysql-proxy
58
rm -f $PROXY_PID
59
fi
60
;;
61
restart)
62
$0 stop
63
sleep 3
64
$0 start
65
;;
66
condrestart)
67
[ -e /var/lock/subsys/mysql-proxy ] && 0 r e s t a r t 68 ; ; 69 s t a t u s ) 70 s t a t u s m y s q l − p r o x y 71 R E T V A L = 0 restart 68 ;; 69 status) 70 status mysql-proxy 71 RETVAL= 0restart68;;69status)70statusmysqlproxy71RETVAL=?
72
;;
73
*)
74
echo “Usage: $0 {start|stop|restart|status|condrestart}”
75
RETVAL=1
76
;;
77
esac
78

79
exit $RETVAL
脚本参数详解:

PROXY_PATH=/opt/mysql-proxy/bin //定义mysql-proxy服务二进制文件路径
PROXY_OPTIONS="–admin-username=root \ //定义内部管理服务器账号
–admin-password=password \ //定义内部管理服务器密码
–proxy-read-only-backend-addresses=192.168.10.131:3306 \ //定义后端只读从服务器地址
–proxy-backend-addresses=192.168.10.130:3306 \ //定义后端主服务器地址
–admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua \ //定义lua管理脚本路径
–proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua" \ //定义lua读写分离脚本路径
PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid //定义mysql-proxy PID文件路径
NICELEVEL
NICELEVEL
PROXY_PATH/mysql-proxy
PROX
Y
O
PTIONS −−daemon //定义以守护进程模式启动−−keepalive //使进程在异常关闭后能够自动恢复−−pid−file=
PROXYOPTIONS −−daemon //定义以守护进程模式启动−−keepalive //使进程在异常关闭后能够自动恢复−−pid−file=
PROXY_PID \ //定义mysql-proxy PID文件路径
–user=mysql \ //以mysql用户身份启动服务
–log-level=warning \ //定义log日志级别,由高到低分别有(error|warning|info|message|debug)
–log-file=/opt/mysql-proxy/log/mysql-proxy.log //定义log日志文件路径

cp mysql-proxy /opt/mysql-proxy/init.d/
chmod +x /opt/mysql-proxy/init.d/mysql-proxy
mkdir /opt/mysql-proxy/run
mkdir /opt/mysql-proxy/log
mkdir /opt/mysql-proxy/scripts
配置并使用rw-splitting.lua读写分离脚本
最新的脚本我们可以从最新的mysql-proxy源码包中获取
cd /opt/install
wget http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1.tar.gz
tar xzvf mysql-proxy-0.8.1.tar.gz
cd mysql-proxy-0.8.1
cp lib/rw-splitting.lua /opt/mysql-proxy/scripts
修改读写分离脚本rw-splitting.lua
修改默认连接,进行快速测试,不修改的话要达到连接数为4时才启用读写分离
vim /opt/mysql-proxy/scripts/rw-splitting.lua

– connection pool
if not proxy.global.config.rwsplit then
proxy.global.config.rwsplit = {
min_idle_connections = 1, //默认为4
max_idle_connections = 1, //默认为8
is_debug = false
}
end

修改完成后,启动mysql-proxy
/opt/mysql-proxy/init.d/mysql-proxy start
3.5 测试读写分离效果
创建用于读写分离的数据库连接用户
登陆主数据库服务器192.168.10.130,通过命令行登录管理MySQL服务器
/opt/mysql/bin/mysql -uroot -p’new-password’
mysql> GRANT ALL ON . TO ‘proxy1’@‘192.168.10.132’ IDENTIFIED BY ‘password’;
由于我们配置了主从复制功能,因此从数据库服务器192.168.10.131上已经同步了此操作。
为了清晰的看到读写分离的效果,需要暂时关闭MySQL主从复制功能
登陆从数据库服务器192.168.10.131,通过命令行登录管理MySQL服务器
/opt/mysql/bin/mysql -uroot -p’new-password’
关闭Slave同步进程
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
连接MySQL-Proxy
/opt/mysql/bin/mysql -uproxy1 -p’password’ -P4040 -h192.168.10.132
登陆成功后,在first_db数据的first_tb表中插入两条记录
mysql> use first_db;
Database changed
mysql> insert into first_tb values (007,’first’);
Query Ok, 1 row affected (0.00 sec)
mysql> insert into first_tb values (110,’second’);
Query Ok, 1 row affected (0.00 sec)
查询记录
mysql> select * from first_tb;

±-----±-----+
| id | name |
±-----±-----+
| 1 | myself |
±-----±-----+
1 rows in set (0.00 sec)

通过读操作并没有看到新记录
mysql> quit
退出MySQL-Proxy
下面,分别登陆到主从数据库服务器,对比记录信息
首先,检查主数据库服务器
mysql> select * from first_tb;

±-----±-----+
| id | name |
±-----±-----+
| 1 | myself |
±-----±-----+
| 007 | first |
±-----±-----+
| 110 | second |
±-----±-----+
3 rows in set (0.00 sec)

两条新记录都已经存在
然后,检查从数据库服务器
mysql> select * from first_tb;

±-----±-----+
| id | name |
±-----±-----+
| 1 | myself |
±-----±-----+
1 rows in set (0.00 sec)

没有新记录存在
由此验证,我们已经实现了MySQL读写分离,目前所有的写操作都全部在Master主服务器上,用来避免数据的不同步;
另外,所有的读操作都分摊给了其它各个Slave从服务器上,用来分担数据库压力。
经验分享:
1.当MySQL主从复制在 show slave status\G 时出现Slave_IO_Running或Slave_SQL_Running 的值不为YES时,需要首先通过 stop slave 来停止从服务器,然后再执行一次本文 2.1与2.2 章节中的步骤即可恢复,但如果想尽可能的同步更多的数据,可以在Slave上将master_log_pos节点的值在之前同步失效的值的基础上增大一些,然后反复测试,直到同步OK。因为MySQL主从复制的原理其实就是从服务器读取主服务器的binlog,然后根据binlog的记录来更新数据库。
2.MySQL-Proxy的rw-splitting.lua脚本在网上有很多版本,但是最准确无误的版本仍然是源码包中所附带的lib/rw-splitting.lua脚本,如果有lua脚本编程基础的话,可以在这个脚本的基础上再进行优化;
3.MySQL-Proxy实际上非常不稳定,在高并发或有错误连接的情况下,进程很容易自动关闭,因此打开–keepalive参数让进程自动恢复是个比较好的办法,但还是不能从根本上解决问题,因此通常最稳妥的做法是在每个从服务器上安装一个MySQL-Proxy供自身使用,虽然比较低效但却能保证稳定性;
4.一主多从的架构并不是最好的架构,通常比较优的做法是通过程序代码和中间件等方面,来规划,比如设置对表数据的自增id值差异增长等方式来实现两个或多个主服务器,但一定要注意保证好这些主服务器数据的完整性,否则效果会比多个一主多从的架构还要差;
5.MySQL-Cluster 的稳定性也不是太好;
6.Amoeba for MySQL 是一款优秀的中间件软件,同样可以实现读写分离,负载均衡等功能,并且稳定性要大大超过MySQL-Proxy,建议大家用来替代MySQL-Proxy,甚至MySQL-Cluster。
三、 从数据库层面增强性能:优化SQL语句,合理使用字段索引
四、 从代码层面增强性能:使用缓存和NoSQL数据库方式存储,如MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力。
五、 减少数据库操作次数,尽量使用数据库访问驱动的批处理方法。
六、 不常使用的数据迁移备份,避免每次都在海量数据中去检索。
七、 提升数据库服务器硬件配置,或者搭建数据库集群。
编程手段防止SQL注入:使用JDBC PreparedStatement按位插入或查询;正则表达式过滤(非法字符串过滤

数据库的优化问题
参考文件链接地址: https://www.cnblogs.com/ycqi/p/10833617.html
数据库的优化主要从一下8点出发
一、 根据服务层面:配置mysql性能优化参数
1、 目的:
湖州街29号时瑞大厦6层
通过根据服务器目前状况,修改Mysql的系统参数,达到合理利用服务器现有资源,最大合理的提高MySQL性能。

2、服务器参数:
32G内存、4个CPU,每个CPU 8核。
3、MySQL目前安装状况。
MySQL目前安装,用的是MySQL默认的最大支持配置。拷贝的是my-huge.cnf.编码已修改为UTF-8.具体修改及安装MySQL,可以参考<<Linux系统上安装MySQL 5.5>>帮助文档。
4、修改MySQL配置
参考文件的位置: https://www.cnblogs.com/angryprogrammer/p/6667741.html
打开MySQL配置文件my.cnf

vi /etc/my.cnf
4.1 MySQL非缓存参数变量介绍及修改
4.1.1修改back_log参数值:由默认的50修改为500.(每个连接256kb,占用:125M)
back_log=500

back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。也就是说,如果MySql的连接数据达到max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。将会报:unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待连接进程时.

back_log值不能超过TCP/IP连接的侦听队列的大小。若超过则无效,查看当前系统的TCP/IP连接的侦听队列的大小命令:cat /proc/sys/net/ipv4/tcp_max_syn_backlog目前系统为1024。对于Linux系统推荐设置为小于512的整数。
修改系统内核参数,)http://www.51testing.com/html/64/n-810764.html
查看mysql 当前系统默认back_log值,命令:
show variables like ‘back_log’; 查看当前数量

4.1.2修改wait_timeout参数值,由默认的8小时,修改为30分钟。(本次不用)
wait_timeout=1800(单位为妙)

我对wait-timeout这个参数的理解:MySQL客户端的数据库连接闲置最大时间值。
说得比较通俗一点,就是当你的MySQL连接闲置超过一定时间后将会被强行关闭。MySQL默认的wait-timeout 值为8个小时,可以通过命令show variables like 'wait_timeout’查看结果值;。
设置这个值是非常有意义的,比如你的网站有大量的MySQL链接请求(每个MySQL连接都是要内存资源开销的 ),由于你的程序的原因有大量的连接请求空闲啥事也不干,白白占用内存资源,或者导致MySQL超过最大连接数从来无法新建连接导致“Too many connections”的错误。在设置之前你可以查看一下你的MYSQL的状态(可用show processlist),如果经常发现MYSQL中有大量的Sleep进程,则需要 修改wait-timeout值了。
interactive_timeout:服务器关闭交互式连接前等待活动的秒数。交互式客户端定义为在mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。
wait_timeout:服务器关闭非交互连接之前等待活动的秒数。在线程启动时,根据全局wait_timeout值或全局 interactive_timeout值初始化会话wait_timeout值,取决于客户端类型(由mysql_real_connect()的连接选项CLIENT_INTERACTIVE定义).
这两个参数必须配合使用。否则单独设置wait_timeout无效

4.1.3修改max_connections参数值,由默认的151,修改为3000(750M)。
max_connections=3000
max_connections是指MySql的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySql会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。可以过’conn%'通配符查看当前状态的连接数量,以定夺该值的大小。
MySQL服务器允许的最大连接数16384;
查看系统当前最大连接数:
show variables like ‘max_connections’;

4.1…4修改max_user_connections值,由默认的0,修改为800
max_user_connections=800
max_user_connections是指每个数据库用户的最大连接
针对某一个账号的所有客户端并行连接到MYSQL服务的最大并行连接数。简单说是指同一个账号能够同时连接到mysql服务的最大连接数。设置为0表示不限制。
目前默认值为:0不受限制。
这儿顺便介绍下Max_used_connections:它是指从这次mysql服务启动到现在,同一时刻并行连接数的最大值。它不是指当前的连接情况,而是一个比较值。如果在过去某一个时刻,MYSQL服务同时有1000个请求连接过来,而之后再也没有出现这么大的并发请求时,则Max_used_connections=1000.请注意与show variables 里的max_user_connections的区别。默认为0表示无限大。
查看max_user_connections值
show variables like ‘max_user_connections’;

4.1.5修改thread_concurrency值,由目前默认的8,修改为64
thread_concurrency=64
thread_concurrency的值的正确与否, 对mysql的性能影响很大, 在多个cpu(或多核)的情况下,错误设置了thread_concurrency的值, 会导致mysql不能充分利用多cpu(或多核), 出现同一时刻只能一个cpu(或核)在工作的情况。
thread_concurrency应设为CPU核数的2倍. 比如有一个双核的CPU, 那thread_concurrency 的应该为4; 2个双核的cpu, thread_concurrency的值应为8.
比如:根据上面介绍我们目前系统的配置,可知道为4个CPU,每个CPU为8核,按照上面的计算规则,这儿应为:482=64
查看系统当前thread_concurrency默认配置命令:
show variables like ‘thread_concurrency’;

4.1.6添加skip-name-resolve,默认被注释掉,没有该参数。
skip-name-resolve
skip-name-resolve:禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项,则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求!
4.1.7 skip-networking,默认被注释掉。没有该参数。(本次无用)
skip-networking建议被注释掉,不要开启
开启该选项可以彻底关闭MySQL的TCP/IP连接方式,如果WEB服务器是以远程连接的方式访问MySQL数据库服务器则不要开启该选项!否则将无法正常连接!
4.1.8 default-storage-engine(设置MySQL的默认存储引擎)
default-storage-engine= InnoDB(设置InnoDB类型,另外还可以设置MyISAM类型)
设置创建数据库及表默认存储类型
show table status like ‘tablename’显示表的当前存储状态值
查看MySQL有哪些存储状态及默认存储状态
show engines;
创建表并指定存储类型
CREATE TABLE mytable (id int, title char(20)) ENGINE = INNODB;
修改表存储类型:
Alter table tableName engine =engineName

备注:设置完后把以下几个开启:

Uncomment the following if you are using InnoDB tables

innodb_data_home_dir = /var/lib/mysql
#innodb_data_file_path = ibdata1:1024M;ibdata2:10M:autoextend(要注释掉,否则会创建一个新的把原来的替换的。)
innodb_log_group_home_dir = /var/lib/mysql

You can set …_buffer_pool_size up to 50 - 80 %

of RAM but beware of setting memory usage too high

innodb_buffer_pool_size = 1000M
innodb_additional_mem_pool_size = 20M

Set …_log_file_size to 25 % of buffer pool size

innodb_log_file_size = 500M
innodb_log_buffer_size = 20M
innodb_flush_log_at_trx_commit = 0
innodb_lock_wait_timeout = 50
设置完后一定记得把MySQL安装目录地址(我们目前是默认安装所以地址/var/lib/mysql/)下的ib_logfile0和ib_logfile1删除掉。否则重启MySQL起动失败。

4.2 MySQL缓存变量介绍及修改
数据库属于IO密集型的应用程序,其主职责就是数据的管理及存储工作。而我们知道,从内存中读取一个数据库的时间是微秒级别,而从一块普通硬盘上读取一个 IO是在毫秒级别,二者相差3个数量级。所以,要优化数据库,首先第一步需要优化的就是IO,尽可能将磁盘IO转化为内存IO。本文先从MySQL数据库 IO相关参数(缓存参数)的角度来看看可以通过哪些参数进行IO优化

4.2.1全局缓存
启动MySQL时就要分配并且总是存在的全局缓存。目前有:key_buffer_size(默认值:402653184,即384M)、innodb_buffer_pool_size(默认值:134217728即:128M)、innodb_additional_mem_pool_size(默认值:8388608即:8M)、innodb_log_buffer_size(默认值:8388608即:8M)、query_cache_size(默认值:33554432即:32M)等五个。总共:560M.
这些变量值都可以通过命令如:show variables like ‘变量名’;查看到。

4.2.1.1:key_buffer_size,本系统目前为384M,可修改为400M
key_buffer_size=400M
key_buffer_size是用于索引块的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),对MyISAM(MySQL表存储的一种类型,可以百度等查看详情)表性能影响最大的一个参数。如果你使它太大,系统将开始换页并且真的变慢了。严格说是它决定了数据库索引处理的速度,尤其是索引读的速度。对于内存在4GB左右的服务器该参数可设置为256M或384M.
怎么才能知道key_buffer_size的设置是否合理呢,一般可以检查状态值Key_read_requests和Key_reads ,比例key_reads / key_read_requests应该尽可能的低,比如1:100,1:1000 ,1:10000。其值可以用以下命令查得:show status like ‘key_read%’;
比如查看系统当前key_read和key_read_request值为:
±------------------±------+
| Variable_name | Value |
±------------------±------+
| Key_read_requests | 28535 |
| Key_reads | 269 |
±------------------±------+
可知道有28535个请求,有269个请求在内存中没有找到直接从硬盘读取索引.
未命中缓存的概率为:0.94%=269/28535100%. 一般未命中概率在0.1之下比较好。目前已远远大于0.1,证明效果不好。若命中率在0.01以下,则建议适当的修改key_buffer_size值。
http://dbahacker.com/mysql/innodb-myisam-compare(InnoDB与MyISAM的六大区别)
http://kb.cnblogs.com/page/99810/(查看存储引擎介绍)
MyISAM、InnoDB、MyISAM Merge引擎、InnoDB、memory(heap)、archive
4.2.1.2:innodb_buffer_pool_size(默认128M)
innodb_buffer_pool_size=1024M(1G)
innodb_buffer_pool_size:主要针对InnoDB表性能影响最大的一个参数。功能与Key_buffer_size一样。InnoDB占用的内存,除innodb_buffer_pool_size用于存储页面缓存数据外,另外正常情况下还有大约8%的开销,主要用在每个缓存页帧的描述、adaptive hash等数据结构,如果不是安全关闭,启动时还要恢复的话,还要另开大约12%的内存用于恢复,两者相加就有差不多21%的开销。假设:12G的innodb_buffer_pool_size,最多的时候InnoDB就可能占用到14.5G的内存。若系统只有16G,而且只运行MySQL,且MySQL只用InnoDB,
那么为MySQL开12G,是最大限度地利用内存了。
另外InnoDB和 MyISAM 存储引擎不同, MyISAM 的 key_buffer_size 只能缓存索引键,而 innodb_buffer_pool_size 却可以缓存数据块和索引键。适当的增加这个参数的大小,可以有效的减少 InnoDB 类型的表的磁盘 I/O 。
当我们操作一个 InnoDB 表的时候,返回的所有数据或者去数据过程中用到的任何一个索引块,都会在这个内存区域中走一遭。
可以通过 (Innodb_buffer_pool_read_requests – Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests * 100% 计算缓存命中率,并根据命中率来调整 innodb_buffer_pool_size 参数大小进行优化。值可以用以下命令查得:show status like ‘Innodb_buffer_pool_read%’;
比如查看当前系统中系统中
| Innodb_buffer_pool_read_requests | 1283826 |
| Innodb_buffer_pool_reads | 519 |
±--------------------------------------±--------+
其命中率99.959%=(1283826-519)/1283826
100% 命中率越高越好。
4.2.1.3:innodb_additional_mem_pool_size(默认8M)
innodb_additional_mem_pool_size=20M
innodb_additional_mem_pool_size 设置了InnoDB存储引擎用来存放数据字典信息以及一些内部数据结构的内存空间大小,所以当我们一个MySQL Instance中的数据库对象非常多的时候,是需要适当调整该参数的大小以确保所有数据都能存放在内存中提高访问效率的。
这个参数大小是否足够还是比较容易知道的,因为当过小的时候,MySQL会记录Warning信息到数据库的error log中,这时候你就知道该调整这个参数大小了。
查看当前系统mysql的error日志 cat /var/lib/mysql/机器名.error 发现有很多waring警告。所以要调大为20M.
根据MySQL手册,对于2G内存的机器,推荐值是20M。
32G内存的 100M
4.2.1.4:innodb_log_buffer_size(默认8M)
innodb_log_buffer_size=20M
innodb_log_buffer_size 这是InnoDB存储引擎的事务日志所使用的缓冲区。类似于Binlog Buffer,InnoDB在写事务日志的时候,为了提高性能,也是先将信息写入Innofb Log Buffer中,当满足innodb_flush_log_trx_commit参数所设置的相应条件(或者日志缓冲区写满)之后,才会将日志写到文件 (或者同步到磁盘)中。可以通过innodb_log_buffer_size 参数设置其可以使用的最大内存空间。
InnoDB 将日志写入日志磁盘文件前的缓冲大小。理想值为 1M 至 8M。大的日志缓冲允许事务运行时不需要将日志保存入磁盘而只到事务被提交(commit)。 因此,如果有大的事务处理,设置大的日志缓冲可以减少磁盘I/O。 在 my.cnf中以数字格式设置。
默认是8MB,系的如频繁的系统可适当增大至4MB~8MB。当然如上面介绍所说,这个参数实际上还和另外的flush参数相关。一般来说不建议超过32MB
注:innodb_flush_log_trx_commit参数对InnoDB Log的写入性能有非常关键的影响,默认值为1。该参数可以设置为0,1,2,解释如下:
0:log buffer中的数据将以每秒一次的频率写入到log file中,且同时会进行文件系统到磁盘的同步操作,但是每个事务的commit并不会触发任何log buffer 到log file的刷新或者文件系统到磁盘的刷新操作;
1:在每次事务提交的时候将log buffer 中的数据都会写入到log file,同时也会触发文件系统到磁盘的同步;
2:事务提交会触发log buffer到log file的刷新,但并不会触发磁盘文件系统到磁盘的同步。此外,每秒会有一次文件系统到磁盘同步操作。
实际测试发现,该值对插入数据的速度影响非常大,设置为2时插入10000条记录只需要2秒,设置为0时只需要1秒,而设置为1时则需要229秒。因此,MySQL手册也建议尽量将插入操作合并成一个事务,这样可以大幅提高速度。根据MySQL手册,在存在丢失最近部分事务的危险的前提下,可以把该值设为0。

4.5.1.5:query_cache_size(默认32M)
query_cache_size=40M
query_cache_size: 主要用来缓存MySQL中的ResultSet,也就是一条SQL语句执行的结果集,所以仅仅只能针对select语句。当我们打开了 Query Cache功能,MySQL在接受到一条select语句的请求后,如果该语句满足Query Cache的要求(未显式说明不允许使用Query Cache,或者已经显式申明需要使用Query Cache),MySQL会直接根据预先设定好的HASH算法将接受到的select语句以字符串方式进行hash,然后到Query Cache中直接查找是否已经缓存。也就是说,如果已经在缓存中,该select请求就会直接将数据返回,从而省略了后面所有的步骤(如SQL语句的解析,优化器优化以及向存储引擎请求数据等),极大的提高性能。根据MySQL用户手册,使用查询缓冲最多可以达到238%的效率。
当然,Query Cache也有一个致命的缺陷,那就是当某个表的数据有任何任何变化,都会导致所有引用了该表的select语句在Query Cache中的缓存数据失效。所以,当我们的数据变化非常频繁的情况下,使用Query Cache可能会得不偿失
Query Cache的使用需要多个参数配合,其中最为关键的是query_cache_size和query_cache_type,前者设置用于缓存 ResultSet的内存大小,后者设置在何场景下使用Query Cache。在以往的经验来看,如果不是用来缓存基本不变的数据的MySQL数据库,query_cache_size一般256MB是一个比较合适的大小。当然,这可以通过计算Query Cache的命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))来进行调整。 query_cache_type可以设置为0(OFF),1(ON)或者2(DEMOND),分别表示完全不使用query cache,除显式要求不使用query cache(使用sql_no_cache)之外的所有的select都使用query cache,只有显示要求才使用query cache(使用sql_cache)。如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲. 如果Qcache_hits的值也非常大,则表明查询缓冲使用非常频繁,此时需要增加缓冲大小;
根据命中率(Qcache_hits/(Qcache_hits+Qcache_inserts)*100))进行调整,一般不建议太大,256MB可能已经差不多了,大型的配置型静态数据可适当调大.
可以通过命令:show status like ‘Qcache_%’;查看目前系统Query catch使用大小
| Qcache_hits | 1892463 |
| Qcache_inserts | 35627
命中率98.17%=1892463/(1892463 +35627 )*100
4.2.2局部缓存
除了全局缓冲,MySql还会为每个连接发放连接缓冲。个连接到MySQL服务器的线程都需要有自己的缓冲。大概需要立刻分配256K,甚至在线程空闲时,它们使用默认的线程堆栈,网络缓存等。事务开始之后,则需要增加更多的空间。运行较小的查询可能仅给指定的线程增加少量的内存消耗,然而如果对数据表做复杂的操作例如扫描、排序或者需要临时表,则需分配大约read_buffer_size,
sort_buffer_size,read_rnd_buffer_size,tmp_table_size 大小的内存空间. 不过它们只是在需要的时候才分配,并且在那些操作做完之后就释放了。有的是立刻分配成单独的组块。tmp_table_size 可能高达MySQL所能分配给这个操作的最大内存空间了
。注意,这里需要考虑的不只有一点——可能会分配多个同一种类型的缓存,例如用来处理子查询。一些特殊的查询的内存使用量可能更大——如果在MyISAM表上做成批的插入
时需要分配 bulk_insert_buffer_size 大小的内存;执行 ALTER TABLE, OPTIMIZE TABLE, REPAIR TABLE 命令时需要分配 myisam_sort_buffer_size 大小的内存。
4.2.2.1:read_buffer_size(默认值:2097144即2M)
read_buffer_size=4M
read_buffer_size 是MySql读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分配一段内存缓冲区。read_buffer_size变量控制这一
缓冲区的大小。如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能.

4.2.2.2:sort_buffer_size(默认值:2097144即2M)
sort_buffer_size=4M
sort_buffer_size是MySql执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。如果不能,可以尝试增加sort_buffer_size变量的大小
4.2.2.3: read_rnd_buffer_size(默认值:8388608即8M)
read_rnd_buffer_size=8M
read_rnd_buffer_size 是MySql的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySql会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开
销过大。
4.2.2.4: tmp_table_size(默认值:8388608 即:16M)
tmp_table_size=16M
tmp_table_size是MySql的heap (堆积)表缓冲大小。所有联合在一个DML指令内完成,并且大多数联合甚至可以不用临时表即可以完成。大多数临时表是基于内
存的(HEAP)表。具有大的记录长度的临时表 (所有列的长度的和)或包含BLOB列的表存储在硬盘上。如果某个内部heap(堆积)表大小超过tmp_table_size,MySQL可以根据需要自
动将内存中的heap表改为基于硬盘的MyISAM表。还可以通过设置tmp_table_size选项来增加临时表的大小。也就是说,如果调高该值,MySql同时将增加heap表的大小,可达到提高
联接查询速度的效果。
4.2.2.5:record_buffer:(默认值:)
record_buffer每个进行一个顺序扫描的线程为其扫描的每张表分配这个大小的一个缓冲区。如果你做很多顺序扫描,你可能想要增加该值。默认数值是131072
(128K)
4.2.3其它缓存:
4.2.3.1:table_cache(默认值:512)

TABLE_CACHE(5.1.3及以后版本又名TABLE_OPEN_CACHE)
table_cache指定表高速缓存的大小。每当MySQL访问一个表时,如果在表缓冲区中还有空间,该表就被打开并放入其中,这样可以更快地访问表内容。通过检查峰值时间的状态值Open_tables和Opened_tables,可以决定是否需要增加table_cache的值。如果你发现open_tables等于table_cache,并且opened_tables在不断增长,那么你就需要增加table_cache的值了(上述状态值可以使用SHOW STATUS LIKE ‘Open%tables’获得)。注意,不能盲目地把table_cache设置成很大的值。如果设置得太高,可能会造成文件描述符不足,从而造成性能不稳定或者连接失败。
SHOW STATUS LIKE ‘Open%tables’;
±--------------±------+
| Variable_name | Value |
±--------------±------+
| Open_tables | 356 |
| Opened_tables | 0 |
±--------------±------+
2 rows in set (0.00 sec)
open_tables表示当前打开的表缓存数,如果执行flush tables操作,则此系统会关闭一些当前没有使用的表缓存而使得此状态值减小;
opend_tables表示曾经打开的表缓存数,会一直进行累加,如果执行flush tables操作,值不会减小。
在mysql默认安装情况下,table_cache的值在2G内存以下的机器中的值默认时256到512,如果机器有4G内存,则默认这个值 是2048,但这决意味着机器内存越大,这个值应该越大,因为table_cache加大后,使得mysql对SQL响应的速度更快了,不可避免的会产生 更多的死锁(dead lock),这样反而使得数据库整个一套操作慢了下来,严重影响性能。所以平时维护中还是要根据库的实际情况去作出判断,找到最适合你维护的库的 table_cache值。
由于MySQL是多线程的机制,为了提高性能,每个线程都是独自打开自己需要的表的文件描 述符,而不是通过共享已经打开的.针对不同存储引擎处理的方法当然也不一样
在myisam表引擎中,数据文件的描述符 (descriptor)是不共享的,但是索引文件的描述符却是所有线程共享的.Innodb中和使用表空间类型有关,假如是共享表空间那么实际就一个数 据文件,当然占用的数据文件描述符就会比独立表空间少.
mysql手册上给的建议大小 是:table_cache=max_connections*n
n表示查询语句中最大表数, 还需要为临时表和文件保留一些额外的文件描述符。
这个数据遭到很多质疑,table_cache够用就好,检查 Opened_tables值,如果这个值很大,或增长很快那么你就得考虑加大table_cache了.
table_cache:所有线程打开的表的数目。增大该值可以增加mysqld需要的文件描述符的数量。默认值是64.

4.2.3.2 thread_cache_size (服务器线程缓存)
thread_cache_size=64

默认的thread_cache_size=8,但是看到好多配置的样例里的值一般是32,64,甚至是128,感觉这个参数对优化应该有帮助,于是查了下:
根据调查发现以上服务器线程缓存thread_cache_size没有进行设置,或者设置过小,这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中,如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,增加这个值可以改善系统性能.通过比较 Connections 和 Threads_created 状态的变量,可以看到这个变量的作用。(–>表示要调整的值) 根据物理内存设置规则如下:
1G —> 8
2G —> 16
3G —> 32 >3G —> 64
mysql> show status like ‘thread%’;
+——————-+——-+
| Variable_name | Value |
+——————-+——-+
| Threads_cached | 0 | <—当前被缓存的空闲线程的数量
| Threads_connected | 1 | <—正在使用(处于连接状态)的线程
| Threads_created | 1498 | <—服务启动以来,创建了多少个线程
| Threads_running | 1 | <—正在忙的线程(正在查询数据,传输数据等等操作)
+——————-+——-+
查看开机起来数据库被连接了多少次?
mysql> show status like ‘%connection%’;
+———————-+——-+
| Variable_name | Value |
+———————-+——-+
| Connections | 1504 | –>服务启动以来,历史连接数
| Max_used_connections | 2 |
+———————-+——-+
通过连接线程池的命中率来判断设置值是否合适?命中率超过90%以上,设定合理。
(Connections - Threads_created) / Connections * 100 %
二、 从系统层面增强mysql的性能:优化数据表结构、字段类型、字段索引、分表,分库、读写分离等等
表结构:数据类型选择;字符编码;适当拆分;适度冗余;尽量使用 NOT NULL 详细, 读写分离

表结构的优化:
https://www.cnblogs.com/eeds-wangwei/p/8135771.html
由于MySQL数据库是基于行(Row)存储的数据库,而数据库操作 IO 的时候是以 page(block)的方式,也就是说,如果我们每条记录所占用的空间量减小,就会使每个page中可存放的数据行数增大,那么每次 IO 可访问的行数也就增多了。反过来说,处理相同行数的数据,需要访问的 page 就会减少,也就是 IO 操作次数降低,直接提升性能。此外,由于我们的内存是有限的,增加每个page中存放的数据行数,就等于增加每个内存块的缓存数据量,同时还会提升内存换中数据命中的几率,也就是缓存命中率。
一、数据类型选择
数据库操作中最为耗时的操作就是 IO 处理,大部分数据库操作 90% 以上的时间都花在了 IO 读写上面。所以尽可能减少 IO 读写量,可以在很大程度上提高数据库操作的性能。
我们无法改变数据库中需要存储的数据,但是我们可以在这些数据的存储方式方面花一些心思。下面的这些关于字段类型的优化建议主要适用于记录条数较多,数据量较大的场景,因为精细化的数据类型设置可能带来维护成本的提高,过度优化也可能会带来其他的问题:
  1.数字类型:非万不得已不要使用DOUBLE,不仅仅只是存储长度的问题,同时还会存在精确性的问题。同样,固定精度的小数,也不建议使用DECIMAL,建议乘以固定倍数转换成整数存储,可以大大节省存储空间,且不会带来任何附加维护成本。对于整数的存储,在数据量较大的情况下,建议区分开 TINYINT / INT / BIGINT 的选择,因为三者所占用的存储空间也有很大的差别,能确定不会使用负数的字段,建议添加unsigned定义。当然,如果数据量较小的数据库,也可以不用严格区分三个整数类型。
  2.字符类型:非万不得已不要使用 TEXT 数据类型,其处理方式决定了他的性能要低于char或者是varchar类型的处理。定长字段,建议使用 CHAR 类型,不定长字段尽量使用 VARCHAR,且仅仅设定适当的最大长度,而不是非常随意的给一个很大的最大长度限定,因为不同的长度范围,MySQL也会有不一样的存储处理。
  3.时间类型:尽量使用TIMESTAMP类型,因为其存储空间只需要 DATETIME 类型的一半。对于只需要精确到某一天的数据类型,建议使用DATE类型,因为他的存储空间只需要3个字节,比TIMESTAMP还少。不建议通过INT类型类存储一个unix timestamp 的值,因为这太不直观,会给维护带来不必要的麻烦,同时还不会带来任何好处。
  4.ENUM & SET:对于状态字段,可以尝试使用 ENUM 来存放,因为可以极大的降低存储空间,而且即使需要增加新的类型,只要增加于末尾,修改结构也不需要重建表数据。如果是存放可预先定义的属性数据呢?可以尝试使用SET类型,即使存在多种属性,同样可以游刃有余,同时还可以节省不小的存储空间。
  5.LOB类型:强烈反对在数据库中存放 LOB 类型数据,虽然数据库提供了这样的功能,但这不是他所擅长的,我们更应该让合适的工具做他擅长的事情,才能将其发挥到极致。在数据库中存储 LOB 数据就像让一个多年前在学校学过一点Java的营销专业人员来写 Java 代码一样。
二、字符编码
字符集直接决定了数据在MySQL中的存储编码方式,由于同样的内容使用不同字符集表示所占用的空间大小会有较大的差异,所以通过使用合适的字符集,可以帮助我们尽可能减少数据量,进而减少IO操作次数。
  1.纯拉丁字符能表示的内容,没必要选择 latin1 之外的其他字符编码,因为这会节省大量的存储空间。
  2.如果我们可以确定不需要存放多种语言,就没必要非得使用UTF8或者其他UNICODE字符类型,这回造成大量的存储空间浪费。
  3.MySQL的数据类型可以精确到字段,所以当我们需要大型数据库中存放多字节数据的时候,可以通过对不同表不同字段使用不同的数据类型来较大程度减小数据存储量,进而降低 IO 操作次数并提高缓存命中率。
三、适当拆分
有些时候,我们可能会希望将一个完整的对象对应于一张数据库表,这对于应用程序开发来说是很有好的,但是有些时候可能会在性能上带来较大的问题。
  当我们的表中存在类似于 TEXT 或者是很大的 VARCHAR类型的大字段的时候,如果我们大部分访问这张表的时候都不需要这个字段,我们就该义无反顾的将其拆分到另外的独立表中,以减少常用数据所占用的存储空间。这样做的一个明显好处就是每个数据块中可以存储的数据条数可以大大增加,既减少物理 IO 次数,也能大大提高内存中的缓存命中率。
  上面几点的优化都是为了减少每条记录的存储空间大小,让每个数据库中能够存储更多的记录条数,以达到减少 IO 操作次数,提高缓存命中率。下面这个优化建议可能很多开发人员都会觉得不太理解,因为这是典型的反范式设计,而且也和上面的几点优化建议的目标相违背。
四、适度冗余
为什么我们要冗余?这不是增加了每条数据的大小,减少了每个数据块可存放记录条数吗?
  确实,这样做是会增大每条记录的大小,降低每条记录中可存放数据的条数,但是在有些场景下我们仍然还是不得不这样做:
  1.被频繁引用且只能通过 Join 2张(或者更多)大表的方式才能得到的独立小字段。
  2.这样的场景由于每次Join仅仅只是为了取得某个小字段的值,Join到的记录又大,会造成大量不必要的 IO,完全可以通过空间换取时间的方式来优化。不过,冗余的同时需要确保数据的一致性不会遭到破坏,确保更新的同时冗余字段也被更新。
五、尽量使用 NOT NULL
NULL 类型比较特殊,SQL 难优化。虽然 MySQL NULL类型和 Oracle 的NULL 有差异,会进入索引中,但如果是一个组合索引,那么这个NULL 类型的字段会极大影响整个索引的效率。此外,NULL 在索引中的处理也是特殊的,也会占用额外的存放空间。
  很多人觉得 NULL 会节省一些空间,所以尽量让NULL来达到节省IO的目的,但是大部分时候这会适得其反,虽然空间上可能确实有一定节省,倒是带来了很多其他的优化问题,不但没有将IO量省下来,反而加大了SQL的IO量。所以尽量确保 DEFAULT 值不是 NULL,也是一个很好的表结构设计优化习惯。

主从配置 读写分离
https://www.cnblogs.com/luckcs/articles/2543607.html
MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践
Mysql作为目前世界上使用最广泛的免费数据库,相信所有从事系统运维的工程师都一定接触过。但在实际的生产环境中,由单台Mysql作为独立的数据库是完全不能满足实际需求的,无论是在安全性,高可用性以及高并发等各个方面。
因此,一般来说都是通过 主从复制(Master-Slave)的方式来同步数据,再通过读写分离(MySQL-Proxy)来提升数据库的并发负载能力 这样的方案来进行部署与实施的。
如下图所示:

下面是我在实际工作过程中所整理的笔记,在此分享出来,以供大家参考。
一、MySQL的安装与配置
具体的安装过程,建议参考我的这一篇文章:http://heylinux.com/archives/993.html
值得一提的是,我的安装过程都是源码包编译安装的,并且所有的配置与数据等都统一规划到了/opt/mysql目录中,因此在一台服务器上安装完成以后,可以将整个mysql目录打包,然后传到其它服务器上解包,便可立即使用。
二、MySQL主从复制
场景描述:
主数据库服务器:192.168.10.130,MySQL已经安装,并且无应用数据。
从数据库服务器:192.168.10.131,MySQL已经安装,并且无应用数据。
2.1 主服务器上进行的操作
启动mysql服务
/opt/mysql/init.d/mysql start
通过命令行登录管理MySQL服务器
/opt/mysql/bin/mysql -uroot -p’new-password’
授权给从数据库服务器192.168.10.131
mysql> GRANT REPLICATION SLAVE ON . to ‘rep1’@‘192.168.10.131’ identified by ‘password’;
查询主数据库状态
Mysql> show master status;
±-----------------±---------±-------------±-----------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
±-----------------±---------±-------------±-----------------+
| mysql-bin.000005 | 261 | | |
±-----------------±---------±-------------±-----------------+
记录下 FILE 及 Position 的值,在后面进行从服务器操作的时候需要用到。
2.2 配置从服务器
修改从服务器的配置文件/opt/mysql/etc/my.cnf
将 server-id = 1修改为 server-id = 10,并确保这个ID没有被别的MySQL服务所使用。
启动mysql服务
/opt/mysql/init.d/mysql start
通过命令行登录管理MySQL服务器
/opt/mysql/bin/mysql -uroot -p’new-password’
执行同步SQL语句
mysql> change master to
master_host=’192.168.10.130’,
master_user=’rep1’,
master_password=’password’,
master_log_file=’mysql-bin.000005’,
master_log_pos=261;
正确执行后启动Slave同步进程
mysql> start slave;
主从同步检查
mysql> show slave status\G

**************** 1. row *******************
Slave_IO_State:
Master_Host: 192.168.10.130
Master_User: rep1
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000005
Read_Master_Log_Pos: 415
Relay_Log_File: localhost-relay-bin.000008
Relay_Log_Pos: 561
Relay_Master_Log_File: mysql-bin.000005
Slave_IO_Running: YES
Slave_SQL_Running: YES
Replicate_Do_DB:
……………省略若干……………
Master_Server_Id: 1
1 row in set (0.01 sec)

其中Slave_IO_Running 与 Slave_SQL_Running 的值都必须为YES,才表明状态正常。
如果主服务器已经存在应用数据,则在进行主从复制时,需要做以下处理:
(1)主数据库进行锁表操作,不让数据再进行写入动作
mysql> FLUSH TABLES WITH READ LOCK;
(2)查看主数据库状态
mysql> show master status;
(3)记录下 FILE 及 Position 的值。
将主服务器的数据文件(整个/opt/mysql/data目录)复制到从服务器,建议通过tar归档压缩后再传到从服务器解压。
(4)取消主数据库锁定
mysql> UNLOCK TABLES;
2.3 验证主从复制效果
主服务器上的操作
在主服务器上创建数据库first_db
mysql> create database first_db;
Query Ok, 1 row affected (0.01 sec)
在主服务器上创建表first_tb
mysql> create table first_tb(id int(3),name char(10));
Query Ok, 1 row affected (0.00 sec)
在主服务器上的表first_tb中插入记录
mysql> insert into first_tb values (001,’myself’);
Query Ok, 1 row affected (0.00 sec)
在从服务器上查看
mysql> show databases;

±-------------------+
| Database |
±-------------------+
| information_schema |
| first_db |
| mysql |
| performance_schema |
| test |
±-------------------+
5 rows in set (0.01 sec)

数据库first_db已经自动生成
mysql> use first_db
Database chaged
mysql> show tables;

±-------------------+
| Tables_in_first_db |
±-------------------+
| first_tb |
±-------------------+
1 row in set (0.02 sec)

数据库表first_tb也已经自动创建
mysql> select * from first_tb;

±-----±-----+
| id | name |
±-----±-----+
| 1 | myself |
±-----±-----+
1 rows in set (0.00 sec)

记录也已经存在
由此,整个MySQL主从复制的过程就完成了,接下来,我们进行MySQL读写分离的安装与配置。
三、MySQL读写分离
场景描述:
数据库Master主服务器:192.168.10.130
数据库Slave从服务器:192.168.10.131
MySQL-Proxy调度服务器:192.168.10.132
以下操作,均是在192.168.10.132即MySQL-Proxy调度服务器 上进行的。
3.1 MySQL的安装与配置
具体的安装过程与上文相同。
3.2 检查系统所需软件包
通过 rpm -qa | grep name 的方式验证以下软件包是否已全部安装。
gcc* gcc-c++* autoconf* automake* zlib* libxml* ncurses-devel* libmcrypt* libtool* flex* pkgconfig*
libevent* glib*
若缺少相关的软件包,可通过yum -y install方式在线安装,或直接从系统安装光盘中找到并通过rpm -ivh方式安装。
3.3 编译安装lua
MySQL-Proxy的读写分离主要是通过rw-splitting.lua脚本实现的,因此需要安装lua。
lua可通过以下方式获得
从http://www.lua.org/download.html下载源码包
从rpm.pbone.net搜索相关的rpm包
download.fedora.redhat.com/pub/fedora/epel/5/i386/lua-5.1.4-4.el5.i386.rpm
download.fedora.redhat.com/pub/fedora/epel/5/x86_64/lua-5.1.4-4.el5.x86_64.rpm
这里我们建议采用源码包进行安装
cd /opt/install
wget http://www.lua.org/ftp/lua-5.1.4.tar.gz
tar zvfx lua-5.1.4.tar.gz
cd lua-5.1.4
vi src/Makefile
在 CFLAGS= -O2 -Wall
(MYCFLAGS)这一行记录里加上−fPIC,更改为CFLAGS=−O2−Wall−fPIC
(MYCFLAGS)这一行记录里加上−fPIC,更改为CFLAGS=−O2−Wall−fPIC
(MYCFLAGS) 来避免编译过程中出现错误。
make linux
make install
cp etc/lua.pc /usr/lib/pkgconfig/
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/pkgconfig
3.4 安装配置MySQL-Proxy
MySQL-Proxy可通过以下网址获得:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/
推荐采用已经编译好的二进制版本,因为采用源码包进行编译时,最新版的MySQL-Proxy对automake,glib以及libevent的版本都有很高的要求,而这些软件包都是系统的基础套件,不建议强行进行更新。
并且这些已经编译好的二进制版本在解压后都在统一的目录内,因此建议选择以下版本:
32位RHEL5平台:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
64位RHEL5平台:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-64bit.tar.gz
测试平台为RHEL5 32位,因此选择32位的软件包
wget http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
tar xzvf mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
mv mysql-proxy-0.8.1-linux-rhel5-x86-32bit /opt/mysql-proxy
创建mysql-proxy服务管理脚本
mkdir /opt/mysql-proxy/init.d/
vim mysql-proxy

01
#!/bin/sh
02

03

mysql-proxy This script starts and stops the mysql-proxy daemon

04

05

chkconfig: - 78 30

06

processname: mysql-proxy

07

description: mysql-proxy is a proxy daemon to mysql

08

09

Source function library.

10
. /etc/rc.d/init.d/functions
11

12
#PROXY_PATH=/usr/local/bin
13
PROXY_PATH=/opt/mysql-proxy/bin
14

15
prog=“mysql-proxy”
16

17

Source networking configuration.

18
. /etc/sysconfig/network
19

20

Check that networking is up.

21
[ ${NETWORKING} = “no” ] && exit 0
22

23

Set default mysql-proxy configuration.

24
#PROXY_OPTIONS="–daemon"
25
PROXY_OPTIONS="–admin-username=root --admin-password=password --proxy-read-only-backend-addresses=192.168.10.131:3306 --proxy-backend-addresses=192.168.10.130:3306 --admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua --proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua"
26
PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid
27

28

Source mysql-proxy configuration.

29
if [ -f /etc/sysconfig/mysql-proxy ]; then
30
. /etc/sysconfig/mysql-proxy
31
fi
32

33
PATH= P A T H : / u s r / b i n : / u s r / l o c a l / b i n : PATH:/usr/bin:/usr/local/bin: PATH:/usr/bin:/usr/local/bin:PROXY_PATH
34

35

By default it’s all good

36
RETVAL=0
37

38

See how we were called.

39
case “$1” in
40
start)
41
# Start daemon.
42
echo -n $"Starting $prog: "
43

NICELEVEL
NICELEVEL
PROXY_PATH/mysql-proxy P R O X Y O P T I O N S − − d a e m o n − − p i d − f i l e = PROXY_OPTIONS --daemon --pid-file= PROXYOPTIONSdaemonpidfile=PROXY_PID --user=mysql --log-level=warning --log-file=/opt/mysql-proxy/log/mysql-proxy.log
44
RETVAL=$?
45
echo
46
if [ $RETVAL = 0 ]; then
47
touch /var/lock/subsys/mysql-proxy
48
fi
49
;;
50
stop)
51
# Stop daemons.
52
echo -n $"Stopping $prog: "
53
killproc p r o g 54 R E T V A L = prog 54 RETVAL= prog54RETVAL=?
55
echo
56
if [ $RETVAL = 0 ]; then
57
rm -f /var/lock/subsys/mysql-proxy
58
rm -f $PROXY_PID
59
fi
60
;;
61
restart)
62
$0 stop
63
sleep 3
64
$0 start
65
;;
66
condrestart)
67
[ -e /var/lock/subsys/mysql-proxy ] && 0 r e s t a r t 68 ; ; 69 s t a t u s ) 70 s t a t u s m y s q l − p r o x y 71 R E T V A L = 0 restart 68 ;; 69 status) 70 status mysql-proxy 71 RETVAL= 0restart68;;69status)70statusmysqlproxy71RETVAL=?
72
;;
73
*)
74
echo “Usage: $0 {start|stop|restart|status|condrestart}”
75
RETVAL=1
76
;;
77
esac
78

79
exit $RETVAL
脚本参数详解:

PROXY_PATH=/opt/mysql-proxy/bin //定义mysql-proxy服务二进制文件路径
PROXY_OPTIONS="–admin-username=root \ //定义内部管理服务器账号
–admin-password=password \ //定义内部管理服务器密码
–proxy-read-only-backend-addresses=192.168.10.131:3306 \ //定义后端只读从服务器地址
–proxy-backend-addresses=192.168.10.130:3306 \ //定义后端主服务器地址
–admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua \ //定义lua管理脚本路径
–proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua" \ //定义lua读写分离脚本路径
PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid //定义mysql-proxy PID文件路径
NICELEVEL
NICELEVEL
PROXY_PATH/mysql-proxy
PROX
Y
O
PTIONS −−daemon //定义以守护进程模式启动−−keepalive //使进程在异常关闭后能够自动恢复−−pid−file=
PROXYOPTIONS −−daemon //定义以守护进程模式启动−−keepalive //使进程在异常关闭后能够自动恢复−−pid−file=
PROXY_PID \ //定义mysql-proxy PID文件路径
–user=mysql \ //以mysql用户身份启动服务
–log-level=warning \ //定义log日志级别,由高到低分别有(error|warning|info|message|debug)
–log-file=/opt/mysql-proxy/log/mysql-proxy.log //定义log日志文件路径

cp mysql-proxy /opt/mysql-proxy/init.d/
chmod +x /opt/mysql-proxy/init.d/mysql-proxy
mkdir /opt/mysql-proxy/run
mkdir /opt/mysql-proxy/log
mkdir /opt/mysql-proxy/scripts
配置并使用rw-splitting.lua读写分离脚本
最新的脚本我们可以从最新的mysql-proxy源码包中获取
cd /opt/install
wget http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1.tar.gz
tar xzvf mysql-proxy-0.8.1.tar.gz
cd mysql-proxy-0.8.1
cp lib/rw-splitting.lua /opt/mysql-proxy/scripts
修改读写分离脚本rw-splitting.lua
修改默认连接,进行快速测试,不修改的话要达到连接数为4时才启用读写分离
vim /opt/mysql-proxy/scripts/rw-splitting.lua

– connection pool
if not proxy.global.config.rwsplit then
proxy.global.config.rwsplit = {
min_idle_connections = 1, //默认为4
max_idle_connections = 1, //默认为8
is_debug = false
}
end

修改完成后,启动mysql-proxy
/opt/mysql-proxy/init.d/mysql-proxy start
3.5 测试读写分离效果
创建用于读写分离的数据库连接用户
登陆主数据库服务器192.168.10.130,通过命令行登录管理MySQL服务器
/opt/mysql/bin/mysql -uroot -p’new-password’
mysql> GRANT ALL ON . TO ‘proxy1’@‘192.168.10.132’ IDENTIFIED BY ‘password’;
由于我们配置了主从复制功能,因此从数据库服务器192.168.10.131上已经同步了此操作。
为了清晰的看到读写分离的效果,需要暂时关闭MySQL主从复制功能
登陆从数据库服务器192.168.10.131,通过命令行登录管理MySQL服务器
/opt/mysql/bin/mysql -uroot -p’new-password’
关闭Slave同步进程
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
连接MySQL-Proxy
/opt/mysql/bin/mysql -uproxy1 -p’password’ -P4040 -h192.168.10.132
登陆成功后,在first_db数据的first_tb表中插入两条记录
mysql> use first_db;
Database changed
mysql> insert into first_tb values (007,’first’);
Query Ok, 1 row affected (0.00 sec)
mysql> insert into first_tb values (110,’second’);
Query Ok, 1 row affected (0.00 sec)
查询记录
mysql> select * from first_tb;

±-----±-----+
| id | name |
±-----±-----+
| 1 | myself |
±-----±-----+
1 rows in set (0.00 sec)

通过读操作并没有看到新记录
mysql> quit
退出MySQL-Proxy
下面,分别登陆到主从数据库服务器,对比记录信息
首先,检查主数据库服务器
mysql> select * from first_tb;

±-----±-----+
| id | name |
±-----±-----+
| 1 | myself |
±-----±-----+
| 007 | first |
±-----±-----+
| 110 | second |
±-----±-----+
3 rows in set (0.00 sec)

两条新记录都已经存在
然后,检查从数据库服务器
mysql> select * from first_tb;

±-----±-----+
| id | name |
±-----±-----+
| 1 | myself |
±-----±-----+
1 rows in set (0.00 sec)

没有新记录存在
由此验证,我们已经实现了MySQL读写分离,目前所有的写操作都全部在Master主服务器上,用来避免数据的不同步;
另外,所有的读操作都分摊给了其它各个Slave从服务器上,用来分担数据库压力。
经验分享:
1.当MySQL主从复制在 show slave status\G 时出现Slave_IO_Running或Slave_SQL_Running 的值不为YES时,需要首先通过 stop slave 来停止从服务器,然后再执行一次本文 2.1与2.2 章节中的步骤即可恢复,但如果想尽可能的同步更多的数据,可以在Slave上将master_log_pos节点的值在之前同步失效的值的基础上增大一些,然后反复测试,直到同步OK。因为MySQL主从复制的原理其实就是从服务器读取主服务器的binlog,然后根据binlog的记录来更新数据库。
2.MySQL-Proxy的rw-splitting.lua脚本在网上有很多版本,但是最准确无误的版本仍然是源码包中所附带的lib/rw-splitting.lua脚本,如果有lua脚本编程基础的话,可以在这个脚本的基础上再进行优化;
3.MySQL-Proxy实际上非常不稳定,在高并发或有错误连接的情况下,进程很容易自动关闭,因此打开–keepalive参数让进程自动恢复是个比较好的办法,但还是不能从根本上解决问题,因此通常最稳妥的做法是在每个从服务器上安装一个MySQL-Proxy供自身使用,虽然比较低效但却能保证稳定性;
4.一主多从的架构并不是最好的架构,通常比较优的做法是通过程序代码和中间件等方面,来规划,比如设置对表数据的自增id值差异增长等方式来实现两个或多个主服务器,但一定要注意保证好这些主服务器数据的完整性,否则效果会比多个一主多从的架构还要差;
5.MySQL-Cluster 的稳定性也不是太好;
6.Amoeba for MySQL 是一款优秀的中间件软件,同样可以实现读写分离,负载均衡等功能,并且稳定性要大大超过MySQL-Proxy,建议大家用来替代MySQL-Proxy,甚至MySQL-Cluster。
三、 从数据库层面增强性能:优化SQL语句,合理使用字段索引
四、 从代码层面增强性能:使用缓存和NoSQL数据库方式存储,如MongoDB/Memcached/Redis来缓解高并发下数据库查询的压力。
五、 减少数据库操作次数,尽量使用数据库访问驱动的批处理方法。
六、 不常使用的数据迁移备份,避免每次都在海量数据中去检索。
七、 提升数据库服务器硬件配置,或者搭建数据库集群。
八、 编程手段防止SQL注入:使用JDBC PreparedStatement按位插入或查询;正则表达式过滤(非法字符串过滤)
1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.
备注、描述、评论之类的可以设置为 NULL,其他的,最好不要使用NULL。
不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。

可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num = 0

3.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。

4.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or Name = ‘admin’
可以这样查询:
select id from t where num = 10
union all
select id from t where Name = ‘admin’

5.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)

6.下面的查询也将导致全表扫描:
select id from t where name like ‘%abc%’
若要提高效率,可以考虑全文检索。

7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
select id from t where num = @num
可以改为强制查询使用索引:
select id from t with(index(索引名)) where num = @num
.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2 = 100
应改为:
select id from t where num = 100*2

9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3) = ’abc’ -–name以abc开头的id
select id from t where datediff(day,createdate,’2005-11-30′) = 0 -–‘2005-11-30’ --生成的id
应改为:
select id from t where name like ‘abc%’
select id from t where createdate >= ‘2005-11-30’ and createdate < ‘2005-12-1’

10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

12.不要写一些没有意义的查询,如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
create table #t(…)
13.Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志。

14.对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。

15.select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的。

16.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。

17.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。

18.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

19.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

20.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

21.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

  1. 避免频繁创建和删除临时表,以减少系统表资源的消耗。临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件, 最好使用导出表。

23.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

27.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时 间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。

29.尽量避免大事务操作,提高系统并发能力。

30.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

实际案例分析:拆分大的 DELETE 或INSERT 语句,批量提交SQL语句
  如果你需要在一个在线的网站上去执行一个大的 DELETE 或 INSERT 查询,你需要非常小心,要避免你的操作让你的整个网站停止相应。因为这两个操作是会锁表的,表一锁住了,别的操作都进不来了。
  Apache 会有很多的子进程或线程。所以,其工作起来相当有效率,而我们的服务器也不希望有太多的子进程,线程和数据库链接,这是极大的占服务器资源的事情,尤其是内存。
  如果你把你的表锁上一段时间,比如30秒钟,那么对于一个有很高访问量的站点来说,这30秒所积累的访问进程/线程,数据库链接,打开的文件数,可能不仅仅会让你的WEB服务崩溃,还可能会让你的整台服务器马上挂了。
所以,如果你有一个大的处理,你一定把其拆分,使用 LIMIT oracle(rownum),sqlserver(top)条件是一个好的方法。下面是一个mysql示例:

spring的4种事务特性,5种隔离级别,7种传播行为?

spring事务:

什么是事务: 
	事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败.
事务特性(4种): 
	原子性 (atomicity):强调事务的不可分割. 
	一致性 (consistency):事务的执行的前后数据的完整性保持一致. 
	隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰 
	持久性(durability) :事务一旦结束,数据就持久到数据库
如果不考虑隔离性引发安全性问题: 
	脏读 :一个事务读到了另一个事务的未提交的数据 
	不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致. 
	虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
解决读问题: 设置事务隔离级别(5种) 
	DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别. 
	未提交读 (read uncommited) :脏读,不可重复读,虚读都有可能发生 
	已提交读 (read commited):避免脏读。但是不可重复读和虚读有可能发生 
	可重复读 (repeatable read) :避免脏读和不可重复读.但是虚读有可能发生. 
	串行化的 (serializable) :避免以上所有读问题. 
	Mysql  默认:可重复读 
	Oracle 默认:读已提交

	read uncommited:是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。 
	read commited:保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。 
	repeatable read:这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)。 
	serializable:这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻象读(避免三种)。

事务的传播行为: 7种
	propagion_XXX :事务的传播行为 
	*保证同一个事务中 
	propagion_required: 支持当前事务,如果不存在 就新建一个(默认) 
	propagion_supports: 支持当前事务,如果不存在,就不使用事务 
	propagion_mandatory: 支持当前事务,如果不存在,抛出异常 
	*保证没有在同一个事务中 
	propagion_requires_new:  如果有事务存在,挂起当前事务,创建一个新的事务 
	propagion_not_supported: 以非事务方式运行,如果有事务存在,挂起当前事务 
	propagion_never: 以非事务方式运行,如果有事务存在,抛出异常 
	propagion_nested: 如果当前事务存在,则嵌套事务执行

分布式事务怎么解决的,底层原理,以及具体的业务场景

概述:

	简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,
	分布式事务需要保证这些小操作要么全部成功,要么全部失败。
分布式事务底层原理:
    分布式事务框架本身并不创建事务,只是将同一个业务逻辑的多个事务进行统一管理,从而达到事务的一致性.
    核心步骤:
		1、创建事务组
		    事务发起方在一开始就调用框架创建事务组,然后拿到groupId
		2、添加事务至事务组
		    当一个模块执行完后,将事务结果添加至事务组
		3、关闭事务组
		    当最后一个模块提交完后,事务组对结果进行判断,分别通知所有模块最终的事务结果(提交或回滚)

分布式事务的应用场景:
	事务必须满足传统事务的特性,即原子性,一致性,分离性和持久性。但是分布式事务处理过程中,
	1. 当数据库单表一年产生的数据超过1000W,那么就要考虑分库分表,具体分库分表的原理在此不做解释,以后有空详细说,
	   简单的说就是原来的一个数据库变成了多个数据库。这时候,如果一个操作既访问01库,又访问02库,而且要保证数据的一致性,那么就要用到分布式事务。

	2. 所谓的SOA化,就是业务的服务化。比如原来单机支撑了整个电商网站,现在对整个网站进行拆解,分离出了订单中心、用户中心、
		库存中心。对于订单中心,有 专门的数据库存储订单信息,用户中心也有专门的数据库存储用户信息,库存中心也会有专门的数据库存储库存信息。这时候如果要同时对订单和库存进行操作,那 么就会涉及到订单数据库和库存数据库,为了保证数据一致性,就需要用到分布式事务。

		另外还比如:
		某些场地比如在电商系统中,当有用户下单后,除了在订单表插入一条记录外,对应商品表的这个商品数量必须减1吧,怎么保证?
		在搜索广告系统中,当用户点击某广告后,除了在点击事件表中增加一条记录外

	事务的ACID特性
		事务必须满足传统事务的特性,即原子性,一致性,分离性和持久性。
		
		1. 所谓的原子性就是说,在整个事务中的所有操作,要么全部完成,要么全部不做,没有中间状态。对于事务在执行中发生错误,所有的操作都会被回滚,整个
		   事务就像从没被执行过一样。
		2. 事务的执行必须保证系统的一致性,就拿转账为例,A有500元,B有300元,如果在一个事务里A成功转给B50元,那么不管并发多少,不管发生什么,只要事
		   务执行成功了,那么最后A账户一定是450元,B账户一定是350元。
		3. 所谓的隔离性就是说,事务与事务之间不会互相影响,一个事务的中间状态不会被其他事务感知。
		4. 所谓的持久性,就是说一单事务完成了,那么事务对数据所做的变更就完全保存在了数据库中,即使发生停电,系统宕机也是如此。

常见解决方案:
	1. 基于XA协议的两阶段提交
		分布式事务通常采用2PC协议,全称Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。分布式事务通过2PC协议将提交分成两个阶段:
		1. prepare;
		2. commit/rollback
		阶段一为准备(prepare)阶段。即所有的参与者准备执行事务并锁住需要的资源。参与者ready时,向transaction manager报告已准备就绪。 
		阶段二为提交阶段(commit)。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。
	2. 消息事务+最终一致性
		所谓的消息事务就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操作成功成功并且对外发消息成功,要么两者都失败.

项目上线流程:
早/晚会汇报情况

    基本每天早上或晚上都会开早会讨论以下问题 昨天的内容,今天的计划,需要解决的问题三个维度出发

   1.开发组每个人讲自己负责模块的项目情况。 (项目负责人小汇总)

   2.各个测试组人员讲述自己测试情况。(测试负责人小汇总) 

   3.如果所有的项目模块测试都Ok,开发组leader将项目整合到master上,开展回归测试,如果回归测试没有问题就可以准备上线了。

 回归测试流程:
   1.配置参数和环境
   2.回归主要的流程
   3.将以前提的bug再次回归
   4.回归主要的异常流程

	注意:如果需要跟第三方系统联测的情况,那么代码整合到master时,需要设计测试用例场景覆盖需求与第三方系统测试人员联测。有时候在回归测试也会进行联测。主要以正向流程为主,目的是检查业务流程是否完整,接口是否联通、数据是否正确等几个方面。

4.上线前的准备

第一步:确定上线策略

	1.上线顺序 特别是微服务项目(具体看项目-多系统上线)
	    注册中心---provider----consumer---zull.....

	2.修复数据策略

		如果功能上线后出现bug,应该怎么处理?

			一般我们会设置一个开关,当新功能一旦出现问题,将开关打开,走原来的老流程。


   第二步:写上线申请邮件
		上线之前,项目测试负责人要写上线申请邮件,邮件内容包括有:
		1.数据配置
		有没有开关?有就需要配置。
		数据库有没有修改?有新增表,需要事先增表,有修改表结构,需要改表结构。
		有没有外部接口?有就需要配置接口URL,否则流程不能跑通,回调也不能通。
		等等,根据实际情况来写。
		2.上线注意点
		可以写本次项目上线后,会引起的风险,哪些地方可能容易出现问题?需不需要加上监控等?又或者上线之后,需要人为地去监控数据。
		3.在邮件中写清楚上线策略
		(第一步中考虑到的上线策略)
	第三步:配置线上环境数据
		根据测试人员编写的上线申请邮件,在上线之前在线上环境中配置好数据,根据邮件来配置,所以在编写邮件的时候需要将配置写全,这些配置可以根据开发人员提测时的转测邮件来写,或者测试过程中的补充配置,谨记配置要写完整。
		完全以上步骤之后,就可以择良辰开始上线了,一般上线的权限只有几个人有,所以上线的人员是固定的,上代码时需要先将线上环境的job停掉,我们也是用jenkins进行自动化部署,只是需要人为的打版号、标签,部署版本,停Djob任务,上线完全之后,启动Djob任务等。
		04
		上线之后
		对于测试人员来说,并不是你测试完全,项目上到线上(生产)环境上就OK了,就不关你的事了,而实则项目上线之后才是真正对测试人员的考验,测试人员经常疑或为什么总有一些BUG是在线上环境中才会被发现?
		王豆豆总结了几点:
		1.线上环境数据的复杂度是测试环境不能比拟的。
		2.业务操作的不可控性
		3.实际场景的复杂性
		基于以上三点,这也就是为什么线上环境总是出现一些测试环境不能发现的BUG,排除测试人员漏测的情况。
		故,上线之后,测试人员需要做好以下二件事:
		第一,灰度测试

			项目上线之后,首先是测试人员开始做灰度测试。
			灰度测试时,可以设置由业务开关或者白名单之类做控制,只要少量数据或添加在白名单上的数据可以走新业务流程。
			灰度测试完全之后,也就是将所有业务流程走完,检查各项数据的正确性、流程是否通、流程是否完整等等检查点。
			确定无问题时,再将开关打开,再开放少量真实用户数据。

		第二,监控线上数据
		
			灰度测试时就已经在监控线上数据和检查线上数据,但因为灰度测试时数据量比较少,有时并不足以引发新问题,所以测试人员需要继续观察线上数据。
			测试人员需要在项目上线之后的几个小时内,重点监控线上数据的流向,一旦数据有异常,立即采取措施,回滚代码又或者重新打开开关等,尽量将线上bug引起的损失降到最低,接下来就开始修改bug和修复数据。
			在这个时候,测试人员对数据的敏感性特别就要发挥出来,有时似错非错的数据正是BUG的前兆,千万不要掉以轻心。
			整个项目上线前后的流程就大致如此,不管是上线前的准备还是上线之后数据的观察都是一环扣一环,这些步骤有息息相关,前面的准备工作做得足,那么后面监控数据就会相对轻松,因为不容易出现问题。

系统A场景:
1、 上游10个系统,每日凌晨2:00跑批处理完成,每个系统会生成约50G(约500万行)的文本数据文件,以固定长度或竖线分割,其中每一个系统都有自己的接口规则;
2、 文件要求传输到系统A,要求保证文件传输过程的完整性、安全性;
3、 解析文件,逐行校验数据,将正确的数据入库,错误的数据记录入失败库;
4、 完成后,系统A统计正确的行数和错误的行数通知到每一个文件对应的上游系统;
要求:
1、 对系统A进行比较充分的设计,在上述场景应当重点注意哪些环节?
1) 文件传输过程中,可能会因为网络抖动丢包,甚至被人恶意篡改。需要发送接收双方制定文件校验规则,如总笔数、总金额校验,对文件进行签名验签,加密传输等手段保证文件完整;
2) 传输文件可以用NFS、NAS等交换文件,也可以用SFTP交换,为了保证文件传输速度,可以对单个文件拆分,多线程传输;
3) 文件传输会大量消耗网络带宽,需要提前对带宽升级并进行压力测试;
4) 所有文件传输都需要严格的记录,避免夹带;
5) 文件传输完成,解析文件的时候要用buffer增量读取(百度上有很多);
6) 适当增加JVM堆内存,并对GC进行调优,否则会因为堆内存过大GC不及时导致CPU暴涨宕机;
7) 数据校验如果逻辑复杂,需要对不同的校验规则编写不同的服务,加以抽象微服务化;
8) 数据入库的方法有很多种,可以用dmp,可以用mybatis框架批量提交,批量提交的时候要注意性能,通过不断的测试一定能找到性能最佳的点(1000行一批或者500行一批);
9) 长时间高频读写数据库,需要用到mysql读写分离;
10) 如果不考虑事务,可以用myisam引擎(innodb支持事务和myisam不支持事务 的区别自己百度);
11) MQ消息队列 (高并发请求);
12) Jconsole对JVM进行监控;

1、 每日超过5千万行的数据处理,mysql应当如何优化?
1) mysql数据库的横向、纵向分库、分区、分表;
2) 深入了解mycat;
2、 根据您的经验充分设计,预估完成10个文件处理需要多长时间?
1) 上下游服务器、数据库服务器是否在同一个网段(同一个机房)?
2)
3、 上游系统可能会增加,接口规则可能会变动,如何设计保证其灵活性?
1) 首先将接口规则保存下来(数据库或文件),如竖线分割,每一位是什么数据类型,代表什么;如定长,需要考虑ISO-8859-1转码,否则中文会错位;
2) 抽象一个适配器,读取接口规则,将每一行数据文本绑定一个class,class实现的时候,通过反射getter、setter方法将每一个字段的值读取出来,生成一个一个对象(工厂模式);
4、 上述场景可能需要用到哪些设计模式?
1) 数据转化为对象:工厂模式;
2) 文件传输:观察者模式
3) 适配器:单例模式
5、 容错和灾备如何设计?
1) 数据重跑、断点续传;
2) MQ和分布式事务;
3) Redis锁;
4) 文件归档,数据备份

MYSQL需要准备:
https://www.jianshu.com/p/10a2381225cf(MySQL简书第一章地址)
https://www.jianshu.com/p/10a2381225cf(二,MySQL体系结构和管理)
https://www.jianshu.com/p/f6413bf7f455(三,SQL基础及元数据获取)
https://www.jianshu.com/p/31801e78885f(四,索引以及执行计划管理)
https://www.jianshu.com/p/0b9b45e50a4f(五,存储引擎innodb)
https://www.jianshu.com/p/b7f6675a8479(六,MySQL日志管理)
https://www.jianshu.com/p/74fdb73c3af8(七,MySQL备份恢复)

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页