前言
自从用了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.数据相对固定,实时性低 | 代码维护复杂、缓存空间占用少 |