0%

关于本人

关于博客

  • why-how-what,理念-逻辑-知识,这就是知识的黄金圆环。

  • 博客建立只是为了监督个人学习,记录生活点滴,个人水平有限欢迎斧正。

  • 博客章节地址可能会发生变化,因为我也是在不断的归纳整理知识内容。

  • 2018年4月开始断断续续写内容,加油。

Read more »

记录最近在Centos7上面部署jenkens。安装的方法有很多,下面采用最简单的方式安装。

准备工作

  1. 一台服务器,安装好jdk。

安装jenkens

这里采用yum源安装

更新安装jenkens源

1
2
3
4
5
6
7
8
9
10
11
12
13
# yum 源导入
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo

#导入密钥
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key

#安装
sudo yum install jenkins

#检查安装
whereis jenkins
> jenkins: /usr/lib/jenkins
# 提示以上内容说明安装成功

修改jenkens配置信息

1
2
3
4
5
6
7
8
9
10
11
# 编辑jenkins配置文件
vim /etc/sysconfig/jenkins
# 这里主要编辑两个参数 JENKINS_USER JENKINS_JAVA_OPTIONS
# JENKINS_USER jenkens权限用户
# JENKINS_JAVA_OPTIONS jenkens启动参数,这里主要设置启动内存。
JENKINS_USER="root"
JENKINS_JAVA_OPTIONS="-server -Xms512m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=512m -Djava.awt.headless=true"
# 修改目录权限 如果你不是使用root账号,我偷下懒。
chown -R root:root /var/lib/jenkins
chown -R root:root /var/cache/jenkins
chown -R root:root /var/log/jenkins

启动junkets检查

1
2
3
4
5
6
7
8
#重载所有修改过的配置文件
sudo systemctl daemon-reload

#启动Jenkins服务
sudo systemctl start jenkins

#由于Jenkins不是Native Service,所以需要用chkconfig命令而不是systemctl命令
sudo /sbin/chkconfig jenkins on

第一次启动配置

1
2
# 查看密码
cat /var/lib/jenkins/secrets/initialAdminPassword

配置jenkens jdk maven环境

1
2
3
4
5
6
7
8
9
10
11
12
13
# 在系统环境中增加
# JAVA_HOME
# MAVEN_HOME
# 如果jdk是通过yum 安装需要通过ll找到jvm的安装地址
# ll /usr/bin/javac -> /etc/alternatives/javac
# ll /etc/alternatives/javac -> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64/bin/javac
#举例子
JAVA_HOME
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64
MAVEN_HOME
/opt/libhome/apache-maven-3.8.1
PATH
$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin

友情提示

不要选择社区推荐插件安装

本章是整理知识内容,为强化知识长期更新。

Git速度查询表

git清理分支提交记录

1
2
3
4
5
6
7
8
9
10
11
12
1.Checkout 
git checkout --orphan latest_branch
2. Add all the files
git add -A
3. Commit the changes
git commit -am "commit message"
4. Delete the branch
git branch -D master
5.Rename the current branch to master
git branch -m master
6.Finally, force update your repository
git push -f origin master

撤销文件追踪

有些时候不想提交部分文件,但是git add .的时候添加进去了。

1
2
3
4
5
6
## 如果是对所有文件都取消跟踪的话,就是
git rm -r --cached .    ## 不删除本地文件
git rm -r --f .    ## 删除本地文件
##对某个文件取消跟踪
git rm --cached readme1.txt ## 删除readme1.txt的跟踪,并保留在本地。
git rm --f readme1.txt ## 删除readme1.txt的跟踪,并且删除本地文件s

git的最小配置

为什么要最小配置,每次提交代码需要告诉git。所以需要简单设置下user信息。

1
2
git config --global user.name 'your name'
git config --global user.email 'your email'

这里需要注意config的三个作用域

1
2
3
git config --local  #某个git本地仓库有效
git config --global #当前用户所有仓库有效,就是你系统的登陆用户。
git config --system #对系统所有的仓库都有效果。

我们一般只会使用local 和 global这两个配置。当我们配置好user.name user.email之后,我们可以检查下配置信息。

1
2
3
git config --list --local # 注意,必须在某个仓库里面才能看到。
git config --list --global
git config --list --system

git创建一个本地仓库

一般来说git仓库有两种情况,一种是没有仓库,另外一种就是已经有仓库了。这里对第一种情况演示,因为工作中习惯在web上创建仓库。这里还是了解下。

1
git init git_learning

创建一个README文件。

1
touch README.md

这里需要说明下,本地仓库创建完成后需要与远程仓库进行管理。

1
git remote add origin github.com:yourname/git_learning.git # 这里的yourname 是你的git账号

建议手动去github上面创建一个叫git_learning的仓库。上面的命令就是做下关联。

1
2
3
git add . # 将当前文件添加至暂存区
git commit -m "upload file" # 将暂存区的文件提交到本地仓库
git push origin mastet # 将本地仓库的改动信息推送到远程仓库中

git log日志查看

如果我们需要查看commit 提交日志可以使用log命令,这里简单介绍下log。

1
git log --oneline #log信息一行显示

这里为了演示,模拟commit。比如现在commit了4次。

1
git log --oneline -n2 #log信息一行显示。且显示2条记录。

也可以用自带的图形化命令看提交记录。

1
git log --oneline --graph

commit的message

如果发现message写错了,可以修改下。

1
git commit --amend  # 修改最新一次commit提交message。

如果想修改以往的commit的message。注意是不连续的commit。

1
# 首先查看log 里面的信息,然后获取commitid进行合并

git clone www./.git

从仓库克隆项目。

Read more »

本章属于持续学习、长期更修。

声明一个Double变量赋值 0.001会编译错误吗 ?

  • 不会,double 数据类型是双精度、64 位、标准的浮点数。

Java是纯粹的面向对象语言吗?

  • Java不是存粹的面向对象语言,因为它包含了原生数据类型,比如int 、double。

Java面向对象的特征?

  • 继承、封装、多态、抽象。

String、StringBuffer、StringBuilder的区别

  • 可变性
    • String 是不可变的,StringBuffer\StringBuilder是可变的。
    • String 类中使用 final 关键字字符数组保存字符串,private final char value[],所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串char[]value 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
  • 线程安全方面
    • String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilderStringBuilderStringBuffer 的公共父类,但是StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
  • 性能
    • 操作少量的数据 = String
    • 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
    • 多线程操作字符串缓冲区下操作大量数据 = StringBuffer

为什么 String 类型要用 final 修饰?

使用 final 修饰的第一个好处是安全;第二个好处是高效,以 JVM 中的字符串常量池来举例,如下两个变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Test {
public static void main(String[] args) {
String s1 = "java";
String s2 = "java";

// 以上两个局部变量都存在了常量池中
System.out.println(s1 == s2); // true


// new出来的对象不会放到常量池中,内存地址是不同的
String s3 = new String();
String s4 = new String();

/**
* 字符串的比较不可以使用双等号,这样会比较内存地址
* 字符串比较应当用equals,可见String重写了equals
*/
System.out.println(s3 == s4); // false
System.out.println(s3.equals(s4)); // true
}
}
  • 只有字符串是不可变时,我们才能实现字符串常量池,字符串常量池可以为我们缓存字符串,提高程序的运行效率,如下图所示:

  • 工作原理

  当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。

Read more »

mysql小炒,记录日常的积累。

Mysql 大小写问题

  • 表名、表别名、字段名、字段别名都小写。SQL保留字段、函数名、绑定变量名都大写。

Exists与in

  • 将设A、B两表,走索引的情况下。根据A、B表的大小比较,如果A表大于B表那么IN的查询效率比EXISTS高。
1
2
3
SELECT * FROM A WHERE cc IN (SELECT cc FROM B)

SELECT * FROM A WHERE EXISTS (SELECT cc FROM B WHERE B.cc=A.cc)

测试环境打开profiling

  • 首先我们需要看下 profiling 是否开启,开启它可以让 MySQL 收集在 SQL 执行时所使用的资源情况,命令如下:
1
2
3
4
5
mysql> select @@profiling;
# profiling=0 代表关闭,我们需要把 profiling 打开,即设置为 1:
mysql> set profiling=1;
# 然后我们执行一个 SQL 查询(你可以执行任何一个 SQL 查询):
mysql> select * from wucai.heros;

DDL设计数据表的原则

  1. 数据表越少越好
  2. 数据表中的字段越少越好
  3. 数据表中联合主键的字段越少越好
  4. 使用主键和外键越多越好

去除重复行

  1. DISTINCT 需要放到所有列名的前面
1
2
# 这么写会报错
SELECT name, DISTINCT age FROM us
  1. DISTINCT 其实是对后面所有列名的组合进行去重。

ORDER BY 子句有以下几个点需要掌握

  1. 排序的列名:ORDER BY 后面可以有一个或多个列名,如果是多个列名进行排序,会按照后面第一个列先进行排序,当第一列的值相同的时候,再按照第二列进行排序,以此类推。
  2. 排序的顺序:ORDER BY 后面可以注明排序规则,ASC 代表递增排序,DESC 代表递减排序。如果没有注明排序规则,默认情况下是按照 ASC 递增排序。我们很容易理解 ORDER BY 对数值类型字段的排序规则,但如果排序字段类型为文本数据,就需要参考数据库的设置方式了,这样才能判断 A 是在 B 之前,还是在 B 之后。比如使用 MySQL 在创建字段的时候设置为 BINARY 属性,就代表区分大小写。
  3. 非选择列排序:ORDER BY 可以使用非选择列进行排序,所以即使在 SELECT 后面没有这个列名,你同样可以放到 ORDER BY 后面进行排序。
  4. ORDER BY 的位置:ORDER BY 通常位于 SELECT 语句的最后一条子句,否则会报错。

SELECT 的执行顺序

  1. 关键字的顺序
1
SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ...
  1. .SELECT 语句的执行顺序(在 MySQL 和 Oracle 中,SELECT 执行顺序基本相同):
1
FROM > WHERE > GROUP BY > HAVING > SELECT的字段 > DISTINCT > ORDER BY > LIMIT
Read more »

本章属于持续学习、长期更修。

数据库的三范式是什么

  • 第一范式:列不可再分
  • 第二范式:行可以唯一区分,主键约束
  • 第三范式:表的非主属性不能依赖与其他表的非主属性 外键约束
  • 且三大范式是一级一级依赖的,第二范式建立在第一范式上,第三范式建立第一第二范式上。
  • 第一范式(1NF):数据库表中的字段都是单一属性的,不可再分。这个单一属性由基本类型构成,包括整型、实数、字符型、逻辑型、日期型等。
  • 第二范式(2NF):数据库表中不存在非关键字段对任一候选关键字段的部分函数依赖(部分函数依赖指的是存在组合关键字中的某些字段决定非关键字段的情况),也即所有非关键字段都完全依赖于任意一组候选关键字。
  • 第三范式(3NF):在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。所谓传递函数依赖,指的是如 果存在”A → B → C”的决定关系,则C传递函数依赖于A。因此,满足第三范式的数据库表应该不存在如下依赖关系: 关键字段 → 非关键字段 x → 非关键字段y

说下mysql有几种数据库引擎

不清楚,因为每个版本发布都会新增一些。但是我最熟悉是的innodb。

说下mysql Master slave 的原理

  • :binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;

  • :io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进 自己的relay log中;

  • :sql执行线程——执行relay log中的语句;

MySQL中myisam与innodb的区别

  • InnoDB支持事物,而MyISAM不支持事物
  • InnoDB支持行级锁,而MyISAM支持表级锁
  • InnoDB支持MVCC, 而MyISAM不支持
  • InnoDB支持外键,而MyISAM不支持
  • InnoDB不支持全文索引,而MyISAM支持。

innodb引擎的4大特性

  • 插入缓冲(insert buffer),
  • 二次写(double write),
  • 自适应哈希索引(ahi),
  • 预读(read ahead)
  • 支持事务操作,具有事务 ACID 隔离特性,默认的隔离级别是可重复读(repetable-read)、通过MVCC(并发版本控制)来实现的。能够解决脏读不可重复读的问题。
  • InnoDB 支持外键操作。
  • InnoDB 默认的锁粒度行级锁,并发性能比较好,会发生死锁的情况。
  • 和 MyISAM 一样的是,InnoDB 存储引擎也有 .frm文件存储表结构 定义,但是不同的是,InnoDB 的表数据与索引数据是存储在一起的,都位于 B+ 数的叶子节点上,而 MyISAM 的表数据和索引数据是分开的。
  • InnoDB 有安全的日志文件,这个日志文件用于恢复因数据库崩溃或其他情况导致的数据丢失问题,保证数据的一致性。
  • InnoDB 和 MyISAM 支持的索引类型相同,但具体实现因为文件结构的不同有很大差异。
  • 增删改查性能方面,如果执行大量的增删改操作,推荐使用 InnoDB 存储引擎,它在删除操作时是对行删除,不会重建表。

什么是事务?

  • 事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。

覆盖索引和回表

  • 覆盖索引指的是在一次查询中,如果一个索引包含或者说覆盖所有需要查询的字段的值,我们就称之为覆盖索引,而不再需要回表查询。而要确定一个查询是否是覆盖索引,我们只需要explain sql语句看Extra的结果是否是“Using index”即可。

MySQL 事务四大特性

一说到 MySQL 事务,你肯定能想起来四大特性:原子性一致性隔离性持久性。什么是 MySQL 中的事务?

事务是一组操作,组成这组操作的各个单元,要不全都成功要不全都失败,这个特性就是事务。

在 MySQL 中,事务是在引擎层实现的,只有使用 innodb 引擎的数据库或表才支持事务。

  • 原子性(Atomicity): 原子性指的就是 MySQL 中的包含事务的操作要么全部成功、要么全部失败回滚,因此事务的操作如果成功就必须要全部应用到数据库,如果操作失败则不能对数据库有任何影响。
  • 一致性(Consistency):一致性指的是一个事务在执行前后其状态一致。比如 A 和 B 加起来的钱一共是 1000 元,那么不管 A 和 B 之间如何转账,转多少次,事务结束后两个用户的钱加起来还得是 1000,这就是事务的一致性。
  • 持久性(Durability): 持久性指的是一旦事务提交,那么发生的改变就是永久性的,即使数据库遇到特殊情况比如故障的时候也不会产生干扰。
  • 隔离性(Isolation):当多个事务同时进行时,就有可能出现脏读(dirty read)不可重复读(non-repeatable read)幻读(phantom read) 的情况,为了解决这些并发问题,提出了隔离性的概念。
    • 重点说下隔离性它们分别是读未提交(read uncommitted)读已提交(read committed)可重复读(repetable read)串行化(serializable)。下面分别来解释一下。
    • 读未提交:读未提交指的是一个事务在提交之前,它所做的修改就能够被其他事务所看到。
    • 读已提交:读已提交指的是一个事务在提交之后,它所做的变更才能够让其他事务看到。
    • 可重复读:可重复读指的是一个事务在执行的过程中,看到的数据是和启动时看到的数据是一致的。未提交的变更对其他事务不可见。
    • 串行化:顾名思义是对于同一行记录,会加写锁会加读锁。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

SQL语句的执行顺序

我们在编写一个查询语句的时候

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT DISTINCT
< select_list >
FROM
< left_table > < join_type >
JOIN < right_table > ON < join_condition >
WHERE
< where_condition >
GROUP BY
< group_by_list >
HAVING
< having_condition >
ORDER BY
< order_by_condition >
LIMIT < limit_number >
  1. FROM 连接
  • 首先,对 SELECT 语句执行查询时,对FROM 关键字两边的表执行连接,会形成笛卡尔积,这时候会产生一个虚表VT1(virtual table)

首先先来解释一下什么是笛卡尔积

现在我们有两个集合 A = {0,1} , B = {2,3,4}

那么,集合 A * B 得到的结果就是

A * B = {(0,2)、(1,2)、(0,3)、(1,3)、(0,4)、(1,4)};

B * A = {(2,0)、{2,1}、{3,0}、{3,1}、{4,0}、(4,1)};

上面 A * B 和 B * A 的结果就可以称为两个集合相乘的 笛卡尔积

我们可以得出结论,A 集合和 B 集合相乘,包含了集合 A 中的元素和集合 B 中元素之和,也就是 A 元素的个数 * B 元素的个数

  1. ON 过滤
  • 然后对 FROM 连接的结果进行 ON 筛选,创建 VT2,把符合记录的条件存在 VT2 中。
  1. JOIN 连接

第三步,如果是 OUTER JOIN(left join、right join) ,那么这一步就将添加外部行,如果是 left join 就把 ON 过滤条件的左表添加进来,如果是 right join ,就把右表添加进来,从而生成新的虚拟表 VT3。

  1. WHERE 过滤
  • 第四步,是执行 WHERE 过滤器,对上一步生产的虚拟表引用 WHERE 筛选,生成虚拟表 VT4。

  • WHERE 和 ON 的区别

    • 如果有外部列,ON 针对过滤的是关联表,主表(保留表)会返回所有的列;
    • 如果没有添加外部列,两者的效果是一样的;
  • 应用

    • 对主表的过滤应该使用 WHERE;
    • 对于关联表,先条件查询后连接则用 ON,先连接后条件查询则用 WHERE;
  1. GROUP BY
  • 根据 group by 字句中的列,会对 VT4 中的记录进行分组操作,产生虚拟机表 VT5。果应用了group by,那么后面的所有步骤都只能得到的 VT5 的列或者是聚合函数(count、sum、avg等)。
  1. HAVING
  • 紧跟着 GROUP BY 字句后面的是 HAVING,使用 HAVING 过滤,会把符合条件的放在 VT6
  1. SELECT
  • 第七步才会执行 SELECT 语句,将 VT6 中的结果按照 SELECT 进行刷选,生成 VT7
  1. DISTINCT
  • 在第八步中,会对 TV7 生成的记录进行去重操作,生成 VT8。事实上如果应用了 group by 子句那么 distinct 是多余的,原因同样在于,分组的时候是将列中唯一的值分成一组,同时只为每一组返回一行记录,那么所以的记录都将是不相同的。
  1. ORDER BY
  • 应用 order by 子句。按照 order_by_condition 排序 VT8,此时返回的一个游标,而不是虚拟表。sql 是基于集合的理论的,集合不会预先对他的行排序,它只是成员的逻辑集合,成员的顺序是无关紧要的。

什么是临时表,何时删除临时表

1
2
3
4
在 MySQL 中,有三种类型的表
一种是`永久表`,永久表就是创建以后用来长期保存数据的表
一种是`临时表`,临时表也有两类,一种是和永久表一样,只保存临时数据,但是能够长久存在的;还有一种是临时创建的,SQL 语句执行完成就会删除。
一种是`虚表`,虚表其实就是`视图`,数据可能会来自多张表的执行结果。
  • MySQL 会在下面这几种情况产生临时表
    • 使用 UNION 查询:UNION 有两种,一种是UNION ,一种是 UNION ALL ,它们都用于联合查询;区别是 使用 UNION 会去掉两个表中的重复数据,相当于对结果集做了一下去重(distinct)。使用 UNION ALL,则不会排重,返回所有的行。使用 UNION 查询会产生临时表。
    • 使用 TEMPTABLE 算法或者是 UNION 查询中的视图。TEMPTABLE 算法是一种创建临时表的算法,它是将结果放置到临时表中,意味这要 MySQL 要先创建好一个临时表,然后将结果放到临时表中去,然后再使用这个临时表进行相应的查询。
    • ORDER BY 和 GROUP BY 的子句不一样时也会产生临时表。
    • DISTINCT 查询并且加上 ORDER BY 时;
    • SQL 用到 SQL_SMALL_RESULT 选项时;如果查询结果比较小的时候,可以加上 SQL_SMALL_RESULT 来优化,产生临时表
    • FROM 中的子查询;
    • EXPLAIN 查看执行计划结果的 Extra 列中,如果使用 Using Temporary 就表示会用到临时表。

介绍下InnoDB存储引擎的B+树索引

  • 每个索引都对应一棵B+树,B+树分为好多层,最下边一层是叶子节点,其余的是内节点。所有用户记录都存储在B+树的叶子节点,所有目录项记录都存储在内节点。
  • InnoDB存储引擎会自动为主键(如果没有它会自动帮我们添加)建立聚簇索引,聚簇索引的叶子节点包含完整的用户记录。
  • 我们可以为自己感兴趣的列建立二级索引,二级索引的叶子节点包含的用户记录由索引列 + 主键组成,所以如果想通过二级索引来查找完整的用户记录的话,需要通过回表操作,也就是在通过二级索引找到主键值之后再到聚簇索引中查找完整的用户记录。
  • B+树中每层节点都是按照索引列值从小到大的顺序排序而组成了双向链表,而且每个页内的记录(不论是用户记录还是目录项记录)都是按照索引列的值从小到大的顺序而形成了一个单链表。如果是联合索引的话,则页面和记录先按照联合索引前边的列排序,如果该列值相同,再按照联合索引后边的列排序。
  • 通过索引查找记录是从B+树的根节点开始,一层一层向下搜索。由于每个页面都按照索引列的值建立了Page Directory(页目录),所以在这些页面中的查找非常快。
  • 二者SELECT COUNT(*)哪个更快,为什么
    • myisam更快,因为myisam内部维护了一个计数器,可以直接调取。
Read more »

本章是整理知识内容,为强化知识长期更新。

Mysql基础架构图

mysql基础架构图

简单介绍上图相关模块功能

  • 连接器:管理连接,权限验证

  • 查询缓存:命中缓存则直接返回结果

  • 语法解析:词法分析,语法分析

  • 查询优化:执行计划生成,索引选择

  • 执行器:操作引擎,返回结果

  • 存储引擎:存储数据,提供读写结构。

连接器

我们需要连接到mysql服务端才能进行各种操作。

1
2
# 使用密码登录到时候我们会使用这种格式。
mysql -h$ip -P$port -u$user -p

执行上述命令会提示输入密码。输入完密码后就进入了mysql。

  • 如果用户名或者密码输入错误,会提示一个Access denied for user到错误,然后客户端程序结束执行。

  • 如果用户名和密码认证通过,连接器会去权限表中查询该用户拥有的所有权限。此后该连接里面的权限逻辑判断都会依赖认证成功时候读取到的权限。

因此当修改用户的权限之后,如果被修改用户的在登录状态是不会修改已经连接的权限。需要让被修改权限用户从新登录。

  • 实际上连接的方式有多种,上面通过密码的方式只是其中的一种方式。当客户端与服务端mysql进程进程建立连接,服务器的进程就会创建一个单独的线程来专门处理与这个客户端的交互,当该客户断开与服务端连接时,服务端并不会马上销毁对应的交互线程,而是缓存起来。当另一个新的客户端连接进来的时候,在把这个缓存的线程分配给新的客户端。这样就避免的频繁创建和修改线程,节省系统的开销。但是连接线程多了也会影响服务端,所以也有默认的参数限制客户端的连接数量。
1
2
# 这里是查询服务端存在的连接。
SHOW PROCESSLIST;

我使用的阿里云的数据库,这里展示下结果集。这里需要注意,登录的账号需要有PROCESS的权限否则只能看到自己的连接信息(线程),我这里采用的root所以看到全部到。

连接完成后如果没有执行后续操作则 Command会显示Sleep的状态,长时间Sleep会导致连接自动断开。默认的时间是8小时,也就是参数 wait_timeout。当客户端连接断开后,若客户端再次发出请求就会提示一个

Lost connection to MySQL server during query,此时就只能重新建立连接了。

半双工
  • MySQL客户端/服务端通信协议是“半双工”的:在任一时刻,要么是服务器向客户端发送数据,要么是客户端向服务器发送数据,这两个动作不能同时发生。一旦一端开始发送消息,另一端要接收完整个消息才能响应它,所以我们无法也无须将一个消息切成小块独立发送,也没有办法进行流量控制。
  • 服务器响应给用户的数据通常会很多,由多个数据包组成。但是当服务器响应客户端请求时,客户端必须完整的接收整个返回结果,而不能简单的只取前面几条结果,然后让服务器停止发送。因而在实际开发中,尽量保持查询简单且只返回必需的数据,减小通信间数据包的大小和数量是一个非常好的习惯,这也是查询中尽量避免使用SELECT *以及加上LIMIT限制的原因之一。
长连接与短连接
  • 在数据库里面,长连接是指数据库建立连接,如果客户端有持续的请求则使用同一个连接,短连接是指每次执行几次短的查询就断开连接,下次查询再次创建连接。由于创建的过程复杂,一般来说尽量减少创建连接的动作,尽可能使用长连接。特别是在开发的时候出现大伙突然连接不上测试库,此时就检查下连接是不是太多了。因为连接多了会导致内存消耗特别快。

    • mysql的执行过程中临时使用的内存管理是在连接线程对象里面,服务端断开的时候才会释放,为了避免内存消耗过大,每次执行较大的操作之后,可以通过mysql_reset_connection来重新初始化连接资源。这个操作是不需要重新做权限,只是恢复到创建的初始状态。
  • MySQL mysql_reset_connection 官方文档

查询缓存

一个不被建议使用的功能,在新版的8.0中已经被删除了。总结就是弊大于利。

  • 建立完成后,假设执行一次SELECT语句,执行逻辑就会到第二部查询缓存。mysql拿到一个查询之后,会先到缓存中寻找释放有完全对应的,因为之前执行的查询语句和结果集会直接被缓存起来,以Keys-value的形式。keys是查询语句-value是查询结果集。如果能命中这个key则直接返回value。咋一看挺有用的,但实际上查询缓存的实效的太频繁。并且keys的命中条件太不聪明了,如果两次查询语句在任何的字符上存在不通(空格、大小写)都不会缓存命中。为什么会频繁失效,因为如果对查询语句中的表进行更新,就会导致缓存失效。比如INSERT、UPDATE 、DELETE 、TRUNCATE TABLE 、ALTER TABLE 等等就会导致缓存失效。

语法解析

如果没有命中查询缓存,就要开始执行sql语句了。mysql需要做什么,因此需要对sql进行解析。MySQL通过关键字将SQL语句进行解析,并生成一颗对应的解析树。这个过程解析器主要通过语法规则来验证和解析。比如SQL中是否使用了错误的关键字或者关键字的顺序是否正确等等。预处理则会根据MySQL规则进一步检查解析树是否合法。比如检查要查询的数据表和数据列是否存在等等。

  • 本质上发送过来的是一个文本信息,这里就需要对该文本信息进行编译,涉及到词法解析语法解析语义解析等阶段。需要注意的是,这里会对sql语句进行一些检查,比如设计的相关表、表字段。这里检查通过的才会进入查询优化模块。
  • 根据SQL语言的功能可以划分成4个部分
    • DDL,英文叫做 Data Definition Language,也就是数据定义语言,它用来定义我们的数据库对象,包括数据库、数据表和列。通过使用 DDL,我们可以创建,删除和修改数据库和表结构。
    • DML,英文叫做 Data Manipulation Language,数据操作语言,我们用它操作和数据库相关的记录,比如增加、删除、修改数据表中的记录。
    • DCL,英文叫做 Data Control Language,数据控制语言,我们用它来定义访问权限和安全级别。
    • DQL,英文叫做 Data Query Language,数据查询语言,我们用它查询想要的记录,它是 SQL 语言的重中之重。在实际的业务中,我们绝大多数情况下都是在和查询打交道,因此学会编写正确且高效的查询语句,是学习的重点。

查询优化

通过之前的语法解析,基本可以判定语法树是合法的,此时mysql就知道文本内容要做什么。

  • mysql会对查询语句进行优化,优化的结果就是生成一个执行计划,这个计划会表明使用了那些查询索引,表之间的连接是什么样子的。有时候出现多种执行方式,只是效率不通,优化器会决定使用哪一个执行方案,这个时候就涉及到EXPLAIN语句,该语句可以查看sql到执行计划,这将涉及到查询优化。
  • MySQL的查询优化器是一个非常复杂的部件,它使用了非常多的优化策略来生成一个最优的执行计划:
    • 重新定义表的关联顺序(多张表关联查询时,并不一定按照SQL中指定的顺序进行,但有一些技巧可以指定关联顺序)
    • 优化函数
    • 提前终止查询(比如:使用Limit时,查找到满足数量的结果集后会立即终止查询)
    • 优化排序(在老版本MySQL会使用两次传输排序,即先读取行指针和需要排序的字段在内存中对其排序,然后再根据排序结果去读取数据行,而新版本采用的是单次传输排序,也就是一次读取所有的数据行,然后根据给定的列排序。对于I/O密集型应用,效率会高很多。

执行器

进入到执行sql到环节。

  • 通过之前到查询优化,进入执行阶段,此时会先判断该连接用户是否有相关表的权限,如果没有会返回权限错误。如果有权限就会打开表,执行器会根据表定义的引擎去使用这个引擎提供的接口完成流程。

存储引擎

关于存储引擎,这里明确提醒。不是三种也不是四种。而是多种因为随时可能出现新的引擎。

  • 我们常用的就是InnoDBMyISAM,其它的不常见就不做过多介绍。mysql现在默认的引擎是InnoDB所以主要也是了解InnoDB
1
2
# 查看当前服务支持的存储引擎
SHOW ENGINES;

Read more »

准备学习下neo4j记录在mac下安装neo4j的坑。

neo4j官网网站下载失败

国内只能从镜像地址下载

http://doc.we-yun.com:1008/

配置jdk11

可以查看我上面内容实用Jenv管理多个版本。

启动neo4j

下载完成后解压

1
2
3
4
# 启动
./neo4j start
# 关闭
./neo4j stop

neo4j界面

  • 在浏览器中输入localhost:7474
  • 初始用户名、密码均为neo4j, 第一次登录需要修改密码

安装jupyter

注意提前安装python环境

1
2
3
pip install jupyter notebook -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com
# 检查版本
jupyter --version

简单记录下mac下多版本jdk管理

检查环境

查看当前安装的jdk版本

1
2
/usr/libexec/java_home -V
# 如果有安装过jdk版本这里会输出信息

使用brew 安装jenv

1
2
3
4
brew install jenv
#检查
jenv doctor
# 刚安装会提示很多信息

初始化jenv

1
2
3
4
5
brew install jenv
jenv init -
echo 'eval "$(jenv init -)"' >> ~/.bash_profile
echo 'eval "$(jenv init -)"' >> ~/.zprofile
jenv add <path-to-java8-Home-Dir> # 这里从/usr/libexec/java_home -V 获取javaHome

切换jdk

1
2
3
4
5
6
7
➜  ~ jenv versions
* system (set by /Users/zengqingfeng/.jenv/version)
1.8
1.8.0.275
openjdk64-1.8.0.275

➜ ~ jenv local system # 切换版本

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。也就是说JWT是Token的一种表述性声明规范。

JWT(Json Web Token)

JWT生成编码后的样子

  • 结构类似 xxx.yyy.zzz
1
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6IuWkqeihjOWBpeeuoeeQhueUqOaItyIsImF1ZGllbmNlIjoid2ViIiwibmJmIjoxNTA3Njg0OTQyLCJpc3MiOiJ3d3cuMW9uZS5jbiIsImV4cCI6MTUwNzY4Njc0MiwiaWF0IjoxNTA3Njg0OTQyLCJqdGkiOjEwMDB9.GGF0kFbxNk2ezzuXEJVBZyyL4e4BYMdpse73cSDrUut7cbVyYuLG1CNr8RI7eI3VHz9sdCB14Kesi8rP-v3VJA
  • base64解析之后
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"body":{
"sub":"admin",
"aud":"XXX用户",
"audience":"web",
"nbf":1507684942,
"iss":"www.xxx.cn",
"exp":1507686742,
"iat":1507684942,
"jti":1000
},
"header":{
"typ":"JWT",
"alg":"HS512"
},
"signature":"GGF0kFbxNk2ezzuXEJVBZyyL4e4BYMdpse73cSDrUut7cbVyYuLG1CNr8RI7eI3VHz9sdCB14Kesi8rP-v3VJA"
}
Read more »