Mysql数据库

MySQL 是一个开源的关系型数据库管理系统(RDBMS),使用结构化查询语言(SQL)进行数据库的增删查改等操作,广泛应用于 Web、数据仓库、日志系统等场景

一、MySQL 基础

1 、安装 MySQL(以 CentOS 7 为例)

# 安装 MySQL 官方 Yum 仓库
yum -y install wget
wget https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
sudo rpm -ivh mysql80-community-release-el7-1.noarch.rpm

# 安装 MySQL 服务
sudo yum install mysql-server -y

# 启动并设置开机自启
sudo systemctl start mysqld
sudo systemctl enable mysqld

2、MySQL tar.gz 安装步骤

cd /usr/local/src
wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.34-linux-glibc2.28-x86_64.tar.xz

# 解压到 /usr/local 目录
tar -xf mysql-8.0.34-linux-glibc2.28-x86_64.tar.xz -C /usr/local

# 重命名目录方便使用
cd /usr/local
mv mysql-8.0.34-linux-glibc2.28-x86_64 mysql  

创建 mysql 用户和数据目录

# 创建用户
groupadd mysql
useradd -r -g mysql -s /sbin/nologin mysql

# 创建数据目录
mkdir -p /data/mysql
chown -R mysql:mysql /data/mysql

初始化数据库

cd /usr/local/mysql

# 初始化并指定数据目录
bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql

# 会生成临时 root 密码,记下它!
# eg: A temporary password is generated for root@localhost: Abc!defg123

配置环境变量

echo 'export PATH=/usr/local/mysql/bin:$PATH' >> /etc/profile
source /etc/profile

创建配置文件 /etc/my.cnf

cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/usr/local/mysql
datadir=/data/mysql
port=3306
socket=/tmp/mysql.sock
pid-file=/data/mysql/mysqld.pid
user=mysql
symbolic-links=0
log-error=/var/log/mysqld.log

[client]
socket=/tmp/mysql.sock
EOF

启动 MySQL

# 拷贝启动脚本
cp support-files/mysql.server /etc/init.d/mysql

# 启动 MySQL
/etc/init.d/mysql start

登录并修改 root 密码

# 登录(使用初始化时生成的临时密码)
mysql -u root -p

# 修改密码
ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPass123!';
目录作用
/usr/local/mysqlMySQL 程序安装目录
/data/mysql数据库存储目录
/etc/my.cnf配置文件
/tmp/mysql.sock套接字文件
/var/log/mysqld.log错误日志
ps -ef | grep mysqld
netstat -tunlp | grep 3306

3、编写mysql的systemctl启动文件(包安装)

vim /etc/systemd/system/mysqld.service
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target
[Install]
WantedBy=multi-user.target
[Service]
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf  #注意路径
LimitNOFILE=5000 

systemctl daemon-reload

二、数据类型

-  整数类型:
-  tinyint(m)   1个字节 范围(-128~127)
-  int(m)        4个字节 范围(-2147483648~2147483647)
-  bigint(m)    8个字节 范围(+-9.22*10的18次方)

-  浮点类型:
-  float(m,d)   单精度浮点型 8位精度(4字节) m总个数,d小数位

-  字符串类型:
-  char(n)    固定长度,最多255个字符
-  varchar(n)    固定长度,最多65535个字符
-  longtext    可变长度,最多2的32次方-1个字符  存储评论信息

三、属性约束

约束:

PK(primary key) 表示主键约束,非空且唯一(表中只能有一个主键)

UK(unique key) 表示唯一约束

NN(not null) 表示非空约束

FK(foreign key) 表示外键约束,多表之间关联使用 约束能力 

属性:(辅助表信息录入)

default 设定默认数据信息,可以实现自动填充

auto_increment 设定数值信息自增,可以实现数值编号自增填充(一般配合主键使用) comment 设定数据注释信息

unsigned 设定数值信息非负,可以实现数值信息列不能出现负数信息

补充知识:数据库外键约束说明--FK

外键也称之为外键约束: foreign key

外键: 外面的键, 一张表的一个字段(非主键)指向另外一个表的主键, 那么该字段就称之为外键.</u> 外键所在的表称之为子表(附表); 外键所指向的主键所在的表称之为父表(主表)

1、外键设置

#添加外键:方式一

   foreign key(外键字段) references 主表(主键);
   实际操作:
   # 创建外键关联的父表
   create table class(
   id int primary key auto_increment,
   name varchar(10) not null comment "班级名字,不能为空",
   room varchar(10) comment '教室:允许为空'
   ) charset utf8;
   
   # 创建子表使用外键
   create table student(
   id int primary key auto_increment,
   number char(10) not null unique comment "学号:不能重复",
   name varchar(10) not null comment "姓名",
   c_id int,
   foreign key(c_id) references class(id) 
   ) charset utf8;
   -- 增加外键:c_id是外键字段,class是引用表(父表),id是引用字段(主键)

 #添加外键:方式二
   alter table 表名 add constraint 外键名 foreign key(外键字段) references 父表(主键字段)
   实际操作:
   create table t_foreign(
   id int primary key auto_increment,
   c_id int
   )charset utf8;
   
   alter table t_foreign add constraint class_foreign foreign key(c_id) references class(id);

1.1、删除外键

# 删除外键语法格式
alter table 表名 drop foreign key 外键名;
# 删除表(t_foreign)中外键信息
alter table t_foreign drop foreign key class_foreign;

1.2、查看外键

desc t_foreign;
show create table t_foreign;

四、数据库操作

1 、创建/查看/删除数据库

-- 创建数据库
CREATE DATABASE testdb;

-- 查看所有数据库
SHOW DATABASES;

-- 使用数据库
USE testdb;

-- 删除数据库
DROP DATABASE testdb;


 #创建新的数据库,并修改调整默认的字符编码
   mysql > create database oldboy character set utf8mb4;
   mysql > create database oldboy charset utf8 collate utf8_general_mysql500_ci;
  

 #修改数据库服务字符集编码信息与字符编码排序规则信息
   mysql > alter database test charset utf8mb4;
   mysql > alter database test charset utf8 collate utf8_general_mysql500_ci;

2、表操作

完整建表语句参考:

CREATE TABLE `student` (
  `id` int NOT NULL COMMENT '学号信息',
  `name` varchar(45) NOT NULL COMMENT '学生名',
  `age` tinyint unsigned NOT NULL COMMENT '学生年龄',
  `gender` enum('M','F','N') NOT NULL DEFAULT 'N' COMMENT '学生性别',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='学生表'

创建一个学生信息表:

# 切换数据库环境
mysql > use xiaoq;
mysql > select database();
-- 查看是否切换数据库成功

# 创建数据表信息
mysql > create table stu1(
id int(10) not null,
name varchar(20) not null,
age tinyint(2)  NOT NULL default '0',
dept varchar(16)  default NULL
);

# 查看数据表信息
mysql > show tables;
mysql > desc stu1;
-- 查看所有表
SHOW TABLES;

-- 查看表结构
DESCRIBE users;

-- 删除表
DROP TABLE users;

2.1修改表 alter

 # 修改表名称(审计工作)
   mysql> rename table stu1 to stu2;
   mysql> alter table stu2 rename stu1;

 # 修改表字符编码
   mysql> alter table stu1 charset utf8mb4;

 # 修改数据表结构信息具体实际操作过程(添加新的表结构字段)
   mysql > alter table stu1 add column telno char(11) not null unique key comment '手机号';
   -- 在学生表中,添加新的表结构字段列(追加字段列-单列操作)

   mysql > alter table stu1 add column wechat varchar(64) not null unique key comment '微信号' after age;
   -- 在学生表中,添加新的表结构字段列(插入字段列-单列操作)

   mysql > alter table stu1 add column sid int not null unique key comment '微信号' first;
   -- 在学生表中,添加新的表结构字段列(插入首行列-单列操作)

   mysql > desc stu1;
   -- 查看表结构字段信息变化

  # 具体实际操作过程(删除已有表结构字段)

   mysql > alter table stu1 drop column sid;
   -- 在学生表中,删除已有表结构字段列(删除指定字段列-单列操作)

  
 # 具体实际操作过程(修改已有表结构字段)

   mysql > alter table stu1 modify name varchar(64);
   -- 在学生表中,修改已有表结构字段列(修改表结构数据类型)

   mysql > alter table stu1 modify name varchar(64) not null comment '学生名';
   -- 在学生表中,修改已有表结构字段列,最后带有保持原有配置的属性信息,否则其他属性信息会被还原为默认

   mysql > alter table stu1 change name stuname varchar(64) not null comment '学生名';
   或者
   mysql > alter table stu1 change column name stuname varchar(64) not null comment '学生名';
   -- 在学生表中,修改已有表结构字段列(修改表结构字段名称)

   mysql > alter table stu1 modify name varchar(64) not null unique comment '学生名称';
   -- 在学生表中,修改已有表结构字段列(修改表结构属性信息)了解即可

   mysql > alter table stu1 drop index `name`;
   -- 在学生表中,修改已有表结构字段列(删除表结构属性信息)了解即可

   mysql > desc stu1;
   -- 查看表结构字段信息变化

2.2删除表 drop

 # 数据表删除命令语法
   mysql > drop table <表名>;
   # 具体实际操作过程
   mysql > drop table stu1;
   -- 删除操作过程,会将定义的表结构和表中数据内容一并删除
   
   mysql > truncate table stu1;
   -- 删除操作过程,只是清空表中数据内容,但保留定义的表结构信息
   
   mysql > delete from stu1;
   -- 删除操作过程,只是清空表中数据内容,但保留定义的表结构信息

2.3查询表desc

   desc stu1;
   -- 查看表结构(常用命令)
   
   show create table stu1;
   -- 查看表的创建命令

3.数据操作(DML)

CREATE TABLE `xiaop`.`stu1` (
   `id` INT NOT NULL AUTO_INCREMENT COMMENT '主键列',
   `name` VARCHAR(10) NOT NULL,
   `age` TINYINT UNSIGNED NOT NULL,
   `dept` ENUM('Linux', 'net', 'go') NOT NULL DEFAULT 'Linux',
   PRIMARY KEY (`id`));

3.1增-insert

 #语法:
   insert into <表名> [( <字段名1>[,..<字段名n > ])] values ( 值1 )[, ( 值n )];
   插入数据信息:

   # 具体实际操作过程
   mysql> desc stu1;
   mysql> insert into stu1(id,name,age,dept) values(1,'xiaop',35,'net sec');
   -- 插入单行信息标准方法(信息输入不要重复,且特定信息不要为空)

   mysql> insert into stu1(id,name,age,dept) values(0,'xiaop',35,'net sec');
   mysql> insert into stu1(id,name,age,dept) values(null,'xiaop',35,'net sec');
   -- 插入单行信息标准方法(自增列信息可以填入0或null,表示默认实现自增效果)

   mysql> insert into stu1 values(2,'oldgirl',25,'Linux');
   -- 插入单行信息可以不含有表字段信息

   mysql> insert into stu1 values(0,'littlegirl',2,'net'),(0,'littleboy',1,'Linux');
   -- 插入多行信息可以不含有表字段信息

   mysql> insert into stu1(name,age) values('xiaop',35);
   -- 插入当行信息可以只含部分字段信息,但是省略字段信息必须具有自增特性 或 可以为空 或有默认值输入

   mysql> insert into stu1 values(0,'小彭',32,'go,linux');
   -- 插入中文信息

   # 检查信息是否插入成功
   mysql> select * from stu1;

3.2修改-update

mysql> update 表名 set 字段=新值,… where 条件


# 具体实际操作过程
mysql> update stu1 set name="zhangsan" where id=6;
-- 修改表数据内容标准方式,修改时一定要加条件信息(条件信息建议为主键或具有唯一性信息)

# 检查信息是否修改成功
mysql> select * from stu1;

3.3删除-delete

# 数据表数据删除命令语法 
mysql> delete from 表名 where 表达式;

-- 属于表内容信息变更操作,需要按照表结构预先定义好的字段信息删除,并且按照条件删除,默认全表删除
# 具体实际操作过程

mysql> delete from stu1 where id=6;
mysql> delete from stu1 where id<3;
mysql> delete from stu1 where age=2 or age=1;
mysql> delete from stu1; 
-- 删除表信息时,如果不加条件会进行逐行删除全表信息(效率比较慢)

# 检查信息是否删除成功
mysql> select * from stu1;


# 真实删除数据信息操作举例
mysql> delete from stu1 where id=6;

# 伪删除数据信息操作举例
mysql> alter table stu1 add state tinyint not null default 1;
-- 在原有表中添加新的状态列

mysql> update stu1 set state=0 where id=6;
-- 将原本删除列信息的状态改为0,实现伪删除效果

mysql> select * from stu1 where state=1;
-- 实现查询时不要获取状态为0的信息,即不查看获取伪删除数据信息

3.4查-select

SELECT * FROM Students;                    --选择Students表中的所有数据
SELECT Name, Grade FROM Students;          --选择Students表中的Name和Grade数据

五、数据库索引

  1. 索引是数据库中用来提高数据读取性能(select update delete);

  2. 提高查询数据的性能,主要是减少多IO CPU 内存的消耗;

1、索引信息创建

#单列索引创建:
	主键索引: 
	ALTER TABLE 表名 ADD PRIMARY KEY (列名);
	
	辅助索引:
	alter table 表名 add index idx_name(列名);
	
	唯一索引:
	ALTER TABLE 表名 ADD UNIQUE (列名);
	
	前缀索引:
	alter table 表名 add index ix_n(列名(10));   
	
#多列索引创建
	alter table 表名 add index idx_na_po(列名01,列名02);
	
#索引信息查看:
	desc 表名;
	show index from 表名;
		
#索引信息删除:
# 删除索引信息
    alter table 表名 drop index 索引名;  
    -- 删除辅助索引
    
    alter table 表名 drop index 索引名;    
    -- 删除联合索引
    
    alter table 表名 drop index 列名;        
    -- 删除唯一索引
    
    alter table 表名 drop primary key; 
    -- 删除聚簇索引

2、效果检验

#数据库压力测试方法:
	一、没有索引情况:
	mysqlslap --defaults-file=/etc/my80.cnf --concurrency=100 --iterations=1 --create-schema='xiao' --query="select * from xiaop.t100w where k2='VWlm'" engine=innodb --number-of-queries=2000 -uroot -p123456 -h192.168.200.10 -verbose
	Running for engine rbose
	Average number of seconds to run all queries: 274.680 seconds
	Minimum number of seconds to run all queries: 274.680 seconds
	Maximum number of seconds to run all queries: 274.680 seconds
	Number of clients running queries: 100
	Average number of queries per client: 20

#二、设置索引情况:
	alter table xiaop.t100w add PRIMARY KEY (id);
	alter table xiaop.t100w add index idx_k2(k2);


mysqlslap --defaults-file=/etc/my80.cnf --concurrency=100 --iterations=1 --create-schema='xiao' --query="select * from xiaop.t100w where k2='VWlm'" engine=innodb --number-of-queries=2000 -uroot -p123456 -h192.168.200.10 -verbose

    mysqlslap: [Warning] Using a password on the command line interface can be insecure.
    Benchmark
	Running for engine rbose
	Average number of seconds to run all queries: 2.612 seconds
	Minimum number of seconds to run all queries: 2.612 seconds
	Maximum number of seconds to run all queries: 2.612 seconds
	Number of clients running queries: 100
	Average number of queries per client: 20

六、存储引擎

1、数据库存储引擎特性(Innodb)

###大部分场景下都会使用innodb存储引擎,是因为innodb存储引擎具有一定优秀特性:

01    数据访问特性    支持多版本并发控制特性(MVCC),支持行级锁控制并发
02    数据索引特性    支持聚簇索引/辅助索引特性,可以组织存储数据和优化查询(IOT)
03    数据事务特性    支持事务概念特性,可以实现数据的安全保证
04    数据缓冲特性    支持多缓冲区功能,自适应hash索引(AHI)
05    数据迁移特性    支持复制数据中的高级功能特性,支持数据备份恢复的热备
06    服务自愈特性    支持自动故障恢复(CR-Crash Recovery)
07    数据存储特性    支持数据双写机制(Double write) 数据存储有关的安全机制

2、存储引擎应用

#命令操作:
	存储引擎设置:
	永久修改默认存储引擎信息:
	vim /etc/my.cnf
    [mysqld]
    default_storage_engine=InnoDB
#存储引擎查看:
	show engines;    -- 查看数据库可以应用的存储引擎
	select @@default_storage_engine;   -- 查看默认存储引擎配置

2.1数据表存储引擎信息查看

# 查看建表语句获取存储引擎信息
mysql > show create table city;

# 查看information_schema数据库获取存储引擎信息
mysql > select table_schema,table_name,engine from information_schema.tables where table_schema not in('sys','mysql','information_schema','performance_schema')

2.2存储引擎配置修改

# 创建表时设置存储引擎
mysql > create table xxx (id int) engine=innodb charset=utf8mb4;

# 修改表示设置存储引擎
mysql > alter table world.xxx engine=myisam;
mysql > alter table world.xxx engine=innodb;

3、存储引擎结构

3.1类型一:共享(系统)表空间

扩容共享表空间操作:
扩容前共享表空间信息查看:

mysql> select @@innodb_data_file_path;
+-------------------------------------+
| @@innodb_data_file_path             |
+-------------------------------------+
| ibdata1:12M:autoextend              |
+-------------------------------------+
1 row in set (0.00 sec)
-- 可以在初始安装好数据库服务后,进行修改配置为两个ibdate文件,每个共享表空间文件占用2G,总共占用4个G空间


mysql> select @@innodb_autoextend_increment;
+---------------------------------------------+
| @@innodb_autoextend_increment               |
+---------------------------------------------+
|                          64                 |
+---------------------------------------------+
1 row in set (0.00 sec)
-- 查看参数信息说明:ibdata1文件,默认初始大小12M,不够用会自动扩展,默认每次扩展64M

共享表空间的扩容操作方法:

# 编写数据库配置文件信息
vim /etc/my.cnf
[mysqld]
innodb_data_file_path=ibdata1:12M;ibdata2:100M;ibdata3:100M:autoextend
-- 需要注意的是ibdata1文件大小必须和实际数据库要存储的数据相匹配,否则会出现如下报错信息

 [ERROR] [MY-012264] [InnoDB] The innodb_system data file './ibdata1' is of a different size 768 pages (rounded down to MB) than the 4864 pages specified in the .cnf file!
-- 表示ibdate1指定大小超过了原有ibdata1实际的大小尺寸
​
# 查看配置信息是否生效
mysql> select @@innodb_data_file_path;
+---------------------------------------------------------------------+
| @@innodb_data_file_path                                             |
+---------------------------------------------------------------------+
| ibdata1:12M;/data02/ibdata2:100M;/data03/ibdata3:100M:autoextend    |
+---------------------------------------------------------------------+
1 row in set (0.00 sec)

七、事务机制

1、特性一:原子性(Atomicity)

原子性:表示一个事务生命周期中的DML语句,要么全成功要么全失败,不可以出现中间状态;

语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;实现主要基于undo log

2、特性二:一致性(Consistency)

一致性:表示一个事务发生前、中、后,数据都最终保持一致,即都要保证一致性

事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障;

3、特性三:隔离性(Isolation)

隔离性:表示一个事务操作数据行的时候,不会受到其他事务的影响,主要利用锁机制来保证隔离性;

4、特性四:持久性(Durability)

持久性:表示一旦事务进行了提交,即可永久生效(落盘)

保证事务提交后不会因为宕机等原因导致数据丢失;实现主要基于redo log
可以在数据库服务异常时,将内存中未落盘的数据进行恢复

5、存储事务生命周期

begin  DML;DML;DML;DML commit   -- 完整生命周期 
begin  DML;DML;DML;DML rollback	-- 完整生命周期

#在运用事务机制完成相关工作任务时,对于事务使用是存在生命周期概念的,标准显示的事务生命周期控制语句有:
# 开启事务机制
begin;
start transaction;

# 提交事务任务
commit;

# 回滚事务操作
rollback;

事务生命周期中,只能使用DML语句,其中包括:select、update、delete、insert;DDL语句会隐式进行提交

5.1生命周期操作演示:

# 进行测试数据库查询数据
mysql> use world;
mysql> select * from city limit 10;

# 进行测试数据库数据撤销修改
mysql> begin;
mysql> update city set population=10 where id=1;
mysql> update city set population=10 where id=2;
-- 由于是采用事务进行的修改,所以只是在内存层面进行的修改,并没有对磁盘上的数据进行修改;

mysql> select * from city limit 10;
+----+----------------+-------------+---------------+------------+
| ID | Name           | CountryCode | District      | Population |
+----+----------------+-------------+---------------+------------+
|  1 | Kabul          | AFG         | Kabol         |         10 |
|  2 | Qandahar       | AFG         | Qandahar      |         10 |
|  3 | Herat          | AFG         | Herat         |     186800 |
|  4 | Mazar-e-Sharif | AFG         | Balkh         |     127800 |
|  5 | Amsterdam      | NLD         | Noord-Holland |     731200 |
|  6 | Rotterdam      | NLD         | Zuid-Holland  |     593321 |
|  7 | Haag           | NLD         | Zuid-Holland  |     440900 |
|  8 | Utrecht        | NLD         | Utrecht       |     234323 |
|  9 | Eindhoven      | NLD         | Noord-Brabant |     201843 |
| 10 | Tilburg        | NLD         | Noord-Brabant |     193238 |
+----+----------------+-------------+---------------+------------+
-- 由于是采用事务进行的修改,此时看到的数据信息只是内存层面的修改信息

mysql> rollback;
-- 由于是采用事务进行的撤销,会读取undo文件信息,将事务操作撤回到事务开始前的状态

mysql> select * from city limit 10;
-- 由于是采用事务进行的修改,当撤销操作执行完,看到数据信息还是原来的;
+----+----------------+-------------+---------------+------------+
| ID | Name           | CountryCode | District      | Population |
+----+----------------+-------------+---------------+------------+
|  1 | Kabul          | AFG         | Kabol         |    1780000 |
|  2 | Qandahar       | AFG         | Qandahar      |     237500 |
|  3 | Herat          | AFG         | Herat         |     186800 |
|  4 | Mazar-e-Sharif | AFG         | Balkh         |     127800 |
|  5 | Amsterdam      | NLD         | Noord-Holland |     731200 |
|  6 | Rotterdam      | NLD         | Zuid-Holland  |     593321 |
|  7 | Haag           | NLD         | Zuid-Holland  |     440900 |
|  8 | Utrecht        | NLD         | Utrecht       |     234323 |
|  9 | Eindhoven      | NLD         | Noord-Brabant |     201843 |
| 10 | Tilburg        | NLD         | Noord-Brabant |     193238 |
+----+----------------+-------------+---------------+------------+

# 进行测试数据库数据永久修改
mysql> begin;
mysql> update city set population=10 where id=1;
mysql> update city set population=10 where id=2;
-- 由于是采用事务进行的修改,所以只是在内存层面进行的修改,并没有对磁盘上的数据进行修改;

mysql> select * from city limit 10;
+----+----------------+-------------+---------------+------------+
| ID | Name           | CountryCode | District      | Population |
+----+----------------+-------------+---------------+------------+
|  1 | Kabul          | AFG         | Kabol         |         10 |
|  2 | Qandahar       | AFG         | Qandahar      |         10 |
|  3 | Herat          | AFG         | Herat         |     186800 |
|  4 | Mazar-e-Sharif | AFG         | Balkh         |     127800 |
|  5 | Amsterdam      | NLD         | Noord-Holland |     731200 |
|  6 | Rotterdam      | NLD         | Zuid-Holland  |     593321 |
|  7 | Haag           | NLD         | Zuid-Holland  |     440900 |
|  8 | Utrecht        | NLD         | Utrecht       |     234323 |
|  9 | Eindhoven      | NLD         | Noord-Brabant |     201843 |
| 10 | Tilburg        | NLD         | Noord-Brabant |     193238 |
+----+----------------+-------------+---------------+------------+

-- 由于是采用事务进行的修改,此时看到的数据信息只是内存层面的修改信息

mysql> commit;
-- 由于是采用事务进行的提交,会加载redo文件信息,将事务内存层面的修改同步到磁盘中(完成了D特性)

mysql> select * from city limit 10;
+----+----------------+-------------+---------------+------------+
| ID | Name           | CountryCode | District      | Population |
+----+----------------+-------------+---------------+------------+
|  1 | Kabul          | AFG         | Kabol         |         10 |
|  2 | Qandahar       | AFG         | Qandahar      |         10 |
|  3 | Herat          | AFG         | Herat         |     186800 |
|  4 | Mazar-e-Sharif | AFG         | Balkh         |     127800 |
|  5 | Amsterdam      | NLD         | Noord-Holland |     731200 |
|  6 | Rotterdam      | NLD         | Zuid-Holland  |     593321 |
|  7 | Haag           | NLD         | Zuid-Holland  |     440900 |
|  8 | Utrecht        | NLD         | Utrecht       |     234323 |
|  9 | Eindhoven      | NLD         | Noord-Brabant |     201843 |
| 10 | Tilburg        | NLD         | Noord-Brabant |     193238 |
+----+----------------+-------------+---------------+------------+

-- 由于是采用事务进行的修改,当执行操作执行完,看到数据信息将永久保存下载;

5.2存储事务提交方式

方式一 :

在事务生命周期管理过程中,事务的提交机制可以采用自动提交方式(auto_commit)

---事务自动提交方式作用说明:

事务自动提交表示在没有显示的使用begin语句的时候,执行DML操作语句时,会在DML操作语句前自动添加begin;

并在DML操作语句执行后自动添加commit;

在生产环境中,若处于频繁事务业务场景中,建议关闭autocommit自动提交功能,或者每次事务执行的时候;

都进行显示的执行begin和commit

--事务自动提交方式参数信息:

mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            1 |
+--------------+
-- 在事务自动提交功能设置修改时,设置为1表示开启自动提交,设置为0表示关闭自动提交

--事务自动提交方式参数修改:

# 临时关闭事务自动提交功能
mysql> set global autocommit=0;
-- 配置调整后,重新登录mysql数据库生效

# 永久关闭事务自动提交功能
[root@xiaoQ-01 ~]# vim /etc/my.cnf
[mysqld]
autocommit=0
-- 配置调整后,重新启动mysql数据库生效
方式二 :

在事务生命周期管理过程中,事务的提交机制可以采用隐式提交方式:

在进行事务操作时,需要注意操作语句必须都是DML语句,如果中间插入了DDL语句,也会造成之前的事务操作自动提交;

begin; DML1; DML2; DDL1; COMMIT; DML3; COMMIT;
-- 这种情况出现会破坏原本事务的原子性
序号语句类型涉及命令
01DDL语句类型alter、create、drop
02DCL语句类型grant、revoke、set password
03锁定语句类型lock tables、unlock tables
04其他语句类型truncate table、load data infile、select for update

6、事务隔离级别类型:

类型一:RU(READ-UNCOMMITTED 表示读未提交)

可以读取到事务未提交的数据,隔离性差,会出现脏读(当前内存读),不可重复读,幻读问题;

类型二:RC(READ-COMMITTED 表示读已提交)可用

可以读取到事务已提交的数据,隔离性一般,不会出现脏读问题,但是会出现不可重复读,幻读问题;

类型三:RR(REPEATABLE-READ 表示可重复读)默认

可以防止脏读(当前内存读),防止不可重复读问题,防止会出现的幻读问题,但是并发能力较差;

会使用next lock锁进制,来防止幻读问题,但是引入锁进制后,锁的代价会比较高,比较耗费CPU资源,占用系统性能;

类型四:SR(SERIALIZABLE 可串行化)

隔离性比较高,可以实现串行化读取数据,但是事务的并发度就没有了;

这是事务的最高级别,在每条读的数据上,加上锁,使之不可能相互冲

2、脏读

脏读主要表示在一个事务窗口中,没有数据修改提交操作前,另一个事务就可以看到内存中数据页的修改;

简单理解:在一个事务窗口中,可以读取到别人没有提交的数据信息;

利用隔离级别RU解读:

# 设置事务隔离级别
mysql> set global transaction_isolation='READ-UNCOMMITTED';
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED        |
+-------------------------+
-- 重新开启两个SQL会话窗口

# 数据库A会话窗口操作
mysql> begin;
mysql> update t1 set a=10 where id=1;
-- 只是在内存层面进行数据页中数据修改

mysql> rollback;
-- 进行事务回滚操作

# 数据库B会话窗口操作
mysql> begin;
mysql> select * from t1 where id=1;
+----+----+---+----+
| id | a | b  | c |
+----+----+---+----+
|  1 | 10 | a | aa|
+----+----+---+----+
1 row in set (0.01 sec)
-- 在A会话窗口没提交的事务修改,被B会话窗口查询到了

mysql> select * from t1 where id=1;
+----+----+---+----+
| id | a  | b | c  |
+----+----+---+----+
|  1 | 5  | a | aa |
+----+----+---+----+
1 row in set (0.01 sec)
-- 在A会话窗口进行回滚后,在B窗口查询的数据又恢复了

3、不可重复读

不可重复读表示在一个事务中,利用相同的语句多次查询,获取的数据信息是不同的;

利用隔离级别RU解读:

# 数据库B会话窗口操作
mysql> begin;
mysql> select * from t1 where id=1;
+----+----+---+----+
| id | a  | b | c  |
+----+----+---+----+
|  1 | 10 | a | aa|
+----+----+---+----+
1 row in set (0.01 sec)
-- 在B会话事务窗口进行数据第一次查询看到数据信息:a=10
mysql> select * from t1 where id=1;
+----+----+---+----+
| id | a  | b | c  |
+----+----+---+----+
|  1 | 5  | a | aa |
+----+----+---+----+
1 row in set (0.01 sec)
-- 在B会话事务窗口进行数据第二次查询看到数据信息:a=5

利用隔离级别RC解读

# 设置事务隔离级别
mysql> set global transaction_isolation='READ-COMMITTED';
mysql> select @@transaction_isolation;
+---------------------------------+
| @@transaction_isolation |
+---------------------------------+
| READ-COMMITTED              |
+---------------------------------+
mysql> set global autocommit=0;
mysql> select @@autocommit;
-- 重新开启两个SQL会话窗口

# 数据库A会话窗口操作
mysql> use xiaop;
mysql> begin;
mysql> select * from t1 where id=1;
+----+---+---+----+
| id   | a  | b  | c  |
+----+---+---+----+
|  1   | 5  | a  | aa |
+----+---+---+----+
1 row in set (0.00 sec)
-- A窗口事务查询信息 = B窗口事务查询信息

mysql> update t1 set a=10 where id=1;
-- A窗口事务进行修改

mysql> commit;
-- A窗口事务进行提交

# 数据库B会话窗口操作
mysql> use xiaop;
mysql> begin;
mysql> select * from t1 where id=1;
+----+---+---+----+
| id   | a  | b  | c  |
+----+---+---+----+
|  1   | 5  | a  | aa |
+----+---+---+----+
1 row in set (0.00 sec)
-- A窗口事务查询信息 = B窗口事务查询信息

mysql> select * from t1 where id=1;
+----+---+---+----+
| id   | a  | b  | c  |
+----+---+---+----+
|  1   | 5  | a  | aa |
+----+---+---+----+
1 row in set (0.00 sec)
-- B窗口事务查询信息,不能看到A窗口事务未提交的数据变化,避免了脏数据问题;

mysql> select * from t1 where id=1;
+----+---+---+----+
| id   | a  | b  | c  |
+----+---+---+----+
|  1   | 10 | a  | aa |
+----+---+---+----+
1 row in set (0.00 sec)
-- A窗口事务提交之后,B窗口事务查询信息和之前不同了

利用隔离级别RR解读:

# 设置事务隔离级别
mysql> set global transaction_isolation='REPEATABLE-READ';
mysql> select @@transaction_isolation;
+---------------------------------+
| @@transaction_isolation |
+---------------------------------+
| REPEATABLE-READ              |
+---------------------------------+
mysql> set global autocommit=0;
mysql> select @@autocommit;
-- 重新开启两个SQL会话窗口
​
# 数据库A会话窗口操作
mysql> use xiaop;
mysql> begin;
mysql> select * from t1;
-- 确认初始数据信息
mysql> update t1 set a=10 where id=1;
-- A窗口事务进行修改
mysql> commit;
-- A窗口事务进行提交
​
# 数据库B会话窗口操作
mysql> use xiaop;
mysql> begin;
mysql> select * from t1;
-- 确认初始数据信息

mysql> select * from t1 where id=1;
+----+---+---+----+
| id   | a  | b  | c  |
+----+---+---+----+
|  1   | 5  | a  | aa |
+----+---+---+----+
1 row in set (0.00 sec)
-- B窗口事务查询信息,不能看到A窗口事务未提交的数据变化,避免了脏数据问题;

mysql> select * from t1 where id=1;
+----+---+---+----+
| id   | a  | b  | c  |
+----+---+---+----+
|  1   | 5  | a  | aa |
+----+---+---+----+
1 row in set (0.00 sec)
-- A窗口事务提交之后,B窗口事务查询信息和之前是相同的;
-- 在RR级别状态下,同一窗口的事务生命周期下,每次读取相同数据信息是一样,避免了不可重复读问题

mysql> commit;
mysql> select * from t1 where id=1;
-- 在RR级别状态下,同一窗口的事务生命周期结束后,看到的数据信息就是修改的了

4、幻读

利用隔离级别RC解读:

# 设置事务隔离级别
mysql> set global transaction_isolation='READ-COMMITTED';
mysql> select @@transaction_isolation;
+---------------------------------+
| @@transaction_isolation |
+---------------------------------+
| READ-COMMITTED              |
+---------------------------------+
mysql> set global autocommit=0;
mysql> select @@autocommit;
-- 重新开启两个SQL会话窗口

# 数据库A会话窗口操作(重新进入)
mysql> use xiaop;
mysql> select * from t1;
+----+----+---+-----+
| id | a  | b | c   |
+----+----+---+-----+
|  1 | 10 | a | aa  |
|  2 |  7 | c | ab  |
|  3 | 10 | d | ae  |
|  4 | 13 | g | ag  |
|  5 | 14 | h | at  |
|  6 | 16 | i | au  |
|  7 | 20 | j | av  |
|  8 | 22 | k | aw  |
|  9 | 25 | l | ax  |
| 10 | 27 | o | ay  |
| 11 | 31 | p | az  |
| 12 | 50 | x | aze |
| 13 | 60 | y | azb |
+----+----+---+-----+
13 rows in set (0.00 sec)
-- 查看获取A窗口表中数据

mysql> alter table t1 add index idx(a);
-- 在A窗口中,添加t1表的a列为索引信息

mysql> begin;
-- 在A窗口和B窗口中,同时做开始事务操作;

mysql> update t1 set a=20 where a<20;
-- 在A窗口中,将a<20的信息均调整为20

mysql> commit;
-- 在A窗口中,进行事务提交操作,是在B窗口事务没有提交前

mysql> mysql> select * from t1;
-- 在A窗口中,查看数据信息,希望看到的a是没有小于20的,但是结果看到了a存在等于10的(即出现了幻读)

# 数据库B会话窗口操作(重新进入)
mysql> use xiaop;
mysql> select * from t1;
+----+----+---+-----+
| id | a  | b | c   |
+----+----+---+-----+
|  1 | 10 | a | aa  |
|  2 |  7 | c | ab  |
|  3 | 10 | d | ae  |
|  4 | 13 | g | ag  |
|  5 | 14 | h | at  |
|  6 | 16 | i | au  |
|  7 | 20 | j | av  |
|  8 | 22 | k | aw  |
|  9 | 25 | l | ax  |
| 10 | 27 | o | ay  |
| 11 | 31 | p | az  |
| 12 | 50 | x | aze |
| 13 | 60 | y | azb |
+----+----+---+-----+
13 rows in set (0.00 sec)
-- 查看获取B窗口表中数据

mysql> begin;
mysql> insert into t1(a,b,c) values(10,'A','B')
-- 在B窗口中,插入一条新的数据信息 a=10 

mysql> commit;
-- 在B窗口中,进行事务提交操作

利用隔离级别RR解读:

# 设置事务隔离级别
mysql> set global transaction_isolation='REPEATABLE-READ';
mysql> select @@transaction_isolation;
+---------------------------------+
| @@transaction_isolation |
+---------------------------------+
| REPEATABLE-READ              |
+---------------------------------+
mysql> set global autocommit=0;
mysql> select @@autocommit;
-- 重新开启两个SQL会话窗口

# 数据库A会话窗口操作
mysql> use xiaop;
mysql> select * from t1;
-- 查看获取A窗口表中数据

mysql> alter table t1 add index idx(a);
-- 在A窗口中,添加t1表的a列为索引信息

mysql> begin;
mysql> update t1 set a=20 where a>20;
-- 在A窗口中,将a>20的信息均调整为20

# 数据库B会话窗口操作
mysql> use xiaop;
mysql> select * from t1;
-- 查看获取B窗口表中数据

mysql> begin;
mysql> insert into t1(a,b,c) values(30,'sss','bbb');
-- 在B窗口中,插入一条新的数据信息 a=30,但是语句执行时会被阻塞,没有反应;

mysql> show processlist;
-- 在C窗口中,查看数据库连接会话信息,insert语句在执行,等待语句超时(默认超时时间是50s)
-- 因为此时在RR机制下,创建了行级锁(阻塞修改)+间隙锁(阻塞区域间信息插入)=next lock
-- 区域间隙锁 < 左闭右开(可用临界值)  ;  区域间隙锁 > 左开右闭(不可用临界值)

5、隔离性与隔离级别

提到事务,肯定会想到 ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)

我们就来说说其中 I,也就是“隔离性”。

当数据库上有多个事务同时执行的时候,就可能出现以下问题:

  • 脏读(dirty read)

  • 不可重复读(non-repeatable read)

  • 幻读(phantom read)

为了解决这些问题,就有了“隔离级别”的概念。在谈隔离级别之前,首先要知道,隔离得越严实,效率就会越低。

因此很多时候,都要在二者之间寻找一个平衡点。SQL 标准的事务隔离级别包括:

隔离级别英文描述解释说明
读未提交RU-read uncommitted一个事务还没提交时,它做的变更就能被别的事务看到。
读提交RC-read committed一个事务提交之后,它做的变更才会被其他事务看到。
可重复读RR-repeatable read一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。 当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
串行化serializable顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。 当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

八、服务日志

在MySQL数据库服务中,有4种不同的日志是最常用的日志类型,这些日志记录这数据库在不同方面的踪迹;

mysql> show variables like '%log%';

1、常用日志信息介绍

序号日志名称解释说明
01general_log表示查询日志(通用日志),默认日志状态处于关闭,可以进行在线调整配置 作用:记录了客户端从会话连接开始,执行过的所有SQL语句信息;
02log_error表示错误日志(运行日志),默认日志状态处于激活 作用:记录了数据库服务启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息;
03log_bin表示二进制日志(binlog日志),默认日志状态处于激活(8.0之后) 作用:记录了所有的DDL语句和DML语句,但是不包括数据库查询语句;语句以事件的形式保存,描述了数据的更改过程,此日志对于灾难时的数据恢复起着极其重要的作用。
04slow_query_log表示慢查询日志,记录了所有执行时间超过参数long_query_time设置值并且扫描记录数小于min_examined_row_limit的所有SQL语句的日志。

2、服务日志信息配置

2.1通用日志(general_log)

general_log=OFF          
-- 默认日志功能处于关闭,建议在需要做调试工作时(功能测试、语句审计)可以打开;
general_log_file=/data/3306/data/xiaoQ-01.log  
-- 定义日志文件存储的路径信息,建议日志文件路径与数据存放路径进行分离;

# 修改日志默认状态(激活日志):
mysql > set global general_log=1;

2.2错误日志(log_error)

log_error=./xiaoQ-01.edu.err      
-- 定义日志文件存储的路径信息,建议日志文件路径与数据存放路径进行分离;

# 修改日志存储路径(永久配置):
[root@xiaoq ~]# vim /etc/my.cnf
log_error=/tmp/mysql3306.err
-- 配置文件编写完毕后,需要重启数据库服务生效

# 模拟故障日志应用
[root@db02 ~]#  ll /data/3306/data/ibdata1 
-rw-r-----. 1 mysql mysql 12582912 Apr 21 14:19 /data/3306/data/ibdata1
[root@db02 ~]# chmod 000 /data/3306/data/ibdata1 
[root@db02 ~]# /etc/init.d/mysqld restart
Shutting down MySQL... SUCCESS! 
Starting MySQL. ERROR! The server quit without updating PID file (/data/3306/data/db02.pid).

#查看错误日志
[root@db02 data]#tail -20 /data/3306/data/db02.err
2025-04-21T06:35:53.637782Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2025-04-21T06:35:53.638022Z 1 [ERROR] [MY-012271] [InnoDB] The innodb_system data file 'ibdata1' must be writable
2025-04-21T06:35:53.638131Z 1 [ERROR] [MY-012278] [InnoDB] The innodb_system data file 'ibdata1' must be writable
2025-04-21T06:35:53.638241Z 1 [ERROR] [MY-010334] [Server] Failed to initialize DD Storage Engine
2025-04-21T06:35:53.638584Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed.
2025-04-21T06:35:53.638829Z 0 [ERROR] [MY-010119] [Server] Aborting
2025-04-21T06:35:53.640117Z 0 [System] [MY-010910] [Server] /usr/local/mysql/bin/mysqld: Shutdown complete (mysqld 8.0.26)  MySQL Community Server - GPL
-- 根据错误日志的错误提示信息,进行错误信息进行分析,从而排查故障可能出现的原因;

2.3二进制日志(log_bin)

在进行增量恢复数据时,需要先了解什么是binlog日志,此日志文件其实就是用于记录对数据库进行操作更改的语句信息的;

并且记录更改的语句信息以事件形式进行记录,但是需要注意的是查询相关的语句是不会被记录的,比如:select、show;

然而作为所有对数据库的改操作事件信息都会被记录,比如:insert、update、create、drop。。。

2.3.1查看数据库binlog日志配置参数
mysql> show variables like '%log_bin%';
Connection id:    8
Current database: xiaop
+---------------------------------+------------------------------+
| Variable_name                   | Value                        |
+---------------------------------+------------------------------+
| log_bin                         | ON                           |
| log_bin_basename                | /data/3306/data/binlog       |
| log_bin_index                   | /data/3306/data/binlog.index |
| log_bin_trust_function_creators | OFF                          |
| log_bin_use_v1_row_events       | OFF                          |
| sql_log_bin                     | ON                           |
+---------------------------------+------------------------------+
6 rows in set (0.00 sec)
--- 通过以上输出信息可以看到log_bin为ON状态,表示binlog日志功能开启

# 已开启binlog日志功能后,查看系统binlog功能配置参数状态
mysql> show variables like '%log_bin%';
+-----------------------------------------+-------+
| Variable_name                           | Value |
+-----------------------------------------+-------+
| log_bin                                 | ON    |
| sql_log_bin                             | ON    |
+-----------------------------------------+-------+
3 rows in set (0.00 sec)
--- 通过以上输出信息可以看到log_bin为on状态,表示binlog日志功能已经开启
日志信息基本配置
server_id=6
-- 进行主从操作时,需要进行此信息配置;
log_bin=ON      
-- 默认日志功能处于关闭状态
log_bin_basename=/data/3306/data/binlog        
-- 定义日志文件存储的路径信息,建议日志文件路径与数据存放路径进行分离;

# 配置信息简写方式:开启数据库binlog日志记录功能
[root@xiaoq ~]# vim /etc/my.cnf
-- 激活binlog日志记录功能,需要对数据库服务配置文件进行编辑修改
[mysqld]
server_id=6
log_bin=/data/3306/binlog/mysql-bin
-- 进行binlog日志目录路径信息修改时,需要创建指定的目录并设置权限信息,最后需要重新启动数据库服务生效;
chown -R mysql:mysql /data/3306/binlog/mysql-bin/

或者
log_bin=binlog
-- 只是设置日志名称信息,日志会自动保存到数据库服务指定的数据目录中;

# 配置文件修改后需要重启数据库服务,加载配置文件改动的信息:
[root@xiaoQ ~]# /etc/init.d/mysqld restart 
[root@xiaoQ xiaoQ]# ll -h /data/3306/data/binlog*
-rw-rw----. 1 mysql mysql 245 6月  24 02:19 /data/3306/data/binlog.00000N
-rw-rw----. 1 mysql mysql   16 6月  24 02:19 /data/3306/data/binlog.index
-- 数据库服务重启后,已经可以在数据库的数据存储目录中,看到binlog日志文件的踪影
2.3.2日志信息查看方法:

可以通过查看方式,获取binlog日志里的数据信息,一般在数据库启动时,日志记录功能就开启了;

可以利用日志中记录信息,将数据库服务的数据信息恢复到指定的时间点,同时也可以支持主从数据复制(在其它机器上回放日志);

查看方式一:确认数据库binlog日志数量

mysql> show binary logs;
+------------------+-------------+--------------+
| Log_name         | File_size   | Encrypted    |
+------------------+-------------+--------------+
| binlog.000001    |     156     | No           |
+------------------+-------------+--------------+
-- 获取数据库服务运行过程中,使用的binlog日志的情况

mysql> flush logs;
Query OK, 0 rows affected (0.12 sec)
-- 可以执行flush刷新命令,从而生成新的binlog日志文件,类似于实现了日志切割功能;

mysql> show binary logs;
+------------------+-------------+--------------+
| Log_name         | File_size   | Encrypted    |
+------------------+-------------+--------------+
| binlog.000001    |        200  | No           |
| binlog.000002    |         156 | No           |
+------------------+-------------+--------------+
2 rows in set (0.00 sec)

查看方式二:确认数据库binlog日志状态

mysql> create database test_binlog;
Query OK, 1 row affected (0.03 sec)
-- 模拟数据服务有修改操作

mysql> select * from world.city limit 1;
Query OK, 1 row affected (0.03 sec)
-- 模拟数据服务有修改操作

mysql> show binary logs;
+------------------+-------------+--------------+
| Log_name         | File_size   | Encrypted    |
+------------------+-------------+--------------+
| binlog.000001    |      200    | No           |
| binlog.000002    |      362    | No           |
+------------------+-------------+--------------+
2 rows in set (0.00 sec)
-- 可以看到binlog日志的存储量发生了变化,但是在做查询操作时,binlog日志的存储量并未发生变化
​
mysql> show master status;
+------------------+------------+------------------+-----------------------+-------------------
| File             | Position   | Binlog_Do_DB     |  Binlog_Ignore_DB     | Executed_Gtid_Set 
+------------------+------------+------------------+-----------------------+-------------------
| binlog.000002    |     362    |                  |                       |                  |
+------------------+------------+------------------+-----------------------+-------------------
1 row in set (0.00 sec)
-- 查看获取当前使用的binlog日志情况,以及产生的日志量字节大小;

查看方式三:查看数据库binlog日志信息

mysql> show binlog events in 'binlog.000002';
-- binlog日志信息是以事件方式进行记录的,所以日志查看过程是查看事件信息
-- 一般binlog日志的前两行,表示日志格式头信息(日志简单的描述信息)
-- 一般binlog日志中的query信息,就是对数据库的操作语句,其中包含了创建数据库的语句;
列号列信息解释说明
01Log_name表示指定查看的binlog日志文件名称信息
02Pos表示binlog日志事件开始的位置点,用于截取二进制日志信息标识
05End_log_pos表示binlog日志事件结束的位置点,用于截取二进制日志信息标识
06Info表示binlog中具体的事件内容信息

查看方式四:筛选数据库binlog日志事件  

# 模拟生成binlog日志事件信息
mysql> source ~/world.sql;
mysql> drop database world;
mysql> source ~/world.sql;

# 获取删除数据库的事件信息:
# 筛选数据库日志方式一:
[root@xiaoq data]# mysql -e "show binlog events in 'binlog.000002'"|grep "drop database"
binlog.000002   722789  Query   1   722896  drop database world /* xid=5363 */
-- 获取指定事件信息产生的起点位置和终点位置信息;

# 筛选数据库日志方式二:
mysql> pager less
-- 在数据库中定义pager功能,数据库连接会话退出即失效;
mysql> show binlog events in 'binlog.000002';
-- 此时查看日志事件信息具有了翻页功能
/drop database
| binlog.000002 | 722789 | Query    |   1 |   722896 | drop database world /* xid=5363 */
mysql> pager grep "drop database"
PAGER set to 'grep "drop database"'
-- 表示开启数据库pager的过滤功能
mysql> show binlog events in 'binlog.000002';
| binlog.000002 |  722789 | Query    |     1 |   722896 | drop database world /* xid=5363 */ 
-- 再次查看binlog事件信息时,只过滤显示删除数据库的操作事件日志

2.3.3获取数据库binlog日志记录信息异常

进行数据库服务数据信息更改操作,随后查看binlog日志信息的变化:

# 进行数据库创建操作
mysql> create database xiaop;
mysql> show databases;

# 查看获取binlog日志记录信息
[root@xiaoQ ~]#mysqlbinlog /data/3306/binlog/mysql-bin.000001 
mysqlbinlog: unknown variable 'default-character-set=utf8mb4'
-- 由于在数据库在客户端配置文件中添加了default-character-set=utf8mb4字符编码信息,因此造成无法查看binlog

[root@xiaoQ ~]# cat /etc/my.cnf.d/client.cnf 
[client]
#default-character-set=utf8mb4
[client-mariadb]
#default-character-set=utf8mb4
-- 可以临时调整先将客户端的字符编码配置信息注释,

[root@xiaoQ ~]# mysqlbinlog /var/lib/mysql/binlog.000001
... 省略部分信息 ...
# at 494
#220624  2:35:02 server id 1  end_log_pos 579 Query thread_id=2 exec_time=0 error_code=0
SET TIMESTAMP=1656009302/*!*/;
create database xiaoQ
/*!*/;
... 省略部分信息 ...
-- 在binlog日志文件中,已经记录了之前的创建xiaoQ的更改操作记录信息

九、GTID概念介绍

GTID(global transation id)称为全局事务(事件)ID,标识binlog日志记录的唯一性;

1、server_uuid信息查看

mysql> select @@server_uuid
+--------------------------------------+
| @@server_uuid                        |
+--------------------------------------+
| e0147cef-0953-11f0-858f-000c2966eb77 |
+--------------------------------------+
1 row in set (0.00 sec)

-- 表示数据库每次初始化之后自动生成,不建议手工进行修改;

[root@db02 ~]# cat /data/3306/data/auto.cnf 
[auto]
server-uuid=e0147cef-0953-11f0-858f-000c2966eb77
-- 在数据库的数据目录文件中也可以查询到
  • GTID功能作用:

  • 利用GTID方式管理binlog,实质上就是对于数据库的每个事务产生事件信息打上唯一标识信息(id号);

    利用GTID方式管理binlog,主要目的是处理数据库主从问题,解决主从数据库的数据一致性问题;

    简单描述:标识事务的唯一性,保证日志恢复时的一致性,并且具备”幂等性”;

  • GTID功能配置:

    # GTID功能参数信息介绍(3个重要的配置参数)
    mysql> select @@gtid_mode;
    +-------------------+
    | @@gtid_mode       |
    +-------------------+
    | OFF               |
    +-------------------+
    1 row in set (0.00 sec)
    -- 设置是否开启显示gtid信息功能(在5.7之后是有个匿名的gtid,是数据库系统自己维护的)
    
    mysql> select @@enforce_gtid_consistency;
    +-------------------------------------+
    | @@enforce_gtid_consistency          |
    +-------------------------------------+
    | OFF                                 |
    +-------------------------------------+
    1 row in set (0.00 sec)
    -- 设置是否开启GTID强制一致性功能
    -- 对某些 SQL 会有限制,例如 CREATE TABLE … SELECT 必须得分成两条语句执行。
    -- OFF:    表示事务允许违反 GTID 一致性。
    -- ON:     表示事务不允许违反 GTID 一致性,有相关 SQL 会直接返回异常。
    -- WARN:表示事务允许违反 GTID 一致性,但会将警告信息记录到 ERROR LOG。
    
    mysql> select @@log_slave_updates;
    +----------------------------+
    | @@log_slave_updates        |
    +----------------------------+
    |                  1         |
    +----------------------------+
    1 row in set, 1 warning (0.01 sec)
    -- 和配置主从有关(在8.0.26开始 推荐配置log_replica_updates替代log_slave_updates参数)
    -- 此参数表示从服务器从主服务器接收的更新信息,是否也会记录在从服务器本地的二进制文件中

    GTID功能相关参数激活:

  • [root@xiaoq ~]# vim /etc/my.cnf
    [mysqld]
    gtid_mode=on
    enforce_gtid_consistency=1
    log_slave_updates=on
    -- 配置文件信息修改完毕后,重启数据库服务使配置生效

  • GTID信息查看:

    mysql> show master status;
    +------------------+-----------+-------------------+-----------------------+-------------------
    | File             | Position | Binlog_Do_DB       | Binlog_Ignore_DB      | Executed_Gtid_Set 
    +------------------+-----------+-------------------+-----------------------+-------------------
    | binlog.000004    |    156    |                   |                       |
    +------------------+-----------+-------------------+-----------------------+-------------------
    1 row in set (0.03 sec)
    -- 在GTID功能被激活后,就会在Executed_Gtid_Set列中显示GTID集合信息;
    
    mysql> create database test3;
    Query OK, 1 row affected (0.08 sec)
    -- 模拟创建数据库,产生新的事件信息
    mysql> show master status;
    +------------------+----------+--------------+------------------+------------------------------
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set     |
    +------------------+----------+--------------+------------------+------------------------------
    | binlog.000004    |      344 |              |                  | 7afe4f8c-5e36-11ed-b083-000c29d44f34:1 |
    +------------------+----------+--------------+------------------+------------------------------
    1 row in set (0.01 sec)
    -- GTID信息随着新的事件产生,随之发生变化
    mysql> create database test4;
    Query OK, 1 row affected (0.03 sec)
    -- 模拟创建数据库,产生新的事件信息
    mysql> show master status;
    +---------------+----------+--------------+------------------+---------------------------------
    | File          | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set              |
    +---------------+----------+--------------+------------------+---------------------------------
    | binlog.000004 |      532 |              |                  | 7afe4f8c-5e36-11ed-b083-000c29d44f34:1-2 |
    +---------------+----------+--------------+------------------+---------------------------------
    1 row in set (0.00 sec)
    -- GTID信息随着新的事件产生,随之发生变化
    
    mysql> SHOW BINLOG EVENTS IN 'mysql-bin.000002';
    +------------------+-----+----------------+-----------+-------------+--------------------------
    | Log_name         | Pos | Event_type     | Server_id | End_log_pos | Info                     
    +------------------+-----+----------------+-----------+-------------+--------------------------
    | mysql-bin.000002 |   4 | Format_desc    |         6 |         125 | Server ver: 8.0.26, Binlog ver: 4                                 |
    | mysql-bin.000002 | 125 | Previous_gtids |         6 |         156 |
    | mysql-bin.000002 | 156 | Gtid           |         6 |         233 | SET @@SESSION.GTID_NEXT= 'e0147cef-0953-11f0-858f-000c2966eb77:1' |
    | mysql-bin.000002 | 233 | Query          |         6 |         344 | create database twst3 /* xid=4 */                                 |
    | mysql-bin.000002 | 344 | Gtid           |         6 |         421 | SET @@SESSION.GTID_NEXT= 'e0147cef-0953-11f0-858f-000c2966eb77:2' |
    | mysql-bin.000002 | 421 | Query          |         6 |         532 | create database test4 /* xid=6 */                                 |
    +------------------+-----+----------------+-----------+-------------+--------------------------
    6 rows in set (0.00 sec)
    
    -- 在每个数据库操作事件之前,会显示GTID的唯一标识信息

十、慢日志(slow_log)

慢日志主要是用于以文本形式记录数据库服务运行过程中,执行过程较慢的语句;

利用慢日志信息生成的信息,可以在日常巡检过程中,通过日志定位SQL语句性能问题

1、日志信息基本配置

mysql> select @@slow_query_log;
+-------------------------+
| @@slow_query_log        |
+-------------------------+
|                       0 |
+-------------------------+
1 row in set (0.00 sec)
-- 此参数配置信息,表示是否激活启动慢日志记录功能,默认处于关闭状态

mysql> select @@slow_query_log_file;
+--------------------------------------------+
| @@slow_query_log_file                      |
+--------------------------------------------+
| /data/3306/data/xiaoQ-01-slow.log          |
+--------------------------------------------+
1 row in set (0.00 sec)
-- 此参数配置信息,表示慢日志文件保存的路径信息;建议日志文件路径与数据存放路径进行分离;

mysql> select @@long_query_time;
+---------------------------+
| @@long_query_time         |
+---------------------------+
|                 10.000000 |
+---------------------------+
1 row in set (0.00 sec)
-- 此参数信息配置,表示记录慢日志的条件,默认是大于10s执行的语句,就会记录为慢查询语句;(建议时间为0.01~0.1)  

mysql> select @@log_queries_not_using_indexes;
+---------------------------------------------+
| @@log_queries_not_using_indexes             |
+---------------------------------------------+
|                                           0 |
+---------------------------------------------+
1 row in set (0.00 sec)
-- 此参数信息配置,表示慢日志中会记录没有使用索引的语句信息;

# 修改日志默认状态(激活日志):
mysql> set global slow_query_log=1;
mysql> set global long_query_time=0.01;
mysql> set global log_queries_not_using_indexes=1;
-- 可以对以上参数信息进行在线调整,也可以将以上参数编写到数据库my.cnf配置文件中,作为永久配置;

2、日志应用配置核实

mysql> use xiaop;
mysql> show index from t100w;
mysql> alter table t100w drop index idx;
-- 删除数据表中索引信息
mysql> select * from t100w limit 100;
mysql> select * from t100w where id=10;
mysql> select * from t100w where id=20;
mysql> select count(*) from t100w group by num limit 10;
...
-- 模拟执行慢查询的操作语句

# 查看核实慢日志文件是否生成
[root@xiaoQ-01 ~]# ll /data/3306/data/xiaoQ-01-slow.log 
-rw-r----- 1 mysql mysql 6842 11月 22 23:54 /data/3306/data/xiaoQ-01-slow.log

[root@xiaoQ-01 ~]# cat /data/3306/data/xiaoQ-01-slow.log
/usr/local/mysql/bin/mysqld, Version: 8.0.26 (MySQL Community Server - GPL). started with:
Tcp port: 3306  Unix socket: /tmp/mysql.sock
Time                 Id Command    Argument
# Time: 2022-11-22T15:41:03.849261Z
# User@Host: root[root] @ localhost []  Id:   490
# Query_time: 0.000446  Lock_time: 0.000143 Rows_sent: 100  Rows_examined: 100
use xiaop;
SET timestamp=1669131663;
select * from t100w limit 100;
# Time: 2022-11-22T15:41:05.677310Z
# User@Host: root[root] @ localhost []  Id:   490
# Query_time: 0.000282  Lock_time: 0.000083 Rows_sent: 100  Rows_examined: 100
SET timestamp=1669131665;
select * from t100w limit 100;
# Time: 2022-11-22T15:41:06.630012Z
# User@Host: root[root] @ localhost []  Id:   490
# Query_time: 0.000242  Lock_time: 0.000075 Rows_sent: 100  Rows_examined: 100
SET timestamp=1669131666;
select * from t100w limit 100;
-- 会按照执行语句的操作时间顺序,进行慢查询日志信息的记录;

3、日志信息分析方法

[root@xiaoQ-01 data]# mysqldumpslow -s c -t 3 /data/3306/data/xiaoQ-01-slow.log 
-- 按照慢查询语句的重复执行次数(c)进行排序(-s),取出其中靠前(t)的前三名慢查询语句
-- 还可以扩展使用pt-query-digest更好的分析慢查询日志,支持图形化展示
-- what to sort by (al, at, ar, c, l, r, t), 'at' is default
    al: average lock time
    ar: average rows sent
    at: average query time
    c: count
    l: lock time
    r: rows sent
    t: query time  

十一、数据库服务备份恢复

1、恢复方式

数据库服务备份数据方式:

在企业中实现数据库服务数据备份的方式主要有两种方式:

① 物理方式

采用拷贝物理文件数据进行备份的方式,数据库服务物理数据文件存放路径是:/var/lib/mysql

实现方式:

  • 可以在某个特定时间点停机或停止业务访问,然后利用cp和tar命令将物理数据文件备份或打包;

  • 可以在任意时间节点在不停机不停止业务时,然后利用专业的xtrabackup(Percona Xtrabackup)热备工具进行数据库数据备份;

应用场景:

当企业数据库服务产生的需要备份的数据量在50G以上,可以选择物理备份(xtrabackup);

② 逻辑方式

可以采用以SQL语句形式把数据库的数据导出保存备份为数据库文件(xxx.sql),文件中会含有大量SQL语句信息;

实现方式:

  • 可以在任意时间节点在不停机不停止业务时,然后利用专业的mysqldump(MDP)逻辑备份工具进行数据备份;

  • 可以在任意时间节点在不停机不停止业务时,然后利用二进制日志binlog文件实现逻辑备份数据操作;

  • 可以在任意时间节点在不停机不停止业务时,然后利用主从数据库架构实现备份数据信息;

应用场景:

当企业数据库服务产生的需要备份的数据量在50G以内,可以选择逻辑备份(mysqldump);

02 数据库服务备份恢复职责:

  • 设计数据库备份策略:备份数据周期、选择的备份工具、应用的备份方式(全备 增量..);

  • 定期数据库备份检查:核实是否存在、确认备份文件大小;

  • 安排数据库恢复演练:真实确认备份的数据,是否能够准确的做数据恢复;

  • 真实数据库恢复能力:在数据库服务出现异常情况时,可以将数据库服务修复,并恢复丢失的数据信息;

  • 关于数据库迁移升级:可以采用Mergeing方式(主从架构)、可以单独备份数据信息到新的数据库节点做恢复(逻辑导出);

2、逻辑备份实践

工具命令使用语法:

[root@db02 ~]# mysqldump -u数据库用户 -p数据库密码 [备份参数] > /路径信息/数据库备份文件.sql
-- 在执行mysqldump命令时,也会用到数据库连接登录的基础参数:-u -p -S -h -P
序号参数信息官方说明解释说明
01-ADump all the databases表示备份所有库中数据信息
02-BDump several databases.表示备份指定库中数据信息
03-FFlush logs file in server before starting dump表示在备份启动前自动刷新日志文件

3、数据库备份恢复练习环境准备:

[root@db02 ~]# mkdir -p /database_backup

3.1、全库备份操作 -A

#我这个没有密码
[root@db02 ~]# mysqldump -uroot -p -A >/database_backup/all_database.sql
[root@db02 ~]#  ll -h /database_backup/all_database.sql
-rw-r--r--. 1 root root 1.5M Apr 30 16:05 /database_backup/all_database.sql
-- 利用mysqldump命令备份的数据文件是纯文本文件,是可以进行查看或过滤的

3.2、单个数据库进行备份(-B)

# 进行数据库单库备份操作
[root@db02 ~]# mysqldump -uroot -p -B xiaop > /database_backup/xiaop.sql

[root@db02 ~]# ll -h /database_backup/xiaop.sql
-rw-r--r--. 1 root root 1.7K Apr 30 16:08 /database_backup/xiaop.sql

# 过滤部分内容后查看备份数据库文件信息:
[root@db02 ~]# egrep -vi '^-|^/\*|^$|lock' /database_backup/xiaop.sql
SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET @@SESSION.SQL_LOG_BIN= 0;
SET @@GLOBAL.GTID_PURGED=/*!80000 '+'*/ 'e0147cef-0953-11f0-858f-000c2966eb77:1-15';
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `xiaop` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `xiaop`;
SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;

以上指定数据库备份完毕后,可以模拟删除相应数据,利用备份的数据库文件进行数据库恢复操作:

mysql> use xiaop
mysql> show tables;
+------------------------+
| Tables_in_xiaop       |
+------------------------+
| stu1                   |
+------------------------+
1 row in set (0.00 sec)

mysql> drop table stu2;
mysql> show tables;
Empty set (0.00 sec)
-- 模拟删除数据库中数据表信息,造成数据库中数据损坏

# 进行数据库数据复原恢复操作:
# 方式一:在数据库系统中加载数据库备份文件
mysql> source /database_backup/xaiop.sql;

# 方式二:在操作系统命令行执行数据恢复命令
[root@db02 ~]# mysql -uroot -p123456 xiaop </database_backup/xiaop.sql

# 数据信息恢复完毕后检查数据库情况
mysql> show tables;
+------------------------+
| Tables_in_xiaop       |
+------------------------+
| stu1                   |
+------------------------+
1 row in set (0.00 sec)

mysql> select * from stu1;
+----+-------+-----+------+
| id | name  | age | dept |
+----+-------+-----+------+
|  1 | xiaop |  22 | nan  |
+----+-------+-----+------+
1 row in set (0.01 sec)

2 rows in set (0.00 sec)

3.3、多个数据库进行备份(-B)

[root@db02 ~]# mysqldump -uroot -p123456 -B xiaop world >/database_backup/xiaop_world.sql

# 过滤部分内容后查看备份数据库文件信息:
[root@db02 ~]# egrep -vi '^-|^/\*|^$|lock' /database_backup/xiaop_world.sql

3.4、数据表部分备份操作练习实践命令

  • 将数据库中单个数据表进行备份

# 备份指定数据库中的单个数据表:
[root@db02 ~]# mysqldump -uroot -p xiaop stu1  >/databases_backup/xiaop_tables_stu1.sql

# 恢复指定数据库中的单个数据表:
[root@db02 ~]# mysql -uroot -p  xiaop </databases_backup/xiaop_tables_stu1.sql
  • 将数据库中多个数据表进行备份

# 备份指定数据库中的多个数据表:
[root@db02 ~]# mysqldump -uroot -p123456 world city country >/database_backup/world_tables_city_country.sql

# 恢复指定数据库中的多个数据表:
[root@db02 ~]# mysql -uroot -p  world </database_backup/world_tables_city_country.sql

4、Xtrabackup数据备份方式01:实现全量备份

# 全量备份操作:
[root@db02-01 ~]# mkdir /data/backup/full -p
-- 进行物理备份的目标目录不能存在数据信息,需要指定一个空目录进行备份

[root@db02-01 ~]# xtrabackup --defaults-file=/etc/my.cnf --host=192.168.30.101 --user=root --password=123456 --port=3306 --backup  --target-dir=/data/backup/full
或者使用参数--datadir替换掉参数--defaults-file

[root@db02-01 ~]# xtrabackup --datadir=/data/3306/data  --user=root --password=123456 --port=3306 --backup --target-dir=/data/backup/full
-- backup参数信息表示进行全备操作

# 物理备份命令执行输出信息说明:
221127 02:46:11 >> log scanned up to (277574297)
-- 记录日志位置点信息,表示进行拷贝数据的checkpoint的SN号码,相当于磁盘当前数据页的SN号码;
Using undo tablespace './undo_001'.
Using undo tablespace './undo_002'.
Opened 2 existing undo tablespaces.
221127 02:46:11 [01] Copying ./ibdata1 to /data/backup/full/ibdata1
221127 02:46:11 [01]        ...done
221127 02:46:11 [01] Copying ./sys/sys_config.ibd to /data/backup/full/sys/sys_config.ibd
221127 02:46:11 [01]        ...done
221127 02:46:11 [01] Copying ./mysql.ibd to /data/backup/full/mysql.ibd
... 省略部分信息...
-- 进行相关数据文件、日志文件、共享表空间文件、数据表空间文件等文件的拷贝,并且拷贝过程是不会进行锁表操作的;
-- 数据表空间信息备份完毕后,会有提示字段信息,并且此时会锁定binlog日志文件,并将binlog日志文件复制到备份目录;
-- 在进行binlog日志文件备份时,会生成xtrabackup_binlog_info文件信息,用于记录物理备份后的二进制日志位置点;
-- 二进制日志文件备份完毕后,会释放binlog日志文件锁定状态,并再次检查checkpoint的SN号码,确认redo日志是否变化;

[root@db02-01 backup]# ll /data/backup/full/
-- 可以看到将原有数据库的数据目录信息,已经基本迁移到指定的物理备份目录中;

Xtrabackup数据备份工具在热备操作后产生的特殊数据文件说明:

序号文件名称解释说明
01xtrabackup_binlog_info表示用于存储备份时的binlog位置点信息
02xtrabackup_checkpoints表示用于记录备份时的数据页LSN信息,主要用于接下一次备份,需要保证连续性;
03xtrabackup_info表示整体物理备份信息的总览
04xtrabackup_logfile表示存储在备份数据期间产生的新的的redo日志的信息;
05xtrabackup_tablespaces表示用于存储表空间的其余信息

4.1、Xtrabackup数据恢复方式01:全量备份恢复

模拟进行数据库数据破坏性操作:

[root@db02 ~]# pkill mysqld
[root@db02 ~]# rm -rf /data/3306/data/*
[root@db02 ~]# rm -rf /data/3306/logs/*
[root@db02 ~]# rm -rf /data/3306/binlog/*

进行数据库数据恢复的操作过程:
[root@db02 ~]# xtrabackup --prepare --target-dir=/data/backup/full
...忽略部分信息...
Shutdown completed; log sequence number 19214860
221127 16:31:58 completed OK!
-- 表示模拟CR过程,将redo日志进行前滚,undo日志进行回滚,让恢复数据信息保持一致性状态

[root@db02 ~]# xtrabackup --copy-back  --target-dir=/data/backup/full
-- 将进行物理备份后的数据,再次进行还原恢复到备份前的目录中(拷贝回数据)

[root@db02 ~]# chown -R mysql.mysql /data/*
[root@db02 ~]# /etc/init.d/mysqld start
-- 重新设置数据目录权限,并重新启动恢复数据库业务

4.2、Xtrabackup数据备份方式02:实现增量备份

xtrabackup物理备份数据时,实现增量备份原理分析:

  • 增量备份的实质是,基于上一次备份LSN变化过的数据页,进行相应的备份操作,从而可以不断实现增量备份操作;

  • 在备份同时产生的新的变更,会将redo日志信息备份;

  • 第一次增量备份时依赖于全量备份的,将来的恢复操作也要合并到全备中,再进行统一恢复;

说明:利用XPK增量备份数据,主要目的是减少频繁全备数据的时间开销,可以将每天增量的数据进行更快速的备份

# 增量备份准备:
[root@db02-01 ~]# mkdir /data/backup/full -p
-- 提前准备好全量备份的目录;
[root@db02-01 ~]# mkdir /data/backup/inc -p
-- 提前准备好增量备份的目录;

# 进行备份操作:
[root@db02-01 ~]# xtrabackup --defaults-file=/etc/my.cnf --host=192.168.30.101 --user=root --password=123456 --port=3306 --backup --parallel=4 --target-dir=/data/backup/full 
-- 进行全量备份操作,并且开启并发线程备份功能(--parallel=4),从而提高备份效率(建议4~8个)

mysql> create database pxb;
mysql> use pxb
mysql> create table t1(id int);
mysql> insert into t1 values(1),(2),(3);
mysql> commit;
-- 模拟登陆数据库,进行相关操作,实现增量备份的效果

[root@db02-01 ~]# xtrabackup --defaults-file=/etc/my.cnf --host=192.168.30.101 --user=root --password=123456 --port=3306 --backup --parallel=4 --target-dir=/data/backup/inc --incremental-basedir=/data/backup/full
-- 进行增量备份操作

# 可以进行继续备份操作(了解)
[root@db02-01 ~]# mkdir /data/backup/inc02 -p
-- 提前准备好增量备份的增量备份目录;

mysql> create database pxb02;
mysql> use pxb02
mysql> create table t1(id int);
mysql> insert into t1 values(1),(2),(3);
mysql> commit;
-- 模拟登陆数据库,进行相关操作,实现增量备份的效果

[root@db02-01 ~]# xtrabackup --defaults-file=/etc/my.cnf --host=192.168.30.101 --user=root --password=123456 --port=3306 --backup --parallel=4 --target-dir=/data/backup/inc02 --incremental-basedir=/data/backup/inc
-- 进行增量备份操作的下一次增量备份
Xtrabackup数据恢复方式02:增量备份恢复

模拟进行数据库数据破坏性操作:

[root@db02 ~]# pkill mysqld
[root@db02 ~]# rm -rf /data/3306/data/*
[root@db02 ~]# rm -rf /data/3306/logs/*
[root@db02 ~]# rm -rf /data/3306/binlog/*
进行数据库数据恢复的操作过程:
# 准备相关备份日志信息
[root@db02 ~]# xtrabackup --prepare  --apply-log-only  --target-dir=/data/backup/full
-- 准备全量备份的日志;
[root@db02 ~]# xtrabackup --prepare  --apply-log-only  --target-dir=/data/backup/full --incremental-dir=/data/backup/inc
-- 准备增量备份的日志,并且将增量备份合并到全量备份中;
[root@db02 ~]# xtrabackup --prepare  --target-dir=/data/backup/full
-- 在全量和增量数据合并后,在整体做日志信息的准备;

# 进行数据备份拷回操作
[root@db02 ~]# xtrabackup --datadir=/data/3306/data --copy-back  --target-dir=/data/backup/full
或者
[root@db02 ~]# xtrabackup  --copy-back  --target-dir=/data/backup/full
-- 将进行物理备份后的数据,再次进行还原恢复到备份前的目录中(拷贝回数据)

# 重新启动恢复业务功能
[root@db02 ~]# chown -R mysql.mysql /data/*
[root@db02 ~]# /etc/init.d/mysqld start
-- 重新设置数据目录权限,并重新启动恢复数据库业务

十二、数据库服务主从复制

所在位置线程名称作用说明
主库涉及线程binlog dump thread用于将主库binlog日志信息进行传输投递的线程 · 可以实现与从库的信息交互 · 可以监控二进制日志的变化 · 可以进行二进制日志的投递
从库涉及线程slave IO thread可以用于连接主数据库服务 · 可以实现与主库线程的交互 · 可以接收和存储二进制日志(接收的二进制日志会存储在中继日志中)
slave SQL thread可以解析执行中继日志信息
 

主库线程信息查看:binlog dump

     可以通过show processlist命令在主库上查看binlog dump线程,从binlog dump线程的状态可以看到,mysql的复制是主库主动推送日志到从库去的,是属于推日志的方式来做同步;

从库线程信息查看:slave io/slave sql

在从库上通过show processlist可以看到I/O线程和SQL线程;

  • I/O线程等待主库上的binlog dump线程发送事件并更新到中继日志relay log;

    用此线程和主库建立连接,并与主库的dump thread线程进行交互,以及接收和存储主库推送过来的binlog日志信息到relay log;

  • SQL线程读取中继日志relay log并应用变更到数据库;

    用此线程实现回放relay log中的日志信息,实现对从库的SQL语句操作;

从MySQL的复制流程可以得知MySQL的复制是异步的,从库上的数据和主库存在一定的延时;

​​​​

1、复制原理涉及文件

所在位置文件信息解释说明
主库涉及文件binlog可以利用二进制日志信息变化,实现主从数据库的异步方式同步
从库涉及文件relaylog可以利用中继日志进行临时存储或接收主库投递的二进制日志信息,日志信息会定期自动清理
master.info可以存储主库相关信息(主库地址 端口 用户 密码 二进制位置点-已经获取的 )(和IO线程相关)
relay-log.info可以存储SQL线程回放过的日志信息(与SQL线程相关)

2、MySQL的复制原理

  1. 在从库上执行change master to命令,将主库连接信息和binlog位置信息写入master.info文件或 slave_master_info表中;

  2. 在从库上执行start slave命令,用于启动从库的IO和SQL线程功能;

  3. 从库IO线程主要用于读取主库连接信息,实现和主库建立连接,从而使主库派生出binlog dump线程(自动监控binlog);

  4. 从库IO线程根据change master to命令所定义的数据位置点,获取最新的binlog日志信息

  5. mysql主库在事务提交时会把数据变更为事件Events记录在二进制日志文件binlog中;

    mysql主库上的sync_binlog参数控制binlog日志刷新到磁盘;

  6. binlog dump线程会截取binlog日志并投递其日志给从库IO线程,此时主库并不关心投递日志信息的结果;

  7. 此时从库IO线程接收binlog投递信息(缓存),随之会立即更新master.info文件 或 slave_master_info数据表信息;

  8. 从库缓存的binlog日志数据信息会被写入到relaylog中继日志中;

    主库推送二进制日志文件binlog中的事件到从库的中继日志relay log,之后从库根据中继日志relay log重做数据变更操作,

  9. 从库SQL线程将会读取relaylog.info文件或者slave_relay_log_info数据表中信息,获取上次数据回放同步位置点;

    随之继续向后回放同步数据,一旦回放同步数据完成后,再次更新relay.info或slave_relay_log_info数据表信息;

  10. 在从库中回放过的relaylog日志信息,会被relay_log_purge线程定期删除处理这些日志;

  11. 通过逻辑复制以此来达到主库和从库的数据一致;

MySQL通过3个线程来完成主从库间的数据复制:其中binlog dump线程跑在主库上,I/O线程和SQL线程跑在从库上;

当在从库上启动复制(START SLAVE)时,首先创建I/O线程连接主库,主库随后创建binlog dump线程读取数据库事件;

并发送给I/O线程,I/O线程获取到事件数据后更新到从库的中继日志relay log中去,之后从库上的SQL线程读取中继日志relay log,

根据中继日志中的更新的数据库事件并应用;

3、主从复制实践

3.1操作步骤01:需要准备两台以上数据库实例

# 数据库节点01服务已经构建完毕
[root@xiaoQ-01 ~]# mysqld_safe --defaults-file=/data/3307/data/my.cnf &      
[root@xiaoQ-01 ~]# netstat -lntp|grep 3307
tcp6       0      0 :::3307                 :::*                    LISTEN      114722/mysqld  
[root@xiaoQ-01 ~]# mysql -S /tmp/mysql3307.sock
    
# 数据库节点02服务已经构建完毕
[root@xiaoQ-01 ~]# mysqld_safe --defaults-file=/data/3308/data/my.cnf &
[root@xiaoQ-01 ~]# netstat -lntp|grep 3308
tcp6       0      0 :::3308                 :::*                    LISTEN      122865/mysqld   
[root@xiaoQ-01 ~]# mysql -S /tmp/mysql3308.sock

3.2、操作步骤02:主数据库二进制日志功能开启

# 主数据库需要开启binlog日志功能
mysql> show variables like '%log_bin%';
+---------------------------------+--------------------------------------+
| Variable_name                   | Value                                |
+---------------------------------+--------------------------------------+
| log_bin                         | ON                                   |
| log_bin_basename                | /data/3307/data/binlog               |
| log_bin_index                   | /data/3307/data/binlog.index         |
| sql_log_bin                     | ON                                   |
+---------------------------------+--------------------------------------+
6 rows in set (0.01 sec)
-- 核实确认binlog日志功能在主库上已经开启

3.3操作步骤03:核实主从复制主机的信息情况

# 确认多个复制节点的服务标识不同(server id/server_uuid)
mysql> set global server_id=7;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           7 |
+-------------+
1 row in set (0.00 sec)

mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid                        |
+--------------------------------------+
| 949efd68-6420-11ed-b1ad-000c2996c4f5 |
+--------------------------------------+
1 row in set (0.00 sec)
-- 主库上server_id server_uuid信息(3307节点做检查)

mysql> set global server_id=8;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           8 |
+-------------+
1 row in set (0.00 sec)

mysql> select @@server_uuid;
+--------------------------------------+
| @@server_uuid                        |
+--------------------------------------+
| ed6c1c6f-6f33-11ed-b630-000c2961cd06 |
+--------------------------------------+
1 row in set (0.00 sec)
-- 从库上server_id server_uuid信息(3308节点做检查)
-- 根据服务标识信息的不同,可以用于在进行主从复制时,辨别节点之间的关系

# 确认多个复制节点的时间信息同步
[root@xiaoQ-01 ~]# date
2022年 11月 30日 星期三 23:44:37 CST
[root@xiaoQ-02 ~]# date
2022年 11月 30日 星期三 23:44:52 CST
-- 核心确认主从节点时间信息同步

# 确认多个复制节点的版本信息一致
[root@xiaoQ-01 ~]# mysql -V
mysql  Ver 8.0.26 for Linux on x86_64 (MySQL Community Server - GPL)
[root@xiaoQ-02 ~]# mysql -V
mysql  Ver 8.0.26 for Linux on x86_64 (MySQL Community Server - GPL)
-- 部分实际应用场景中可以支持不一致,但是复制源端可以是低版本,复制目标端可以是高版本,反之不行;

3.4操作步骤05:创建主从数据同步的用户信息

# 在主库上创建复制同步数据用户
mysql> create user repl@'192.168.200.%' identified with mysql_native_password by '123456';

mysql> grant replication slave on *.* to repl@'192.168.200.%';
-- 从库会利用主库上的同步数据用户,进行数据同步传输操作

3.5操作步骤06:进行从库部分数据信息的同步

# 可以将主库上的部分数据在从库上先进行同步

[root@db02 tmp]# mysqldump -uroot -A -S /tmp/mysql.sock --master-data=2 --single-transaction >/tmp/full.sql
-- 在3306主库上进行数据的全备(模拟企业环境的历史数据全备)

scp /tmp/full.sql 192.168.200.146:/tmp/
[root@xiaoQ-01 ~]# mysql 
mysql> source /tmp/full.sql;
-- 在从库上进行数据的恢复(模拟企业环境的历史数据恢复)两边数据一样
-- 将原有主机的数据先备份,然后从库中进行恢复一部分数据,随后再进行数据信息同步追加
-- 可以利用同步方式有很多:mysqldump xtrabackup clone_plugin

3.6操作步骤07:配置主从节点数据复制的信息

# 设置从库连接主库信息,定义从库连接主库同步位置点自动复制
mysql> help change master to
-- 获取连接主库,以及定义同步位置点的数据库配置模板信息

[root@xiaoQ-01 ~]# vim /tmp/full.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='binlog.000003', MASTER_LOG_POS=681;
-- 通过备份文件获取同步位置点信息

SHOW MASTER STATUS; #查看MASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=1638,

#注意MASTER_LOG_FILE='binlog.000001',文件名对不对
mysql> CHANGE MASTER TO
MASTER_HOST='192.168.200.145',
MASTER_USER='repl',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='binlog.000001',
MASTER_LOG_POS=881,
MASTER_CONNECT_RETRY=10;
-- 以上配置主从同步信息在 --从库 进行执行;

3.7操作步骤08:激活主从节点数据复制的线程

# 利用相应线程实现主从数据库的数据同步复制
mysql> start slave;
-- 在从库上激活数据复制同步功能

# 若此时数据同步失败可以重新开启同步功能
mysql> stop slave;
mysql> reset slave all;
-- 在从库上重置数据复制同步功能,重新配置change master to信息,然后重新激活同步复制功能;

# 进行核实主从同步功能是否实现
[root@xiaoQ-01 ~]# mysql -S /tmp/mysql3307.sock
mysql> create database xiaop;
-- 在主库模拟创建数据信息

[root@xiaoQ-01 ~]# mysql -S /tmp/mysql3308.sock
mysql> show databases;
-- 在从库模拟查看数据信息(确认是否同步数据)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for source to send event
                  Master_Host: 192.168.30.101
                  Master_User: repl
                  Master_Port: 3307
                Connect_Retry: 10
              Master_Log_File: binlog.000003
          Read_Master_Log_Pos: 869
               Relay_Log_File: xiaoQ-01-relay-bin.000002
                Relay_Log_Pos: 509
        Relay_Master_Log_File: binlog.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
-- 从库上查看数据同步状态情况,看到上面的两个Yes信息,就表示主从数据同步功能设置成功了

####有待补充。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值