MySQL学习笔记

文章目录

SQL基础

SQL(Structured Query Language,结构化查询语言)是用于管理关系数据库管理系统(RDBMS)。 SQL 的使用范围包括数据插入、查询、更新和删除,数据库模式创建和修改,以及数据访问控制。

1、基础语法

1.1 数据定义语言(DCL)

1.1.1 create(创建)
  1. 数据库

    create database [if not exists] 数据库名称 [character set 字符集];
    

    注意:数据库使用的默认编码为ISO-8859-1,且不支持中文。

  2. create [if not exists] table 表名(字段名1 字段类型1, 字段名2 字段类型2, ...);
    
1.1.2 alter(修改)
  1. 数据库

    • 修改数据库名

      alter database 数据库名 rename 新数据库名
      
    • 修改表名

      alter table 表名 rename 新表名;
      
    • 添加字段

      alter table 表名 add [column] 字段名称 字段类型;
      
    • 修改字段名

      alter table 表名 change 旧字段名称 字段名称 字段类型;
      
    • 修改字段类型

      alter table 表名 modify 字段名 数据类型;
      
    • 删除字段

      alter table 表名 drop [column] 字段名称;
      
    • 修改存储引擎

      alter table 表名 engine=存储引擎名;
      
    • 修改表字符集

      alter table 表名 [default] character set 字符集名 [default] collate 校对规则名;
      
  2. 索引

    • 添加新索引

      -- 添加唯一索引ALTER table 表名称 ADD UNIQUE INDEX 索引名称(字段名);-- 添加主键索引ALTER TABLE 表名称 ADD PRIMARY KEY 索引名称(字段名);-- 添加普通索引ALTER TABLE 表名称 ADD INDEX 索引名称(字段名);-- 添加全文索引ALTER TABLE 表名称 ADD FULLTEXT 索引名称(字段名);
      
1.1.3 constraint
1.1.4 merge

根据与源表联接的结果,对目标表执行插入、更新或删除操作。

  1. 数据同步

    
    
  2. 数据转换

    
    
  3. 基于源表对目标表做Insert,Update,Delete操作

    merge into 目标表 as T using 源表 as Son 条件 when matchedthen update set T.列 [DESC] = S.列 [DESC]when not matchedthen insert values (S.id, S.[DESC])when not matched by sourcethen delete;
    
1.1.5 rename table

重命名表,原子操作

rename table 表名称1 to 新表名称1 [表名称2 to 新表名称2,...];
1.1.6 truncate table

清空表数据

truncate table 表名称;
1.1.7 drop(删除)
  1. 数据库

    drop [if exists] database 数据库名称;
    
  2. drop [if exists] table 表名;
    

1.2 数据操作语言(DML)

1.2.1 insert(插入)
  1. insert into

    insert into 表名称[(字段名称1, 字段名称2, ...)] values(值1, 值2, ...);
    
  2. insert delayed

    insert delayed into 表名称[(字段名称1, 字段名称2, ...)] values(值1, 值2, ...);
    
  3. insert select

    insert into 表名称1[(字段名称1, 字段名称2, ...)] select (字段名称1, 字段名称2, ...) from 表名称2;
    

    注意:

    1. 要求表名称1必须存在,并且(字段名称1, 字段名称2, ...)也必须存在;
    2. 注意语法,不要加values;
    3. 注意表名称1的主键约束,如果表名称1有主键且不为空,则(字段名称1, 字段名称2, ...)中必须包括主键。
1.2.2 update(修改)
-- 修改表中满足条件的记录update 表名 set 字段名=值 where 条件;
1.2.3 delete(删除)
-- 删除表中满足条件的记录delete from 表名 [where 条件];
1.2.4 call(存储过程)

1.2.5 join(连接)
img
  1. 笛卡尔积(cross join)

    select (字段名称1, 字段名称2, ...) from 表名称1 cross join 表名称2 [on 表名称1.字段1 = 表名称2.字段2];
    
  2. 内连接(inner join)

    select (字段名称1, 字段名称2, ...) from 表名称1 inner join 表名称2 [on 表名称1.字段1 = 表名称2.字段2];
    
  3. 外连接(outer join)

    select (字段名称1, 字段名称2, ...) from 表名称1 outer join 表名称2 [on 表名称1.字段1 = 表名称2.字段2];
    
  4. 左连接(left join)

    select (字段名称1, 字段名称2, ...) from 表名称1 left join 表名称2 [on 表名称1.字段1 = 表名称2.字段2];
    
  5. 右连接(right join)

    select (字段名称1, 字段名称2, ...) from 表名称1 right join 表名称2 [on 表名称1.字段1 = 表名称2.字段2];
    
  6. 自然连接(nature join)

    select (字段名称1, 字段名称2, ...) from 表名称1 nature join 表名称2;
    
1.2.6 load data

load data 能够快速将一个文本文件的内容导入到对应数据库的表中,其效率远高于insert into语句。

LOAD DATA    [LOW_PRIORITY | CONCURRENT] [LOCAL]    INFILE 文件名称    [REPLACE | IGNORE]    INTO TABLE 表名称    [PARTITION (partition_name [, partition_name] ...)]    [CHARACTER SET charset_name]    [{FIELDS | COLUMNS}        [TERMINATED BY 'string']        [[OPTIONALLY] ENCLOSED BY 'char']        [ESCAPED BY 'char']    ]    [LINES        [STARTING BY 'string']        [TERMINATED BY 'string']    ]    [IGNORE number {LINES | ROWS}]    [(col_name_or_user_var        [, col_name_or_user_var] ...)]    [SET col_name={expr | DEFAULT},        [, col_name={expr | DEFAULT}] ...]
1.2.7 union(合并)

union用于合并两个或多个select语句的结果集。

select (字段名称1, 字段名称2, ...) from 表名称1unionselect (字段名称1, 字段名称2, ...) from 表名称2;

注意:

  1. union 内部的select语句必须拥有相同数量的列;
  2. 列也必须拥有相似的数据类型;
  3. 每条select语句中的列的顺序必须相同。

union all 允许重复的值。

select (字段名称1, 字段名称2, ...) from 表名称1union allselect (字段名称1, 字段名称2, ...) from 表名称2;
1.2.8 replace

replace into 与 insert into 功能类似,不同之处:replace into 首先尝试插入数据到表中,根据主键或者唯一索引判断表中是否已有数据 ,若有,则先删除该数据,然后插入新数据。若无,则直接插入新数据。

注意:插入数据的表必须有主键或者是唯一索引,否则,replace into 会直接插入数据,可能会导致表中出现重复的数据。

replace into 表名[(字段名称1, 字段名称2, ...)] values(值1, 值2, ...);

1.3 数据查询语言(DQL)

1.3.1 select(查询)
select 字段1, 字段2, 字段3, ... from 表名 [where 条件];
1.3.2 group by

group by 语句用于结合聚合函数,根据一个或多个列对结果集进行分组。

select 字段1, 字段2, 字段3, ...,聚合函数(字段名) from 表名 [where 条件] [group by 字段名];
1.3.3 having

在 SQL 中增加 having 子句原因是,where 关键字无法与聚合函数一起使用,而 having 子句可以筛选分组后的各组数据。

select 字段1, 字段2, 字段3, ...,聚合函数(字段名) from 表名 [where 条件] [group by 字段名] [having 聚合函数(字段名)条件];

实例:

SELECT Websites.name, Websites.url, SUM(access_log.count) AS nums FROM (access_logINNER JOIN WebsitesON access_log.site_id=Websites.id)GROUP BY Websites.nameHAVING SUM(access_log.count) > 200;

1.4 数据定义语言(DDL)

1.4.1 create

创建数据库和表等对象

1.4.2 drop

删除数据库和表等对象

1.4.3 alter

修改数据库和表等对象的结构

1.5 用户管理

  1. 创建新用户

    create user 用户名称 [identified by '密码'];
    
  2. 修改用户密码

    set password for 用户名称 = password("新密码");
    
  3. 删除用户

    drop user '用户名称';
    
  4. 设置用户权限

    grant 权限 on 数据库.表名 用户名称 with grant option;
    

    权限说明:

    • all表示所有权限

    数据库.表名*表示数据库中的所有表

    with grant option:表示当前用户可将自身所具备的权限,授权给其他用户

  5. 显示当前用户的权限

    -- 方式一show grants-- 方式二select user,host from mysql.user;select * from mysql.user where user=用户名;
    
  6. 取消用户权限

    revoke all privileges, grant option from 用户名称;
    
  7. 若忘记root用户密码,修改方法

    步骤一:先关闭MySQL服务器,再重启服务;

    mysqld --consle --skip-grant-tables;  # 不使用密码登录
    

    步骤二:重新设置密码。

    upadte user set password = password("新密码") where user = "root";
    

1.6 管理员操作

1.6.1 binlog
1.6.2 cache index
1.6.3 flush

清除或者重新加载内部缓存

-- 重新查询缓存flush query cache;-- 清空主机缓存表flush hosts;-- flush slave;-- 关闭当前的二进制日志文件并创建一个新文件flush logs;-- flush master;-- 关闭所有打开的表,同时清空查询缓存中的内容flush tables with read lock;-- 重置大多数状态变量到0flush status;
1.6.4 help command
1.6.5 kill
1.6.6 load index
1.6.7 reset
1.6.8 set
1.6.9 show
  1. 用户

    -- 显示开发者信息show authors;-- 显示当前用户的权限show grants;
    
  2. 日志

    -- show binary logs;
    
  3. 字符集

    -- 显示支持的字符集show character set;show character set 'latin%';-- 显示字符集的排列方式show collation;show collation LIKE 'utf8%';
    
  4. 数据库

    -- 显示所有数据库show databases;-- 显示数据库创建SQL语句show create database 数据库名称;
    
  5. -- 显示当前数据库中所有的表show tables;-- 显示创建表的SQL语句show create table 表名称;-- 显示数据库中表的状态show table status;-- 显示给定表的列show columns from 表名称;-- 显示在表缓存中当前被打开的非TEMPORARY表show open tables;
    
  6. 触发器

    -- 别处表定义触发器的SQL语句show create trigger 触发器名称;-- 列出当前数据库下,表中定义的触发器show triggers;
    
  7. 视图

    -- show creat view ;
    
  8. 存储引擎

    -- 显示当前数据库支持的存储引擎show engines;-- 显示存储引擎的日志或状态信息show engine 存储引擎名称 LOGS;show engine 存储引擎名称 STATUS;
    
  9. 错误信息

    -- 显示一条语句执行而导致的出错信息show errors;-- 显示上一条语句执行的警告信息show warnings;
    
  10. 索引

    -- 显示给定表的索引信息show index from 表名称;
    
  11. 事件

    -- show create event;-- show binary events;--show relaylog events;
    
  12. 函数

    -- show create function;-- show function code;-- show function status;
    
  13. 性能分析

    -- show profile;-- show profiles;
    
  14. 存储过程

    -- 显示创建存储过程的SQL语句show create procedure 存储过程名称;-- 显示有关存储函数的信息show procedure code;-- 显示存储过程show procedure status;
    
  15. 插件

    -- 显示MySQL的插件show plugins;
    
  16. 变量

    -- show variables;-- show status;
    
  17. 其他

show contributions;-- 显示MySQL中可分配权限的列表show privileges;-- 列出连接到相同MySQL服务器的当前会话。show processlist;-- show master status;-- show slave hosts;-- show slave status;

1.7 其他约束

1.7.1 Where
select 字段1, 字段2, 字段3, ... from 表名称 where 条件;
1.7.2 Distinct

1.7.3 And & Or
select 字段1, 字段2, 字段3, ... from 表名称 where [条件1 and 条件2 or 条件3]
1.7.4 Order by & DESC/ASC

1.7.5 Like

1.7.6 In

1.7.7 Between And

2、数据类型

2.1 数值类型

2.1.1 整数类型
类型名称说明存储需求取值范围
TINYINT很小的整数(-128〜127)1个字节0 〜255
SMALLINT小的整数(-32768〜32767)2个宇节0〜65535
MEDIUMINT中等大小的整数( -8388608〜8388607)3个字节0〜16777215
INT普通大小的整数(-2147483648〜2147483647)4个字节0〜4294967295
BIGINT大整数( -9223372036854775808〜9223372036854775807)8个字节0〜18446744073709551615
2.1.2 小数类型

浮点类型有两种,分别是单精度浮点数(FLOAT)和双精度浮点数(DOUBLE);定点类型只有一种,就是 DECIMAL。

浮点类型和定点类型都可以用(M, D)来表示,其中M称为精度,表示总共的位数;D称为标度,表示小数的位数。

浮点数类型的取值范围为 M(1~255)和 D(1~30,且不能大于 M-2),分别表示显示宽度和小数位数。M 和 D 在 FLOAT 和DOUBLE 中是可选的,FLOAT 和 DOUBLE 类型将被保存为硬件所支持的最大精度。DECIMAL 的默认 D 值为 0、M 值为 10。

类型名称说明存储需求取值范围
FLOAT单精度浮点数4 个字节-3.402823466E+38~-1.175494351E-38(有符号)0 和 -1.175494351E-38~-3.402823466E+38(无符号)
DOUBLE双精度浮点数8 个字节-1.7976931348623157E+308~-2.2250738585072014E-308(有符号)0 和 -2.2250738585072014E-308~-1.7976931348623157E+308(无符号)
DECIMAL (M, D),DEC压缩的“严格”定点数M+2 个字节

FLOAT 和 DOUBLE 在不指定精度时,默认会按照实际的精度(由计算机硬件和操作系统决定),DECIMAL 如果不指定精度,默认为(10,0)。浮点数相对于定点数的优点是在长度一定的情况下,浮点数能够表示更大的范围;缺点是会引起精度问题。

2.2 字符串类型

类型名称说明存储需求
CHAR(M)固定长度非二进制字符串M 字节,1<=M<=255
VARCHAR(M)变长非二进制字符串L+1字节,在此,L< = M和 1<=M<=255
TINYTEXT非常小的非二进制字符串L+1字节,在此,L<2^8
TEXT小的非二进制字符串L+2字节,在此,L<2^16
MEDIUMTEXT中等大小的非二进制字符串L+3字节,在此,L<2^24
LONGTEXT大的非二进制字符串L+4字节,在此,L<2^32
ENUM枚举类型,只能有一个枚举字符串值1或2个字节,取决于枚举值的数目 (最大值为65535)
SET一个设置,字符串对象可以有零个或多个SET成员,最多可以有 64 个1、2、3、4或8个字节,取决于集合 成员的数量(最多64个成员)

CHAR 和 VARCHAR 的区别如下:

  1. CHAR 是固定长度字符,VARCHAR 是可变长度字符;
  2. CHAR 会自动删除插入数据的尾部空格,VARCHAR 不会删除尾部空格。

CHAR 是固定长度,所以它的处理速度比 VARCHAR 的速度要快,但是它的缺点就是浪费存储空间。所以对存储不大,但在速度上有要求的可以使用 CHAR 类型,反之可以使用 VARCHAR类型来实现。

存储引擎对于选择 CHAR 和 VARCHAR 的影响:

  1. 对于 MyISAM 存储引擎,最好使用固定长度的数据列代替可变长度的数据列。这样可以使整个表静态化,从而使数据检索更快,用空间换时间;
  2. 对于InnoDB存储引擎,最好使用可变长度的数据列,因为 InnoDB 数据表的存储格式不分固定长度和可变长度,因此使用 CHAR 不一定比使用 VARCHAR 更好,但由于 VARCHAR 是按照实际的长度存储,比较节省空间,所以对磁盘 I/O 和数据存储总量比较好。

2.3 日期/时间类型

类型名称日期格式日期范围存储需求
YEARYYYY1901 ~ 21551 个字节
TIMEHH:MM:SS-838:59:59 ~ 838:59:593 个字节
DATEYYYY-MM-DD1000-01-01 ~ 9999-123 个字节
DATETIMEYYYY-MM-DD HH:MM:SS1000-01-01 00:00:00 ~ 9999-12-31 23:59:598 个字节
TIMESTAMPYYYY-MM-DD HH:MM:SS1980-01-01 00:00:01 UTC ~ 2040-01-19 03:14:07 UTC4 个字节

2.4 二进制类型

类型名称说明存储需求存储范围
BIT(M)位字段类型大约 (M+7)/8 字节,M默认值为 1
BINARY(M)固定长度二进制字符串M 字节
VARBINARY (M)可变长度二进制字符串M+1 字节
TINYBLOB (M)非常小的BLOBL+1 字节,在此,L<2^8最大长度为255 (28-1)字节
BLOB (M)小 BLOBL+2 字节,在此,L<2^16最大长度为65535 (216-1)字节
MEDIUMBLOB (M)中等大小的BLOBL+3 字节,在此,L<2^24最大长度为16777215 (224-1)字节
LONGBLOB (M)非常大的BLOBL+4 字节,在此,L<2^32最大长度为4294967295或4GB (231-1)字节

BLOB是二进制字符串,TEXT是非二进制字符串,两者均可存放大容量的信息。BLOB主要存储图片、音频信息等,而TEXT 只能存储纯文本文件。

3、约束

3.1 null & not null

指示某列能否存储 NULL 值。

NOT NULL 约束强制列不接受 NULL 值。

NOT NULL 约束强制字段始终包含值。这意味着,如果不向字段添加值,就无法插入新记录或者更新记录。

3.2 unique

保证某列的每行必须有唯一的值。

3.3 primary key

NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。

每个表可以有多个 UNIQUE 约束,但是每个表只能有一个 PRIMARY KEY 约束。

每个表都应该有一个主键,并且每个表只能有一个主键。

3.4 foreign key

一个表中的 FOREIGN KEY 指向另一个表中的 UNIQUE KEY(唯一约束的键)。

3.5 deafult

规定没有给列赋值时的默认值。

3.6 check

保证列中的值符合指定的条件。

4、聚合函数

4.1 COUNT

计算表中的记录数(行数)。

COUNT函数的结果根据参数的不同而不同。

COUNT(*)会得到包含NULL的数据行数,而COUNT(列名)会得到NULL之外的数据行数。

4.2 SUM

计算表中数值列中数据的合计值。

4.3 AVG

计算表中数值列中数据的平均值。

4.4 MAX

求出表中任意列中数据的最大值。

4.5 MIN

求出表中任意列中数据的最小值。

MAX/MIN 函数和 SUM/AVG 函数有一点不同,那就是 SUM/AVG 函数只能对数值类型的列使用,而 MAX/MIN 函数原则上可以适用于任何数据类型的列。

5、集合运算

所谓集合运算,就是对满足同一规则的记录进行的加减等四则运算。

5.1 union & union all(并集)

并集是在行方向上进行操作。

select 语句1 union [all] select 语句2;

5.2 join(联结)

所谓联结运算,一言以蔽之,就是“以表A中的列作为桥梁,将表B中满足同样条件的列汇集到同一结果之中”。

5.2.1 inner join(内联结)

内联结只能选取出同时存在于两张表中的数据。

select 字段名1, 字段名2, 字段名3, ... from 表名1 inner join 表名2 on 联结条件

进行内联结时必须使用ON子句,并且要书写在FROM和WHERE之间。

5.2.2 outer join(外联结)

外联结能够选取出单张表中全部的信息。

select 字段名1, 字段名2, 字段名3, ... from 表名1 [left/right] outer join 表名2 on 联结条件

外联结中使用LEFT、RIGHT来指定主表。使用二者所得到的结果完全相同。

5.2.3 cross join(交叉联结)

6、高级查询

6.1 子查询

子查询就是一次性视图(SELECT语句)。与视图不同,子查询在SELECT语句执行完毕之后就会消失。

6.2 关联子查询

6.3 视图

表中存储的是实际数据,而视图中保存的是从表中取出数据所使用的SELECT语句。

-- 创建视图create view 视图名称 as 别名 select 语句;-- 删除视图drop view 视图名称;-- 查询视图select 字段1, 字段2, ... from 视图名称;

在 FROM 子句中使用视图的查询,通常有如下两个步骤:

  1. 首先执行定义视图的 SELECT 语句;
  2. 根据得到的结果,再执行在 FROM 子句中使用视图的 SELECT 语句

注意:

  1. 将经常使用的SELECT语句做成视图;
  2. 避免在视图的基础上创建视图,因为多重视图会降低 SQL 的性能;
  3. 定义视图时不要使用ORDER BY子句。

MySQL概述

1、简介

关系:以二维表来描述实体间的联系

记录:元组,表中的一行数据

字段:列(属性、域),表中的一列

注意事项:

  • 列名必须唯一
  • 列没有顺序
  • 行没有顺序

2、安装

2.1 Windows下,安装MySQL

进入MySQL下载页面,直接下载免安装版MySQL,解压至某一目录下,即可完成安装。

使用命令行模式,并切换到MySQL的安装路径,借助如下命令,安装MySQL服务。

在Windows中,使用MySQL服务

# 启动MySQLnet start mysql# 停止MySQLnet stop mysql

登录MySQL

mysql -uroot -p

2.2 Linux下,安装MySQL

以Ubuntu系统为例,安装MySQL

安装命令

sudo apt-get install mysql

2.3 Docker下,安装MySQL

拉取MySQL镜像

sudo docker pull mysql

生成MySQL容器

sudo docker run -it --name 容器名 --port 端口号:端口号 mysql

3、常用命令

默认数据库说明:

  • mysql,核心数据库
  • performance_schema,提供记录数据的数据库
  • information_schema,视图,虚拟表
  • test,空数据库

3.1 数据库操作

  1. 显示所有的数据库

    -- 显示所有的数据库show databases;-- 使用数据库,在对数据库操作之前必须使用use 数据库名称;
    
  2. 显示当前操作数据库

    select database();
    
  3. 查询表结构

    desc 表名;
    
  4. 查询数据库支持的字符集

    show character set;-- 显示当前系统的环境变量,且只显示编码show variables like ‘%cahr%’;
    
  5. 查看MySQL正在进行的线程

    show processlist
    

4、架构

图片

4.1 Server层

4.1.1 查询缓存
4.1.2 分析器
4.1.3 优化器
4.1.4 执行器

4.2 存储引擎层

存储引擎是数据库的底层组件,数据库管理系统依赖存储引擎进行创建、查询、更新和删除数据操作。

MySQL 提供了多个不同的存储引擎,包括处理事务安全表的引擎和处理非事务安全表的引擎。在 MySQL 中,不需要在整个服务器中使用同一种存储引擎,针对具体要求,可以对每一个表使用不同的存储引擎。

使用如下命令,可显示MySQL支持的存储引擎

show engines;

查看默认的存储引擎

show variables like '%storage_engine%';

查看表的存储引擎

show table status like 'table_name';

修改数据库临时的默认存储引擎

set default_storage_engine=存储引擎名;

修改表的存储引擎

alter table 表名 engine=存储引擎名;

MySQL支持的存储引擎,如下表所示:

存储引擎描述说明
ARCHIVE用于数据存档的引擎,数据被插入后就不能在修改了,且不支持索引
CSV在存储数据时,会以逗号作为数据项之间的分隔符
BLACKHOLE会丢弃写操作,该操作会返回空内容
FEDERATED将数据存储在远程数据库中,用来访问远程表的存储引擎
InnoDB具备外键支持功能的事务处理引擎
MEMORY置于内存的表。
MERGE用来管理由多个 MyISAM 表构成的表集合
MyISAM非事务处理存储引擎
NDBMySQL 集群专用存储引擎

为了能够正确地选择存储引擎,必须掌握各种存储引擎的特性。下面重点介绍几种常用的存储引擎,它们对各种特性的支持如下表所示。

特性MyISAMInnoDBMEMORY
存储限制支持
事务安全不支持支持支持
锁机制表级锁行级锁表级锁
B-Tree索引支持支持支持
Hash索引不支持不支持支持
全文索引支持不支持不支持
集群索引不支持支持不支持
数据缓存支持支持
索引缓存支持支持支持
数据可压缩性支持不支持不支持
空间使用N/A
内存使用中等
批量插入速度
支持外键不支持支持不支持

InnoDB与MyISAM,在磁盘上存储的文件是不同的。

  1. InnoDB:

    • .frm:存储表定义;
    • .idb:存储数据和索引,且二者在同一个文件中。
  2. MyISAM:

    • .frm:存储表定义;
    • .myd(MYData):存储数据;
    • .MYI(MYindex):存储索引。

5、建表规范

5.1 三大范式

5.1.1 第一范式

字段不能再分

5.1.2 第二范式

满足第一范式的条件下,不能出现部分依赖。

消除符合主键即可避免部分依赖

增加单列关键字

5.1.3 第三范式

满足第二范式的条件下,不能出现传递依赖( 某个字段依赖于主键,而有其他字段依赖于该字段)。

将一个实体信息的数据放在一个表内实现。

5.2 表结构设计原则

  1. 每张表具备一个ID字段作为主键;
  2. 推荐使用自增ID,而不要使用UUID;
  3. 字段定义为not null,因为null值会占用更多的字节;
  4. 每张表保存一个实体信息。

MySQL索引

索引的目的就是用于快速查找某一列的数据,对相关数据列使用索引能够大大提高查询操作的性能。不使用索引,MySQL 必须从第一条记录开始读完整个表,直到找出相关的行,表越大查询数据所花费的时间就越多。如果表中查询的列有索引,MySQL 能够快速到达一个位置去搜索数据文件,而不必查看所有数据,那么将会节省很大一部分时间。

索引是数据库优化中最常用也是最重要的手段,通过使用不同的索引可以解决大多数 SQL 性能问题。

索引的优缺点

优点:

  1. 加快数据检索速度,这也是创建索引的最主要的原因;
  2. 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

缺点:

  1. 时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率;
  2. 空间方面:索引需要占用物理空间。

1、索引类型

1.1 从数据结构上划分

1.1.1 全局索引

目前只有 MyISAM 引擎支持全局索引,它的出现是为了解决针对文本的模糊查询效率较低的问题,并且只限于 CHAR、VARCHAR 和 TEXT 列。

1.1.2 哈希索引

哈希索引是 MySQL 中用到的唯一 key-value 键值对的数据结构,很适合作为索引。HASH 索引具有一次定位的好处,不需要像树那样逐个节点查找,但是这种查找适合应用于查找单个键的情况,对于范围查找,HASH 索引的性能就会很低。默认情况下,MEMORY 存储引擎使用 HASH 索引,但也支持 BTREE 索引。

1.1.3 B-Tree 索引

B-Tree 是一种平衡树,它有很多变种,最常见的就是 B+ Tree,它被 MySQL 广泛使用。

1.1.4 R-Tree索引

R-Tree 在 MySQL 很少使用,仅支持 geometry 数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种,相对于 B-Tree 来说,R-Tree 的优势在于范围查找。

1.2 从逻辑上划分

1.2.1 单列索引
  1. 普通索引

    普通索引是最基础的索引类型,它没有任何限制 。创建命令如下:

    create index 索引名称 on 表名称(字段名称);
    

    删除命令:

    drop index 索引名称 on 表名称;
    
  2. 唯一索引

    唯一索引列的值必须唯一,允许有空值,如果是组合索引,则列值的组合必须唯一,创建方式如下:

    create unique index 索引名称 on 表名称(字段名称);
    
  3. 主键索引

    一种特殊的索引,一个表只能有一个主键,不允许有空值。一般是在建表的时候同时创建主键索引,如下:

    create table 表名称 (字段名称1 数据类型 约束,					字段名称2 数据类型 [约束],...,					primary key(字段名)) engine=innodb character set = utf8mb4;
    
1.2.2 组合索引

指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀原则。

1.2.3 全文索引

主要用来查找文本中的关键字,而不是直接与索引中的值相比较,目前只有 char、varchar,text 列上可以创建全文索引,创建表的适合添加全文索引。

create fulltext index 索引名称 on 表名称(字段名称);

1.3 根据数据中的物理顺序与键值的逻辑(索引)顺序关系划分

1.3.1 聚集索引

在 InnoDB 里,索引B+ Tree的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引,即将数据存储与索引放到了一块,找到索引也就找到了数据。

1.3.2 非聚集索引

索引B+ Tree的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引、二级索引。

二者的区别:

  1. 非聚集索引与聚集索引的区别在于非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键(行号);
  2. 对于InnoDB来说,想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。第一次索引一般是顺序IO,回表的操作属于随机IO。需要回表的次数越多,即随机IO次数越多,我们就越倾向于使用全表扫描 ;
  3. 通常情况下, 主键索引(聚簇索引)查询只会查一次,而非主键索引(非聚簇索引)需要回表查询多次。当然,如果是覆盖索引的话,查一次即可;
  4. 注意:MyISAM无论主键索引还是二级索引都是非聚簇索引,而InnoDB的主键索引是聚簇索引,二级索引是非聚簇索引。用户单独创建的索引基本都是非聚簇索引。

2、索引使用

2.1 创建索引需要注意的地方

  1. 非空字段:应该指定列为NOT NULL,除非你想存储NULL。在mysql中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值;
  2. 取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的前面,可以通过count()函数查看字段的差异值,返回值越大说明字段的唯一值越多字段的离散程度高;
  3. 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次IO操作获取的数据越大效率越高。

2.2 创建索引的原则

  1. 最左前缀匹配原则,MySQL会一直向右匹配直到遇到范围查询(><betweenlike)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整;
  2. =in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,MySQL的查询优化器会帮你优化成索引可以识别的形式;
  3. 尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大,扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录;
  4. 索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,B+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成 create_time = unix_timestamp(’2014-05-29’)
  5. 尽量扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

2.3 索引失效的情况

  1. 使用 != 或者 <> 导致索引失效;

  2. 类型不一致导致的索引失效;

  3. 函数导致的索引失效;

    SELECT * FROM `user` WHERE DATE(create_time) = '2020-09-03';
    
  4. 运算符导致的索引失效;

    SELECT * FROM `user` WHERE age - 1 = 20;
    
  5. OR引起的索引失效;

    SELECT * FROM `user` WHERE `name` = '张三' OR height = '175';
    

    在特定情况下,OR会导致索引失效,并不是所有的OR都是使索引失效,如果OR连接的是同一个字段,那么索引不会失效,反之索引失效。

  6. 模糊搜索导致的索引失效;

    SELECT * FROM `user` WHERE `name` LIKE '%冰';
    

    %放在匹配字段前是不走索引的,放在后面才会走索引。

  7. NOT IN、NOT EXISTS导致索引失效。

3、数据结构

3.1 B树

图片

3.2 B+树

图片

3.3 Hash

图片

4、最左前缀原则

最左前缀原则就是最左优先,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。MySQL会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。

=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。


MySQL事务

事务是逻辑上的一组操作,要么都执行,要么都不执行。

图片

1、四种特性

1.1 原子性(Atomicity)

事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。

1.2 一致性(Consistency)

执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的。

1.3 隔离性(Isolaton)

并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的。

1.4 持久性(Durability)

一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

2、事务隔离级别

多事务的并发进行一般会造成以下几个问题:

  1. 脏读:A事务读取到了B事务未提交的内容,而B事务后面进行了回滚。
  2. 丢失修改:指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改;
  3. 不可重复读:指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
  4. 幻读:A事务读取了一个范围的内容,而同时B事务在此期间插入了一条数据,造成"幻觉"。

为解决多事务并发导致的问题,MySQL中有四种事务隔离级别:

2.1 读取未提交(Read Uncommitted)

最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

2.2 读取已提交(Read Committed)

允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。

2.3 可重复读(Repeatable Read)

对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。MySQL InnoDB 存储引擎的默认支持的隔离级别是 Repeatable Read(可重复读),InnoDB 存储引擎在分布式事务的情况下一般会用到 SERIALIZABLE(可串行化)隔离级别。

2.4 可串行化(Serializable)

最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

3、事务实现原理

MySQL InnoDB 引擎使用 redo log(重做日志) 保证事务的持久性,使用 undo log(回滚日志) 来保证事务的原子性。 MySQL InnoDB 引擎通过锁机制、MVCC 等手段来保证事务的隔离性( 默认支持的隔离级别是 REPEATABLE-READ )。 保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。

4、事务执行流程

MySQL使用下列语句来管理事务。

4.1 开启事务

-- 方式一begin;-- 方式二start transaction;

4.2 提交事务

commit;

提交事务,意味着将事务开始以来所执行的所有数据都修改成为数据库的永久部分,因此也标志着一个事务的结束。一旦执行了该命令,将不能回滚事务。只有在所有修改都准备好提交给数据库时,才执行这一操作。

4.3 回滚事务

rollback;

当事务执行过程中遇到错误时,使用 ROLLBACK 语句使事务回滚到起点或指定的保持点处。同时,系统将清除自事务起点或到某个保存点所做的所有的数据修改,并且释放由事务控制的资源。因此,这条语句也标志着事务的结束。

5、事务使用注意事项

  1. 事务尽可能简短

    事务的开启到结束会在数据库管理系统中保留大量资源,以保证事务的原子性、一致性、隔离性和持久性。如果在多用户系统中,较大的事务将会占用系统的大量资源,使得系统不堪重负,会影响软件的运行性能,甚至导致系统崩溃。

  2. 事务中访问的数据量尽量最少

    当并发执行事务处理时,事务操作的数据量越少,事务之间对相同数据的操作就越少。

  3. 查询数据时尽量不要使用事务

    对数据进行浏览查询操作并不会更新数据库的数据,因此应尽量不使用事务查询数据,避免占用过量的系统资源。

  4. 在事务处理过程中尽量不要出现等待用户输入的操作

    在处理事务的过程中,如果需要等待用户输入数据,那么事务会长时间地占用资源,有可能造成系统阻塞。

6、MVCC

多版本并发控制(MultiVersion Concurrency Control,MVCC),其主要实现思想是通过数据多版本来做到读写分离,从而实现不加锁读,进而做到读写并行。

MVCC在MySQL中的实现依赖的是undo log与read view:

  1. undo log:undo log中记录某行数据的多个版本;
  2. read view:用来判断当前版本数据的可见性。

MySQL集群

1、概述

当业务量增加时,普通的单机架构无法满足系统性能提升的需求,而集群是将同一业务通过复制,然后部署,达到性能提升的目标。因此,数据库集群的好处可总结为以下几条:

  1. 高可用:故障迁移及检测,多节点备份;
  2. 可伸缩性:方便新增数据库节点,容易扩容;
  3. 负载均衡:分摊数据库节点的压力。

2、集群方案

2.1 MySQL Replication

2.2 MySQL Fabirc

2.3 MySQL Cluster

2.4 MMM(Master replication Manager for MySQL)

2.5 MHA(Master High Availability)

2.6 Galera Cluster

2.7 HeartBeat+SAN

2.8 HeartBeat+DRDB

2.9 ZooKeeper+Proxy

2.10 Paxos


MySQL分库分表

MySQL单表通常500w条数据以内比较合适,不建议超过1000w,如果超过1000w,建议做分库分表。

1、概述

一般解决分案:

借助MQ或异步读写系统,将并发量削峰,以减轻数据库访问压力。

图片

分库分表前分库分表后
并发情况MySQL 单机部署,扛不住高并发MySQL从单机到多机,能承受的并发增加了多倍
磁盘使用情况MySQL 单机磁盘容量几乎撑满拆分为多个库,数据库服务器磁盘使用率大大降低
SQL执行情况单表数据量太大,SQL 越跑越慢单表数据量减少,SQL 执行效率明显提升

2、水平拆分

水平拆分,就是将一个表中的数据划分到多个库的多个表里去,但是每个库的表结构都一样,只不过每个库表放的数据是不同的,所有库表的数据加起来就是全部数据。水平拆分的意义是将数据均匀放更多的库里,然后用多个库来扛更高的并发,还有就是用多个库的存储容量来进行扩容。

图片

3、垂直拆分

垂直拆分,就是把一个有很多字段的表给拆分成多个表,或者是多个库上去。每个库表的结构都不一样,每个库表都包含部分字段。一般来说,会将访问频率很高的字段放到一个表里去,然后将访问频率很低的字段放到另外一个表里去。因为数据库是有缓存的,你访问频率高的行字段越少,就可以在缓存里缓存更多的行,性能就越好。这个一般在表层面做的较多一些。

图片

假如有600w数据,现在要分库分表,综合来看分库分表可能是这样的:

图片

4、数据库中间件

图片

Sharding-Sphere(Sharding-jdbc)是一套开源的分布式数据库中间件解决方案,属于client端方案,也就是在业务系统只需要引用它的jar包,就可以使用了。Sharding-Sphere目前社区也还一直在开发和维护,还算是比较活跃。

MyCAT是基于Cobar改造的,属于 proxy 层方案,支持的功能非常完善,而且目前应该是非常火的而且不断流行的数据库中间件,社区很活跃。相比于 Sharding jdbc 来说,年轻一些,经历的锤炼少一些。

对比:

Sharding-Sphere这种client端方案的优点在于不用部署,运维成本低,不需要代理层的二次转发请求,性能很高,但是如果遇到升级,需要各个业务系统都重新升级版本再发布,各个系统都需要耦合Sharding-Sphere。

MyCAT 这种proxy层方案的缺点在于需要单独部署,自身运维一套中间件,成本高,但好处是对于各项目是透明的,如果需要升级只需要单独升级MyCAT即可。

通常来说,这两个方案都可以选用。中小型公司选用 Sharding-Sphere,client 层方案轻量级,而且维护成本低,不需要额外增派人手去维护,而且中小型公司系统复杂度会低一些,项目也没那么多。 但是中大型公司最好还是选用MyCAT这类proxy层方案,因为可能大公司系统和项目非常多,团队很大,人员充足,有专门人员研究和维护MyCAT,然后各个项目直接透明使用即可。


MySQL数据库中间件

1、Sharding-JDBC(ShardingSphere)

1.1 概述

Sharding-Sphere是一套开源的分布式数据库中间件解决方案,属于client端方案。

2、MyCAT

2.1 概述

2.1.1 简介

MyCat是目前最流行的基于Java编写的数据库中间件,是一个实现了MySQL协议的服务器,其核心功能是分库分表,配合数据库的主从模式能够实现读写分离。

2.1.2 架构

img

2.1.3 优势
  1. 单一的MySQL数据存储量和操作量级有限,MyCAT可以管理若干MySQL数据库,可以实现数据库的存储和操作;
  2. MyCAT是 java 编写的中间件,开源,免费,有非常多的人和组织对MyCAT进行开发、维护、管理、更新,MyCAT是由阿里原应用 corba 转型而来;

2.2 基本概念

2.2.1 切分

逻辑上的切分,在物理层面使用多库(database)、多表(table)实现切分。

2.2.1.1 纵向切分/垂直切分

将存储在一个库的数据存储在多个库上。

由于数据库的读写都是对同一个库进行操作,所以单库并不能解决大规模并发写入的问题。

例如:建立定义数据库 workDB、商品数据库 payDB、用户数据库 userDB、日志数据库 logDB 等。

优点:

  1. 减少增量数据写入时,锁对查询的影响;
  2. 由于单表数量下降,常见的查询操作由于减少了需要扫描的记录,使得单表单次查询所需检索的行数变少,减少了磁盘IO、时延变短。

缺点:

  1. 无法解决单表数据量太大的问题。
2.2.1.2 横向切分/水平切分

把存储于一个表的数据分块存储到多个表上。

当一个表中的数据量过大时,我们可以把该表的数据按照某种规则,进行划分,然后存储到多个结构相同的表上。

例如:userDB 中的 userTable 中数据量很大,那么可以把 userDB 切分为结构相同的多个 userDB:part0DB、part1DB 等,再将 userDB 上的 userTable,切分为很多 userTable:userTable0、userTable1 等,然后将这些表按照一定的规则存储到多个 userDB 上。

优点:

  1. 单表的并发能力提高了,磁盘的I/O性能也提高了;
  2. 如果出现高并发的话,总表可以根据不同的查询,将并发压力分散到不同的小表里。

缺点:

  1. 无法实现表连接查询。
2.2.2 逻辑库(Schema)

MyCAT中定义的database是逻辑上存在的,但物理上是不存在的,主要是针对纵向切分提供的概念。

2.2.3 逻辑表(Table)

MyCat中定义的table,逻辑上存在,物理上不存在,主要是针对横向切分提供的概念。

2.2.4 默认端口
类别默认端口号
MySQL3306
MyCAT8066
TomCat8080
Oracle1521
Nginx80
HTTP80
Redis6379
2.2.5 数据主机(DataHost)

物理MySQL存放的主机地址,可以使用主机名,IP,域名定义。

2.2.6 数据节点(DataNode)

配置物理的database。

数据保存的物理节点就是database。

img

2.2.7 分片规则

当控制数据的时候,如何访问物理database和table?

就是访问dataHost和dataNode的算法。

在Mysql处理CRUD时,如何访问datahost和datanode的算法?如:哈希算法,crc32算法等。

2.3、使用

2.3.1 主从备份
2.3.1.2 概念

主从备份是一种主备模式的数据库应用。

主库(master)数据与备库(slave)数据完全一致。

实现数据的多重备份,保证数据的安全。

可以在Master(InnoDB)和Slave(MyISAM)中使用不同的数据库存储引擎,实现读写分离。

2.3.1.2 目的
  1. 实现主备模式;

    保证数据安全,尽量避免数据丢失。

  2. 实现读写分离。

    使用不同的数据库引擎,实现读写分离,提高所有的操作效率; InnoDB使用DML语法操作、MyISAM使用DQL语法操作。

2.3.1.3 效果

主库操作同步到备库。

所有对Master的操作,都会同步到Slave中。

注意:如果 Master 和 Salve 天生上环境不同,那么对 Master 的操作,可能会在 Slave 中出现错误。

如:在创建主从模式之前,Master 有 database:db1、db2、db3。Slave 有 database:db1、db2。创建主从模式,现在的情况 Master 和 Slave 天生不同,主从模式创建成功后,在 Master 中 drop database db3, Slave 中抛出数据库 SQL 异常,后续所有的命令不能同步。一旦出现错误,只能重新实现主从模式。

2.3.1.4 逻辑视图

img

2.3.2 搭建MySQL主从模式
2.3.2.1 Master配置
2.3.2.2 Slave配置
2.3.2.3 安装配置MyCAT

MySQL性能优化

MySQL数据库的常见性能瓶颈主要是在CPU和I/O上

1、慢查询分析

1.1 慢查询日志

1.2 EXPLAIN分析查询

在MySQL中,主要通过Explain命令来分析低效SQL语句的执行。该命令使用示例:

explain select * from adminlog;

执行结果:

idselect_typetablepartitjonstypepossible_keyskeykey_lenref
1SIMPLEadminlogALL

说明:

  1. select_type:查询类型,常见值SIMPLE(简单表,不使用表连接或子查询);
  2. table:输出结果的表;
  3. type:表示MySQL在表中找到所需行的方式,或者叫访问类型。常见类型有:
ALLindexrangerefeq_refconst/systemNull

从左到右,性能逐渐变好。一个好的SQL语句至少要达到range级别,避免出现all级别。

  • ALL(全表扫描);
  • index(索引全扫描);
  • range(索引范围扫描,常见于<,<=,>,>=,between,in等操作符);
  • ref(使用非唯一索引或唯一索引的前缀扫描,返回匹配某个单独值的记录行。ref还经常出现在JOIN操作中);
  • eq_ref(类似于ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中有一条记录匹配;简单来说,说是多表连接中使用 主建或唯一健作为关联条件);
  • const/system(单表中最多有一个匹配行。主要用于比较primary key [主键索引]或者unique[唯一]索引,因为数据都是唯一的,所以性能最优。条件使用=);
  • NULL(不用访问表或者索引,直接就能够得到结果)。
  1. possible_keys:可能使用的索引列表;
  2. key:实现执行使用索引列表,若没有选择索引,值是NULL,但可以采取强制索引方式;
  3. key_len:索引长度;
  4. ref:显示使用哪个列或常数与key一起从表中选择行
  5. row:执行查询的行数,简单且重要,数值越大越不好,说明没有用好索引;
  6. filterod:
  7. extra:该列包含MySQL解决查询的详细信息。注意常见不友好的值:Using filesort、Using temporary

1.3 profiling分析查询

2、优化索引

尽量覆盖索引,5.6支持索引下推。

组合索引符合最左匹配原则。

避免索引失效。

在写多读少的场景下,可以选择普通索引而不是唯一索引。更新时,普通索引可以使用change buffer进行优化,减少磁盘IO,将更新操作记录到change bufer,等查询来了将数据读到内存再进行修改。

索引建立原则(一般建在where和order by,基数要大,区分度要高,不要过度索引,外键建索引)。

3、优化步骤

排查思路

使用show status命令查看服务器状态信息,了解SQL执行次数。

查看MySQL慢查询日志是否开启

show variables like "%slow%";

启用慢查询日志

set global show_query_log="ON";

4、调优工具

4.1 mysqltuner.pl

4.2 tuning-primer.sh

4.3 pt-variable-advisor

4.4 pt-qurey-digest


MySQL日志

日志是 MySQL 数据库的重要组成部分,记录着数据库运行期间各种状态信息。MySQL日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。

1、二进制日志(binlog)

binlog 用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。binlog 是 mysql的逻辑日志,并且由 Server 层进行记录,使用任何存储引擎的 mysql 数据库都会记录 binlog 日志。

  1. 逻辑日志(记录sql语句);
  2. 物理日志(MySQL数据最终是保存在数据页中的,物理日志记录的就是数据页变更)。

binlog 是通过追加的方式进行写入的,可以通过max_binlog_size 参数设置每个 binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。

1.1 使用场景

在实际应用中, binlog 的主要使用场景有两个,分别是 主从复制 和 数据恢复 :

  1. 主从复制 (在 Master 端开启 binlog ,然后将 binlog发送到各个 Slave 端, Slave 端重放 binlog 从而达到主从数据一致);
  2. 数据恢复 (通过使用 mysqlbinlog 工具来恢复数据)。

1.2 刷盘时机

对于 InnoDB 存储引擎而言,只有在事务提交时才会记录biglog,mysql 通过 sync_binlog 参数控制 biglog 的刷盘时机,取值范围是 0-N:

  1. 0(不去强制要求,由系统自行判断何时写入磁盘);
  2. 1(每次 commit 的时候都要将 binlog 写入磁盘);
  3. N(每N个事务,才会将 binlog 写入磁盘)。

由上可知, sync_binlog 最安全的是设置是 1 ,这也是MySQL 5.7.7之后版本的默认值。但是设置一个大一些的值可以提升数据库性能,因此实际情况下也可以将值适当调大,牺牲一定的一致性来获取更好的性能。

1.3 日志格式

binlog 日志有三种格式,分别为 STATMENT 、 ROW 和 MIXED。

  1. STATMENT:基于SQL 语句的复制( statement-based replication, SBR ),每一条会修改数据的sql语句会记录到binlog 中 。
    • 优点:不需要记录每一行的变化,减少了 binlog 日志量,节约了 IO , 从而提高了性能;
    • 缺点:在某些情况下会导致主从数据不一致,比如执行sysdate() 、 slepp() 等 。
  2. ROW:基于行的复制(row-based replication, RBR ),不记录每条sql语句的上下文信息,仅需记录哪条数据被修改了 。
    • 优点:不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题 ;
    • 缺点:会产生大量的日志,尤其是alter table 的时候会让日志暴涨。
  3. MIXED:基于STATMENT 和 ROW 两种模式的混合复制(mixed-based replication, MBR ),一般的复制使用STATEMENT 模式保存 binlog ,对于 STATEMENT 模式无法复制的操作使用 ROW 模式保存 binlog。

1.4 还原数据库

数据库遭到意外损坏时,应该先使用最近的备份文件来还原数据库。另外备份之后,数据库可能进行了一些更新,这时可以使用二进制日志来还原。因为二进制日志中存储了更新数据库的语句,如 UPDATE 语句、INSERT 语句等。

二进制日志还原数据库的命令如下:

mysqlbinlog filename.number | mysql -u root -p

技巧:二进制日志虽然可以用来还原 MySQL 数据库,但是其占用的磁盘空间也是非常大的。因此,在备份 MySQL 数据库之后,应该删除备份之前的二进制日志。如果备份之后发生异常,造成数据库的数据损失,可以通过备份之后的二进制日志进行还原。

2、事务日志

2.1 redo log

事务的四大特性里面有一个是持久性 ,具体来说就是只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态 。 那么 mysql是如何保证一致性的呢? 最简单的做法是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中。但是这么做会有严重的性能问题,主要体现在两个方面:

  1. Innodb 是以 页 为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,如果将完整的数据页刷到磁盘,太过于浪费资源。
  2. 一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差。

因此 mysql 设计了 redo log , 具体来说就是只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序IO)。

2.1.1 基本概念

redo log 包括两部分:一个是内存中的日志缓冲( redo log buffer ),另一个是磁盘上的日志文件( redo logfile)。 mysql 每执行一条 DML 语句,先将记录写入 redo log buffer,后续某个时间点再一次性将多个操作记录写到 redo log file。这种先写日志,再写磁盘的技术就是 MySQL 中常说的 WAL(Write-Ahead Logging) 技术。

在计算机操作系统中,用户空间( user space )下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间( kernel space )缓冲区( OS Buffer )。 因此, redo log buffer 写入 redo logfile 实际上是先写入 OS Buffer ,然后再通过系统调用 fsync() 将其刷到 redo log file 中,过程如下:

图片

mysql 支持三种将 redo log buffer 写入 redo log file 的时机,可以通过 innodb_flush_log_at_trx_commit 参数配置,各参数值含义如下:

图片

图片

2.1.2 记录形式

redo log 实际上记录数据页的变更,而这种变更记录是没必要全部保存,因此 redo log实现上采用了大小固定,循环写入的方式,当写到结尾时,会回到开头循环写日志。如下图:

图片

在innodb中,既有redo log 需要刷盘,还有 数据页 也需要刷盘, redo log存在的意义主要就是降低对 数据页 刷盘的要求 。 在上图中, write pos 表示 redo log 当前记录的 LSN (逻辑序列号)位置, check point 表示 数据页更改记录 刷盘后对应 redo log 所处的 LSN(逻辑序列号)位置。 write pos 到 check point 之间的部分是 redo log 空着的部分,用于记录新的记录;check point 到 write pos 之间是 redo log 待落盘的数据页更改记录。当 write pos追上check point 时,会先推动 check point 向前移动,空出位置再记录新的日志。 启动 innodb 的时候,不管上次是正常关闭还是异常关闭,总是会进行恢复操作。因为 redo log记录的是数据页的物理变化,因此恢复的时候速度比逻辑日志(如 binlog )要快很多。 重启innodb 时,首先会检查磁盘中数据页的 LSN ,如果数据页的LSN 小于日志中的 LSN ,则会从 checkpoint 开始恢复。

还有一种情况,在宕机前正处于checkpoint 的刷盘过程,且数据页的刷盘进度超过了日志页的刷盘进度,此时会出现数据页中记录的 LSN 大于日志中的 LSN,这时超出日志进度的部分将不会重做,因为这本身就表示已经做过的事情,无需再重做。

2.1.3 redo log 与 binlog的区别

图片

由图可知:binlog 日志只用于归档,只依靠 binlog 是没有 crash-safe 能力的。 但只有 redo log 也不行,因为 redo log 是 InnoDB特有的,且日志上的记录落盘后会被覆盖掉。因此需要 binlog和 redo log二者同时记录,才能保证当数据库发生宕机重启时,数据不会丢失。

2.2 undo log

数据库事务四大特性中有一个是原子性 ,具体而言,原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。 实际上, 原子性 底层就是通过 undo log 实现的。undo log主要记录了数据的逻辑变化,比如一条 INSERT 语句,对应一条DELETE 的 undo log ,对于每个 UPDATE 语句,对应一条相反的 UPDATE 的 undo log ,这样在发生错误时,就能回滚到事务之前的数据状态。 同时, undo log 也是 MVCC(多版本并发控制)实现的关键。


MySQL数据备份与恢复

任何数据库都需要备份,备份数据是维护数据库必不可少的操作。在操作数据过程中,可能会导致数据错误,甚至数据库奔溃,而有效的定时备份能很好地保护数据库。

1、数据备份

2、数据恢复


缓存一致性

1、概述

为提高系统的性能一般都会引入缓存机制,比如 Redis。这种情况下当用户读数据时一般会按照如下流程:

图片

2、解决方案

2.1 缓存TTL

简单直接又暴力的方法,如果有些数据不重要,在读完一次数据到缓存后设置个TTL即可,等待超时后缓存自动从数据库读取数据。

2.2 先更新数据库,再更新缓存

非正常执行情况:

图片

如果出现网络震荡会导致缓存的数据是旧数据。因此这种方法不可取。并且如果是如下场景也不合适:

  1. 写场景多而读场景少的业务需求,此时缓存不是经常性的读,却被频繁的更新;
  2. 如果缓存的数据是经过各种复杂计算后写入的,那每次写入缓存都要运算一次,此法不可取。

2.3 先删缓存,再更新数据库

假如A先请求更改数据,B请求读数据,如果因为网络导致发生如下情况也会造成缓存脏数据,如果此时缓存没有设置TTL那会一直是脏数据。

图片

一般可以采用延时双删策略,解决上述问题,其核心处理流程如下:

public void write(String key, Object value){    redis.delKey(key);    db.updateValue(value);    Thread.sleep(1000); // 再次删除    redis.delKey(key);}

该思路落实到流程图上,如下图所示:

图片

sleep的时间要根据业务数据逻辑耗时而定,反正目的是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

当然如果用的是主从写读架构,那处理思路跟上面类似,无非就是休眠时间再加上主从同步的时间即可。

图片

二次删除,仍存在有缺陷的地方:

  1. 二次删除前面涉及到休眠,可能导致系统性能降低,可以采用异步的方式,再起一个线程来进行异步删除;
  2. 如果二次删除失败,仍然会导致缓存脏数据存在。

2.4 先更新数据库,再删缓存

针对缓存更新问题,有一个名为Cache-Aside pattern的缓存更新套路,该策略在Facebook中广泛使用,该策略指出:

  1. 失效:应用程序先从缓存取数据,没有得到,则从数据库中取数据,成功后,放到缓存中;
  2. 命中:应用程序从缓存中取数据,取到后返回;
  3. 更新:先把数据存到数据库中,成功后,再让缓存失效。

假如此时A、B两个线程同时请求,正常而言,不论是读写分离还是单机版,读一般比写快。因此,删除缓存一般是有效的。

图片

但是也有可能别的原因导致读比写还慢,虽然这种情况很少发生。

图片

该方案相比先删除缓存再更新数据库还是稳妥些的,但是也不是万无一失。不管是先删缓存再更新数据库还是先更新数据库再删缓存,如果删除缓存失败了都会导致缓存跟数据不一致问题!

2.5 消息队列,确保消息删除

通过消息队列的确认消费机制来删除缓存。

图片

缺点:

  1. 引入中间件,对业务线代码造成大量的侵入;
  2. 消息的延迟删除也会造成短暂的不一致。

2.6 专门程序+消息队列,确保消息删除

该方案启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。

图片

订阅binlog程序在mysql中有现成的中间件叫canal,可以完成订阅binlog日志的功能。

方案选择:

数据更新时缓存是删除不是更新,而删除缓存一般有三种方法:

  1. 如果缓存数据不敏感,直接给缓存设置TTL即可;
  2. 先删缓存再更新数据库,此时需配合延时双删技术,但可能导致二次删除失败;
  3. 先更新数据库再删缓存,此时需配合binlog消费 + 消息队列来实现。

MySQL锁机制

图片

1、分类

当数据库中有多个操作需要修改同一数据时,不可避免的会产生数据的脏读。这时就需要数据库具有良好的并发控制能力,这一切在 MySQL 中都是由服务器和存储引擎来实现的。解决并发问题最有效的方案是引入了锁的机制,锁在功能上分为共享锁 (shared lock) 和排它锁 (exclusive lock) 即通常说的读锁和写锁; 锁的粒度上分行锁和表锁,表级锁MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL) 。

图片

1.1 共享锁

又叫做读锁,当用户要进行数据的读取时,对数据加上共享锁,共享锁可以同时加上多个。

1.2 排他锁

又叫做写锁,当用户要进行数据的写入时,对数据加上排他锁,排他锁只可以加一个,它和其他的排他锁,共享锁都相斥。

1.3 行级锁种类

  1. Next-Key Lock:锁定一个范围,并且锁定记录本上;
  2. Gap Lock:间隙锁,锁定一个范围,但不包含记录本上;
  3. Record Lock:单个行记录上的锁。

2、加锁规则

虽然 MySQL 的锁各式各样,但是有些基本的加锁原则是保持不变的,比如:快照读是不加锁的,更新语句肯定是加排它锁的,RC 隔离级别是没有间隙锁的等等。这些规则整理如下:

2.1 常见语句的加锁

  1. SELECT … 语句正常情况下为快照读,不加锁;
  2. SELECT … LOCK IN SHARE MODE 语句为当前读,加 S 锁;
  3. SELECT … FOR UPDATE 语句为当前读,加 X 锁;
  4. 常见的 DML 语句(如 INSERT、DELETE、UPDATE)为当前读,加 X 锁;
  5. 常见的 DDL 语句(如 ALTER、CREATE 等)加表级锁,且这些语句为隐式提交,不能回滚;

2.2 表锁分析

  1. 表锁(分 S 锁和 X 锁)
  2. 意向锁(分 IS 锁和 IX 锁)
  3. 自增锁(一般见不到,只有在 innodb_autoinc_lock_mode = 0 或者 Bulk inserts 时才可能有)

2.3 行锁分析

  1. 行锁都是加在索引上的,最终都会落在聚簇索引上;
  2. 加行锁的过程是一条一条记录加的;

2.4 锁冲突

S 锁和 S 锁兼容;

X 锁和 X 锁冲突;

X 锁和 S 锁冲突;

2.5 不同隔离级别下的锁

  1. 上面说 SELECT … 语句正常情况下为快照读,不加锁;但是在 serializable 隔离级别下为当前读,加 S 锁;
  2. RC 隔离级别下没有间隙锁和 next-key 锁。

3、SQL语句加锁分析

4、如何避免死锁

死锁的根本原因是有两个或多个事务之间加锁顺序的不一致造成的。

  1. 对索引加锁顺序的不一致很可能会导致死锁,因此,尽量以相同的顺序来访问索引记录和表。在程序以批量方式处理数据的时候,如果事先对数据排序,保证每个线程按固定的顺序来处理记录,也可以大大降低出现死锁的可能;
  2. 为表添加合理的索引,如果不走索引将会为表的每一行记录加锁,死锁的概率就会大大增大;
  3. 避免大事务,尽量将大事务拆成多个小事务来处理;因为大事务占用资源多,耗时长,与其他事务冲突的概率也会变高;
  4. 避免在同一时间点运行多个对同一表进行读写的脚本,特别注意加锁且操作数据量比较大的语句;避免定时任务脚本在同一时间点运行;
  5. 设置锁等待超时参数:innodb_lock_wait_timeout(默认50s),这个参数并不是只用来解决死锁问题,在并发访问比较高的情况下,如果大量事务因无法立即获得所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖跨数据库。我们通过设置合适的锁等待超时阈值,可以避免这种情况发生。

实际场景中如何避免锁的资源竞争:

  1. 让 SELECT 速度尽量快,尽量减少大的复杂的Query,将复杂的Query分拆成几个小的Query分步进行;
  2. 尽可能地建立足够高效的索引,让数据检索更迅速;
  3. 使用EXPLAIN SELECT来确定对于查询中使用的索引与预期一致。

ORM框架

1、MyBatis

2、MyBatis-Plus

3、JdbcTemplate

3.1 POM依赖


3.2 Spring配置文件


4、Fluent MyBatis


参考

1、SQL基础

  1. MySQL 用 limit 为什么会影响性能? (qq.com)
  2. SQL语句中 left join 后用 on 还是 where,区别大了! (qq.com)
  3. SQL查找是否"存在",别再 count 了! (qq.com)
  4. 这个 MySQL bug 99% 的人会踩坑! (qq.com)
  5. 一款SQL检查审核神器!再也不担心写SQL出问题了 (qq.com)
  6. MySQL SHOW命令使用详解
  7. SQL中merge的用法
  8. MySQL load data 快速导入大批量数据
  9. MySQL的存储过程(call)
  10. mysql中flush命令_lss__51CTO博客
  11. 如果要存 IP 地址,用什么数据类型比较好?大部人都会答错! (qq.com)
  12. 8种常见SQL错误用法 (qq.com)
  13. SQL 查询总是先执行SELECT语句吗?你们都错了! (qq.com)
  14. 为什么代码规范要求SQL语句不要过多的join? (qq.com)
  15. MySQL 时间类型 datetime、bigint、timestamp,选哪个? (qq.com)

2、MySQL概述

2.1 简介

  1. MySQL基本知识点梳理和查询优化 (qq.com)

2.2 安装

2.3 常用命令

  1. MySQL查看用户权限及权限管理

2.4 架构

  1. 深入理解MySQL底层架构,看这一篇文章就够了! (qq.com)
  2. mysql 的一行记录是怎么存储的? (qq.com)
  3. 9 张图总结一下 MySQL 架构 (qq.com)
  4. 什么是数据库的 “缓存池” ?(万字干货) (qq.com)
  5. 一文讲清,MySQL的表空间 (qq.com)

2.5 建表规范

  1. MySQL中,21个写SQL的好习惯! (qq.com)
  2. 某大佬整理的MySQL数据库设计规范,值得收藏! (qq.com)
  3. 为什么MySQL不推荐使用uuid或者雪花id作为主键? (qq.com)
  4. 不要再使用uuid作为MySQL的主键了!!! (qq.com)

3、MySQL索引

3.1 索引类型

  1. MySQL索引连环18问! (qq.com)
  2. 一文讲清,MySQL中的二级索引 (qq.com)
  3. 一文讲清,MySQL中的主键索引 (qq.com)

3.2 索引使用

  1. 十万个为什么,精通MySQL索引 (qq.com)
  2. 妈妈再也不用担心我不会MySQL索引了 (qq.com)
  3. 别再一知半解啦!索引其实就这么回事! (qq.com)
  4. 24个经典的MySQL索引问题,你都遇到过哪些? (qq.com)
  5. 索引的使用规则和设计考虑 (qq.com)

3.3 数据结构

  1. 这就是你要的 B+ 树? (qq.com)

3.4 最左前缀原则

4、MySQL事务

4.1 四种特性

4.2 事务隔离级别

  1. 一文讲清,MySQL事务隔离级别 (qq.com)

4.3 事务实现原理

  1. 阿里二面:了解 MySQL 事务底层原理吗 (qq.com)
  2. 你说熟悉MySQL事务,那来谈谈事务的实现原理吧! (qq.com)

4.4 事务执行流程

4.5 事务使用注意事项

4.6 MVCC

  1. 一文讲清,MySQL如何解决多事务并发问题 (qq.com)
  2. 看一遍就理解:MVCC原理详解 (qq.com)
  3. 相见恨晚,MVCC 这么理解,早就通关了 (qq.com)
  4. 面试官问:Mysql的数据多版本并发控制如何实现?图解 MVCC… (qq.com)

5、MySQL集群

5.1 概述

5.2 集群方案

6、MySQL分库分表

6.1 概述

  1. 有关分库分表你想知道的,都在这儿了 (qq.com)
  2. 分库分表的 9种分布式主键ID 生成方案,挺全乎的 (qq.com)
  3. MySQL 跨库分页、分表分页之后,面临的一些新问题 (qq.com)

6.2 水平拆分

6.3 垂直拆分

6.4 数据库中间件

  1. 国产最强开源分库分表,没有之一,不接受任何反驳! (qq.com)

7、MySQL数据库中间件

7.1 Sharding-JDBC

  1. 一文快速入门分库分表中间件 Sharding-JDBC (必修课) (qq.com)
  2. Sharding-Jdbc实现读写分离、分库分表 (qq.com)
  3. 实战:Springboot 集成 Sharding-JDBC + Mybatis-Plus 实现分库分表(附源码) (qq.com)

7.2 MyCat

  1. Spring Boot 实现读写分离,还有谁不会??

8、MySQL性能优化

8.1 慢查询分析

  1. 一次 SQL 查询优化原理分析 (qq.com)
  2. 我真在看慢SQL了,DBA哥哥 (qq.com)
  3. 干货!!!35 张图带你 MySQL 调优 (qq.com)
  4. 深入理解部分 SQL 语句执行慢的原因 (qq.com)
  5. 面试官:如果MySQL引起CPU消耗过大,你会怎么优化? (qq.com)
  6. 深入理解为什么MySQL全表扫描很慢? (qq.com)
  7. 一文讲清,MySQL的执行计划 (qq.com)

8.2 优化索引

  1. 一张900w的数据表,16s执行的SQL优化到300ms? (qq.com)
  2. 一次 SQL 查询优化原理分析 (qq.com)
  3. 为什么我使用了索引,查询还是慢? (qq.com)
  4. 字节面试官:一条sql执行慢的原因?如何优化? (qq.com)
  5. 10个经典场景带你玩转SQL优化 (qq.com)
  6. 面试中被问到SQL优化,看这篇就对了! (qq.com)
  7. 实战!聊聊如何解决MySQL深分页问题! (qq.com)
  8. 男朋友连模糊匹配like %%怎么优化都不知道 (qq.com)
  9. 求求你别再用offset和limit分页了 (qq.com)
  10. 为什么大家都说 SELECT * 效率低 (qq.com)
  11. 阿里规定超过三张表禁止JOIN,为啥呢? (qq.com)

8.3 优化步骤

  1. DBA整理的万字详解MySQL性能优化,值得收藏! (qq.com)
  2. MySQL 性能优化的 9 种姿势,面试再也不怕了! (qq.com)

8.4 调优工具

  1. 4 款 MySQL 调优工具,公司大神都在用! (qq.com)

9、MySQL日志

9.1 二进制日志(binlog)

  1. 不会吧,不会吧,还有人不知道 binlog ? (qq.com)
  2. 短小精悍,MySQL日志15连问,看完直接通关了 (qq.com)

9.2 事务日志

  1. MySQL的redo log和binlog日志 (qq.com)
  2. 必须了解的 MySQL 三大日志 (qq.com)
  3. 剖析 MySQL的 undo log (qq.com)
  4. MySQL不会丢失数据的秘密,就藏在它的 7种日志里 (qq.com)

10、MySQL数据备份与恢复

10.1 数据备份

  1. MySQL定时备份数据库方案(全库备份) (qq.com)
  2. MySQL 定时备份数据库(非常全) (qq.com)
  3. Linux 下如何实现 MySQL 数据库每天自动备份定时备份 (qq.com)

10.2 数据恢复

11、缓存一致性

11.1 概述

  1. 数据库跟缓存的双写一致性 (qq.com)
  2. 数据库与缓存不一致问题:JPA实体状态 (qq.com)
  3. 面试官:你是怎么理解缓存的? (qq.com)
  4. 8 张图 | 剖析 Redis 与MySQL 一致性的爱恨情仇 (qq.com)
  5. Cache 工作原理,Cache 一致性,你想知道的都在这里 (qq.com)

11.2 解决方案

  1. 先更新数据库,再删缓存
  2. 4 种数据库缓存最终一致性的优缺点对比?最终选择方案四! (qq.com)
  3. 缓存和数据库一致性问题,看这篇就够了 (qq.com)

12、MySQL锁机制

12.1 分类

  1. mysql各种锁,一篇文章讲明白 (qq.com)
  2. 一文讲清,MySQL中的锁 (qq.com)
  3. 聊一聊数据库中的锁 (qq.com)
  4. 面试命中率90%的点 —— MySQL锁 (qq.com)
  5. 用 MySQL 实现分布式锁,你听过吗? (qq.com)

12.2 加锁规则

  1. MySQL死锁产生原因和解决方法 (qq.com)

12.3 SQL语句加锁分析

  1. 这 6 个MySQL死锁案例,让你彻底理解死锁的原因! (qq.com)

12.4 如何避免死锁

  1. 面试官:怎么解决MySQL中的死锁问题? (qq.com)
  2. 大厂怎么解决MySQL死锁问题?差点被坑到享年 (qq.com)

13、ORM框架

13.1 MyBatis

  1. MyBatis 速成手册 (qq.com)
  2. 强大:MyBatis 流式查询 (qq.com)
  3. Mybatis 框架下 SQL 注入攻击的 3 种方式,真是防不胜防! (qq.com)
  4. MyBatis 架构与原理 (qq.com)
  5. Mybatis 面试 18 问,你想知道的都在这里了! (qq.com)
  6. 10 个 最火的 MyBatis 开源项目 (qq.com)
  7. MyBatis 的执行流程,写得太好了!
  8. MyBatis 批量插入数据的 3 种方法! (qq.com)
  9. MyBatis原生批量插入的坑与解决方案! (qq.com)
  10. MyBatis动态SQL(认真看看, 以后写SQL就爽多了) (qq.com)
  11. MyBatis千万级数据查询解决方案,避免OOM (qq.com)
  12. Mybatis 使用的 9 种设计模式,真是太有用了 (qq.com)
  13. Spring Boot + MyBatis + MySQL读写分离 (qq.com)
  14. 手把手教你开发 MyBatis 插件 (qq.com)

13.2 MyBatis-Plus

  1. 熟练掌握 MyBatis-Plus,这一篇就够了! (qq.com)
  2. Mybatis-plus常用API全套教程,看完没有不懂的 (qq.com)

13.3 JDBCTemplate

  1. 放弃MyBatis!我选择 JDBCTemplate! (qq.com)
  2. Spring JdbcTemplate使用_浅然的专栏-CSDN博客
  3. Spring JDBC配置与使用_木夆的博客-CSDN博客

13.4 Fluent MyBatis

  1. Fluent Mybatis 牛逼! (qq.com)
  2. 取代MybatisPlus?阿里推出了新 ORM 框架!(两者对比参考) (qq.com)

14、其他

  1. show status命令参数说明
  2. 不藏了,我的一千行 MySQL 学习笔记(2万字长文) (qq.com)
  3. MySql批量插入时,如何不插入重复的数据 (qq.com)
  4. 在MySQL数据库中,这4种方式可以避免重复的插入数据! (qq.com)
  5. 生产环境MySQL,应该选什么样配置的机器? (qq.com)
  6. 1 W 字+ | 硬刚 MySQL(典藏版) (qq.com)
  7. 面试必备:MySQL知识点总结 (qq.com)
  8. 数据库版本管理,已经从困难变容易 (qq.com)
  9. MySQL 高频 100 问 (qq.com)
  10. MySQL 8.0 可以操作 JSON 了,牛逼! (qq.com)
  11. 快问快答,MySQL面试夺命20问 (qq.com)
  12. 实现数据“一键脱敏”,Sharding Sphere帮你搞定 (qq.com)
  13. 一款SQL检查审核神器!再也不担心写SQL出问题了 (qq.com)
  14. Mysql 连环20问 (qq.com)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值