前言
自从用了Spring Boot,个人最喜欢的就是Spring Boot的配置文件了,和Spring比起,Spring Boot更加灵活,修改的某些配置也是更加得心应手。
Spring Boot 官方提供了两种常用的配置文件格式,分别是properties、YML格式。相比于properties来说,YML更加年轻,层级也是更加分明。
今天这篇文章就来介绍一下Spring Boot的配置文件的语法以及如何从配置文件中取值。
Mysql在中小型企业中是个香饽饽,目前主流的数据库之一,几乎没有一个后端开发者不会使用的,但是作为一个老司机,仅仅会用真的不够。
今天陈某透过一个简单的查询语句来讲述在Mysql内部的执行过程。
select * from table where id=10;
首先通过一张图片来了解一下Mysql的基础架构,如下:

从上图可以看出,Mysql大致分为Server层和存储引擎层两部分。
Server层包括连接器、查询缓存、分析器、优化器等,其中包含了Mysql的大多数核心功能以及所有的内置函数(如日期,时间函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
存储引擎层负责数据的存储和提取。它的架构是可插拔式的,支持InnoDB、MyISAM等多个存储引擎。Mysql中主流的存储引擎是InnoDB,由于它对事务的支持让它从Mysql5.5.5版本开始成为了默认的存储引擎。
大致了解了整体架构,现在说说每一个基础的模块都承担着怎样的责任。
mysql [-h] ip [- P] port -u [user] -p
在完成经典的TCP握手后,连接器会开始认证身份,要求输入密码。
连接完成后,没有后续动作的连接将会变成空闲连接,你可以输入show processlist命令看到它。如下图,其中的Command这一列显示为sleep的这一行表示在系统里面有一个空闲连接。

客户端如果太长时间没有执行动作,连接器将会自动断开,这个时间由参数wait_timeout控制,默认值是8小时。
如果在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query。这时候如果你要继续,就需要重连,然后再执行请求了。
连接建立完成后,你就可以select语句了,执行之前会查询缓存。
查询缓存在Mysql中的是默认关闭的,因为缓存命中率非常低,只要有对表执行一个更新操作,这个表的所有查询缓存都将被清空。怎么样?一句废材足以形容了!!!
废材的东西不必多讲,主流的Redis的缓存你不用,别再搞这废材了。
如果没有命中查询缓存,就要执行查询了,但是在执行查询之前,需要对SQL语句做解析,判断你这条语句有没有语法错误。
分析器会做 '词法分析' ,你输入的无非可就是多个字符串和空格组成的SQL语句,MYSQL需要识别出里面的字符串是什么,代表什么,有没有关键词等。
MYSQL会从你输入的select 这个关键字识别出来是一个查询语句,table是表名,id是列名。
做完这些会做 '语法分析' ,根据MYSQL定义的规则来判断你的SQL语句有没有语法错误,如果你的语法不对,就会收到类似如下的提醒:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect * from t where ID=1' at line 1
经过分析器词法和语法的分析,此时就能知道这条SQL语句是干什么的。但是在开始执行之前,MYSQL底层还要使用优化器对这条SQL语句进行优化处理。
MYSQL内部会对这条SQL进行评估,比如涉及到多个索引会比较使用哪个索引代价更小、多表join的时候会考虑决定各个表的连接顺序。
优化器的作用一句话总结:根据MYSQL内部的算法决定如何执行这条SQL语句来达到MYSQL认为代价最小目的。
优化器阶段完成后,这个语句的执行方案就确定了,接下来就交给执行器执行了。
MYSQL通过分析器知道了要做什么,通过优化器知道了如何做,于是就进入了执行器阶段。
执行器开始执行之前,需要检查一下用户对表table有没有执行的权限,没有返回权限不足的错误,有的话就执行。
执行也是分类的,如果Id不是索引则全表扫描,一行一行的查找,如果是索引则在索引组织表中查询,索引的查询很复杂,其中涉及到B+树等算法,这里不再详细介绍。
一条SQL语句在MYSQL内部执行的过程涉及到的内部模块有:连接器、查询缓存、分析器、优化器、执行器、存储引擎。
至此,MYSQL的基础架构已经讲完了。

JPDA(Java Platform Debugger Architecture),即 Java 平台调试体系,具体结构图如下图所示。
其中实现调试功能的主要协议是JDWP协议,在 Java SE 5 以前版本,JVM 端的实现接口是 JVMPI(Java Virtual Machine Profiler Interface),而在 Java SE 5 及以后版本,使用 JVMTI(Java Virtual Machine Tool Interface) 来替代 JVMPI。
因此,如果使用 Java SE 5 之前版本,使用调试功能的命令为:
1 | java -Xdebug -Xrunjdwp:... |
Java SE 5 及之后版本,使用调试功能的命令为:1 | java -agentlib:jdwp=... |
1 | java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9091 -jar xxx.jar |
dt_socket:主要的方式,采用socket方式连接。dt_shmem:采用共享内存方式连接,仅支持 Windows 平台。n。y,如果你想将当前应用作为客户端,作为调试的发起者,设置该值为n。y。n,即不需要应用阻塞等待连接。一个可能为 y的应用场景是,你的程序在启动时出现了一个故障,为了调试,必须等到调试方连接上来后程序再启动。8000。java -agentlib:jdwp=…可用,单位为毫秒ms。suspend = y 时,该值表示等待连接的超时;当 suspend = n 时,该值表示连接后的使用超时。-agentlib:jdwp=transport=dt_socket,server=y,address=8000:以 Socket 方式监听 8000 端口,程序启动阻塞(suspend 的默认值为 y)直到被连接。
-agentlib:jdwp=transport=dt_socket,server=y,address=localhost:8000,timeout=5000:以 Socket 方式监听 8000 端口,当程序启动后 5 秒无调试者连接的话终止,程序启动阻塞(suspend 的默认值为 y)直到被连接。
-agentlib:jdwp=transport=dt_shmem,server=y,suspend=n:选择可用的共享内存连接地址并使用 stdout 打印,程序启动不阻塞。
-agentlib:jdwp=transport=dt_socket,address=myhost:8000:以 socket 方式连接到 myhost:8000上的调试程序,在连接成功前启动阻塞。
-agentlib:jdwp=transport=dt_socket,server=y,address=8000,onthrow=java.io.IOException,launch=/usr/local/bin/debugstub:以 Socket 方式监听 8000 端口,程序启动阻塞(suspend 的默认值为 y)直到被连接。当抛出 IOException 时中断调试,转而执行 usr/local/bin/debugstub程序。
1 | java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9190 -jar debug-demo.jar |
出现下图的界面,表示运行成功:
然后在 IDEA 中,点击 Edit Configurations,在弹框中点击 + 号,然后选择Remote。
填写服务器的地址及端口,点击 OK 即可。
配置完毕后,DEBUG 调试运行即可。
配置完毕后点击保存即可,因为我配置的 suspend=n,因此服务端程序无需阻塞等待我们的连接。我们点击 IDEA 调试按钮,当我访问某一接口时,能够正常调试。
JAVA面试题即可免费获取。


m比特的位数组与k个哈希函数组成的数据结构。比特数组均初始化为0,所有哈希函数都可以分别把输入数据尽量均匀地散列。k个哈希函数转换成k个哈希值,这k个哈希值将作为比特数组的下标,并将数组中的对应下标的值置为1。k个哈希函数转换成k个哈希值(数组下标),查询数组中对应下标的值,如果有一个下标的值为0表明该元素一定不在集合中,如果全部下标的值都为1,表明该元素有可能在集合中。至于为什么有可能在集合中? 因为有可能某个或者多个下标的值为 1 是受到其他元素的影响,这就是所谓的假阳性,下文会详细讲述。m=18, k=3的布隆过滤器示例。集合中的 x、y、z 三个元素通过 3 个不同的哈希函数散列到位数组中。当查询元素 w 时,因为有一个比特为 0,因此 w 不在该集合中。
m的布隆过滤器中插入一个元素,它的其中一个哈希函数会将某个特定的比特置为1。因此,在插入元素后,该比特仍然为 0 的概率是:
k个哈希函数,并插入n个元素,自然就可以得到该比特仍然为 0 的概率是:
1的概率就是:
n个元素后,我们用一个不在集合中的元素来检测,那么被误报为存在于集合中的概率(也就是所有哈希函数对应的比特都为1的概率)为:
n比较大时,根据极限公式,可以近似得出假阳性率:
k一定的情况下有如下结论:O(k)。假阳性的概率,准确率要求高的场景不太适用。假阳性的概率会很低,另一方面,你认为百度会在意这种的误差吗,你的一篇文章可能因为假阳性概率没有收录到,对百度有影响吗?1 | docker pull redislabs/rebloom |
1 | redis-cli |
1. 创建布隆过滤器
1 | BloomFilter<Integer> filter = BloomFilter.create( |
arg1:用于将任意类型 T 的输入数据转化为 Java 基本类型的数据,这里转换为 bytearg2:byte 字节数组的基数arg3:期望的假阳性概率2.估计最优 m 值和 k 值
1 | //m值的计算 |
k值应为:



p值和m值很重要。加群加陈某微信,陈某会第一时间拉你进群。


缓存空值、布隆过滤器。
1 | Object nullValue = new Object(); |

数据命中不高、 数据相对固定、 实时性低(通常是数据 集较大)的应用场景,代码维护较为复杂,但是缓存空间占用少。为什么呢?因为布隆过滤器不支持删除元素,一旦数据变化,并不能及时的更新布隆过滤器。| 方案 | 适用场景 | 维护成本 |
|---|---|---|
| 缓存对象 | 1. 数据命中不高 2. 数据频繁变化,实时性高 | 代码维护点单、需要过多的缓存空间,数据一致性需要自己实现 |
| 布隆过滤器 | 1. 数据命中不高 2.数据相对固定,实时性低 | 代码维护复杂、缓存空间占用少 |