数据库方面是知识和实战

庞丽静

邮箱 [email protected]

笔记 https://gitee.com/panglijing/dba

准备软件是

[root@ip176-121-205-88 ftp]# cd /linux-soft/4/mysql/
[root@ip176-121-205-88 mysql]# ls
libev-4.15-1.el6.rf.x86_64.rpm
maxscale-2.1.2-1.rhel.7.x86_64.rpm
mha-soft-student
Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
my.cnf
mysql-5.7.17.tar
mysql-5.7.20-linux-glibc2.12-x86_64.tar.gz
percona-xtrabackup-24-2.4.7-1.el7.x86_64.rpm
phpMyAdmin-2.11.11-all-languages.tar.gz
pxc
schema.xml
[root@ip176-121-205-88 mysql]# scp mysql-5.7.17.tar 192.168.4.50:/root/
mysql-5.7.17.tar                              100%  543MB 115.1MB/s   00:04 

什么是数据库

数据库介绍

  • 存储数据的仓库

  • 生活中的数据

    • 视频、音频、图片、文本

常见的软件

  • 主流操作系统:unix、linux、windoes

开源软件不等于免费

专业术语(行业黑话)

  • DB
    • 数据库
    • 依照某种数据模型进行组织并存放到存储器的数据集合
  • DBMS
    • 数据库管理系统
    • 用来操作和管理数据库的服务软件
  • DBS
    • 数据库系统:即DB+DBMS
    • 指带有数据库并整合了数据库管理软件的计算机系统
  • DBA
    • 数据库管理员
      • 初级
      • 中级
      • 高级(三到五年的经验)

MYSQL的介绍

起源与发展
  • 应用最广泛的的开源数据库
  • 崭新的开源分支Mariadb
    • 为应对mysql可能会闭源的风险而诞生
特点
  • 主要特点
    • 适用于中小规模,关系型数据库系统
    • 支持多种操作系统
    • 支持多种编程语言
  • 典型应用环境
    • LAMP平台
    • LNMP平台

搭建数据库

[root@localhost ~]# tar xf mysql-5.7.17.tar 
[root@localhost ~]# ls
mysql-5.7.17.tar
mysql-community-client-5.7.17-1.el7.x86_64.rpm
mysql-community-common-5.7.17-1.el7.x86_64.rpm
mysql-community-devel-5.7.17-1.el7.x86_64.rpm
mysql-community-embedded-5.7.17-1.el7.x86_64.rpm
mysql-community-embedded-compat-5.7.17-1.el7.x86_64.rpm
mysql-community-embedded-devel-5.7.17-1.el7.x86_64.rpm
mysql-community-libs-5.7.17-1.el7.x86_64.rpm
mysql-community-libs-compat-5.7.17-1.el7.x86_64.rpm
mysql-community-minimal-debuginfo-5.7.17-1.el7.x86_64.rpm
mysql-community-server-5.7.17-1.el7.x86_64.rpm
mysql-community-test-5.7.17-1.el7.x86_64.rpm
[root@localhost ~]# rpm -q mariadb-server
未安装软件包 mariadb-server 
[root@localhost ~]# rpm -q mariadb
未安装软件包 mariadb 
# 这两个软件都需要不存在,如果有的话,就需要先停止服务,删除软件,删除配置文件
systemctl  stop  mariadb 
          rpm  -e  --nodeps  mariadb  mariadb-server 
          rm  -rf  /etc/my.cnf  
          rm  -rf  /var/lib/mysql/*

[root@localhost ~]# yum -y install mysql-community-*.rpm
[root@localhost ~]# systemctl start mysqld  # 只有第一次启动的时候才会初始化数据
[root@localhost ~]# ls /var/lib/mysql  # 存储数据的文件夹
auto.cnf         ib_buffer_pool  mysql               public_key.pem
ca-key.pem       ibdata1         mysql.sock          server-cert.pem
ca.pem           ib_logfile0     mysql.sock.lock     server-key.pem
client-cert.pem  ib_logfile1     performance_schema  sys
client-key.pem   ibtmp1          private_key.pem

[root@localhost ~]# systemctl enable mysqld   # 设置开机自启  
[root@localhost ~]# ss -tunlp | grep 3306   # 端口是3306
tcp    LISTEN     0      80       :::3306                 :::*                   users:(("mysqld",pid=1049,fd=22))
[root@localhost ~]# ps -C mysqld
  PID TTY          TIME CMD
 1049 ?        00:00:00 mysqld

查看初始密码

[root@localhost ~]# ls /var/log/mysqld.log 
/var/log/mysqld.log
[root@localhost ~]# grep -i "password" /var/log/mysqld.log   # -i 是忽略字母大小写
2022-02-07T02:15:34.952961Z 1 [Note] A temporary password is generated for root@localhost: z%s=b1Dg*8Wm  # 冒号空格后面的才是密码

[root@localhost ~]# mysql -hlocalhost -uroot -p'z%s=b1Dg*8Wm'
-h 指定登录的服务器
-u 指定用户
-p 后面需要加‘’避免出现特殊字符而报错:指定密码

ctrl +l 清屏

初次登录必须修改密码

mysql> alter user root@"localhost" identified by "123qqq...A";   
# identified 是指定密码的
mysql> show databases;

退出

mysql> exit ;
Bye

再次登录

[root@localhost ~]# mysql -uroot -p'123qqq...A'
自己访问自己,-hlocalhost 可以省略

多准备一台192.168.4.51的机器,一样的操作。密码设置为”NSD2110…a"

连接服务

初始密码登录

  • 数据库管理员名为root
    • 默认仅允许root本机连接
    • 首次登录密码存储在/var/log/mysql.log 日志文件中

基本操作

  • 必备命令
mysql> select version();  #查看服务器软件版本

mysql> select user();  #查看登录用户

mysql> show databases;   #查看当前所在的库

mysql> select database();   #查看已有的库

mysql> use mysql;   #切换库
Database changed

mysql> show tables ;  #查看已有的表


相关参数

  • 必须熟知
[root@mysql1 ~]# ls /etc/my.cnf  # 主配置文件
/etc/my.cnf

[root@mysql1 ~]# ls /var/lib/mysql  # 数据库的文件
auto.cnf         ib_buffer_pool  mysql               public_key.pem
ca-key.pem       ibdata1         mysql.sock          server-cert.pem
ca.pem           ib_logfile0     mysql.sock.lock     server-key.pem
client-cert.pem  ib_logfile1     performance_schema  sys
client-key.pem   ibtmp1          private_key.pem

# 端口号 3306
# 进程名  mysqld
# 传输协议 TCP
# 进程所有者  mysql
# 进程所属组  mysql
# 错误日志文件 服务日志  /var/log/mysqld.log 

密码策略

  • 临时修改
mysql> show variables like "%password%";  %是模糊搜索
+---------------------------------------+--------+
| Variable_name                         | Value  |
+---------------------------------------+--------+
| default_password_lifetime             | 0      |
| disconnect_on_expired_password        | ON     |
| log_builtin_as_identified_by_password | OFF    |
| mysql_native_password_proxy_users     | OFF    |
| old_passwords                         | 0      |
| report_password                       |        |
| sha256_password_proxy_users           | OFF    |
| validate_password_check_user_name     | OFF    |
| validate_password_dictionary_file     |        |
| validate_password_length              | 8      |  # 这个是密码的长度
| validate_password_mixed_case_count    | 1      |
| validate_password_number_count        | 1      |
| validate_password_policy              | MEDIUM | # 这个是密码策略
| validate_password_special_char_count  | 1      |
+---------------------------------------+--------+
14 rows in set (0.03 sec)

mysql> set global validate_password_policy = 0 ;  0 就是最低级别
mysql> show variables like "%password%";
+---------------------------------------+-------+
| Variable_name                         | Value |
+---------------------------------------+-------+
| default_password_lifetime             | 0     |
| disconnect_on_expired_password        | ON    |
| log_builtin_as_identified_by_password | OFF   |
| mysql_native_password_proxy_users     | OFF   |
| old_passwords                         | 0     |
| report_password                       |       |
| sha256_password_proxy_users           | OFF   |
| validate_password_check_user_name     | OFF   |
| validate_password_dictionary_file     |       |
| validate_password_length              | 8     |  # 这个是密码的长度
| validate_password_mixed_case_count    | 1     |
| validate_password_number_count        | 1     |
| validate_password_policy              | LOW   |  # 显示当前的密码等级
| validate_password_special_char_count  | 1     |
+---------------------------------------+-------+
14 rows in set (0.00 sec)

mysql> set global validate_password_length = 6 ;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "%password%";
+---------------------------------------+-------+
| Variable_name                         | Value |
+---------------------------------------+-------+
| default_password_lifetime             | 0     |
| disconnect_on_expired_password        | ON    |
| log_builtin_as_identified_by_password | OFF   |
| mysql_native_password_proxy_users     | OFF   |
| old_passwords                         | 0     |
| report_password                       |       |
| sha256_password_proxy_users           | OFF   |
| validate_password_check_user_name     | OFF   |
| validate_password_dictionary_file     |       |
| validate_password_length              | 6     |  # 这个是密码的长度
| validate_password_mixed_case_count    | 1     |
| validate_password_number_count        | 1     |
| validate_password_policy              | LOW   |  # 显示当前的密码等级
| validate_password_special_char_count  | 1     |
+---------------------------------------+-------+
14 rows in set (0.00 sec)

mysql> alter user root@"localhost" identified by "123456"; 
Query OK, 0 rows affected (0.00 sec)

  • 永久修改
。。。
[mysqld]
validate_password_policy=0
validate_password_length=6
。。。
[root@mysql1 ~]# systemctl restart mysqld  # 重启不报错就可以了
 

破解密码

  • 忘记root登录密码时候,恢复登录密码
[mysqld]
skip-grant-tables  #  跳过授权表
#validate_password_policy=0
#validate_password_length=6
# 再次登录的时候就可以直接输入mysql
systemctl restart mysqld # 重启服务
mysql # 无密码登录
mysql> update mysql.user set authentication_string=password("654321")
    -> where user="root" and host="localhost";  # 修改密码

mysql> flush privileges;   # 刷新权限

mysql> exit  # 退出连接
Bye
[root@mysql1 ~]# vim /etc/my.cnf
[mysqld]
#skip-grant-tables  # 注释
validate_password_policy=0
validate_password_length=6
[root@mysql1 ~]# systemctl restart mysqld  # 重启服务
[root@mysql1 ~]# mysql -uroot -p654321  # 新密码登录

具体操作如下:(必须要重启数据库的服务:不适合线上服务器)

  1. 修改主配置文件(使其可以无密码登录)
  2. 重启数据库服务
  3. 无密码登录,并修改登录密码,断开连接
  4. 还原对主配置文件的修改
  5. 重启数据库服务
  6. 使用破解后的密码登陆(能登录成功)

不停止数据库的情况下破解数据库管理员的密码

必须借助其他的服务器的

用其他的服务器密码去覆盖不知道的服务器密码

[root@mysql2 ~]# ls /var/lib/mysql
auto.cnf         ib_buffer_pool  mysql               public_key.pem
ca-key.pem       ibdata1         mysql.sock          server-cert.pem
ca.pem           ib_logfile0     mysql.sock.lock     server-key.pem
client-cert.pem  ib_logfile1     performance_schema  sys
client-key.pem   ibtmp1          private_key.pem
都是存储到mysql这个文件夹中

[root@mysql1 ~]# scp -r 192.168.4.51:/var/lib/mysql/mysql /var/lib/mysql
[root@mysql1 ~]# kill -l  # 查看所有的信号
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

[root@mysql1 ~]# which pstree
/usr/bin/pstree
如果没有的话,yum -y install psmisc  这个是pstree 命令的软件包

[root@mysql1 ~]# pstree -p | grep mysql | head -1
           |-mysqld(2301)-+-{mysqld}(2302)

[root@mysql1 ~]# kill -SIGHUP 2301  # 发送-SIGHUP信号给父进程
[root@mysql1 ~]# ss -tunlp | grep 3306
tcp    LISTEN     0      80       :::3306                 :::*                   users:(("mysqld",pid=2301,fd=32))

[root@mysql1 ~]# mysql -uroot -p'NSD2110...a'

破解线上数据库服务器的管理员root密码

  • 恢复线上服务器密码,线上服务器是不能轻易重启服务的

具体操作步骤如下

  1. 拷贝其他数据库服务器管理员root用户能正常连接数据库服务的mysql库覆盖本机的mysql库
  2. !!!mysql库存放的是数据库服务器的用户和密码!!!
  3. 查看mysql服务器 父进程的pid
  4. 给mysql服务的父进程发送SIGHUP信息(作用重新加载数据库目录下的文件,可以重新识别mysql库里的用户和密码)
  5. 使用破解后的密码登录(密码和root用户能正常服务主机的root密码一样)

修改密码

登录前修改:mysqladmin

等效于alter user 命令(登录后修改)

[root@mysql1 ~]# mysqladmin  -uroot -p"NSD2110...a" password "123456"
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.7.17 MySQL Community Server (GPL)

[root@mysql1 ~]# mysqladmin  -uroot -p password 
回车,不明文输入密码

基础查询

连接方式

  • 客户端连接Mysql服务的方式
    • 命令行连接
    • 图形软件连接
    • 脚本连接
常用如性软件 操作系统 说明
Mysql-workbench 跨平台 Mysql官方提供
Mysql-Fromt windows 开源,轻量级客户端软件
Navicat Windows 专业,功能强大,商业版
phpMyAdmin 跨平台 开源,需LAMP平台
yum -y install httpd php php-mysql
systemctl restart httpd
systemctl enable httpd.service 
tar xf phpMyAdmin-2.11.11-all-languages.tar.gz 
mv phpMyAdmin-2.11.11-all-languages /var/www/html/phpMyAdmin
cd /var/www/html/phpMyAdmin/
cp config.sample.inc.php  config.inc.php   # 创建主配置文件
vim +17 config.inc.php # 在‘’号里添加plj123  这个类似与验证码,可以随便写,但不可以没有

接下来直接在真机的浏览器中访问http://192.168.4.50/phpMyAdmin

用户名和密码都是数据库的用户名和密码

Mysql管理环境

就是命令行登入界面的环境

安装sqljoy这个软件可以直接tab

语法规范

  • \c终止sql命令
  • 但行注释# 或-
  • 多行注释/× ×/
  • 默认命令不支持tab键补全
  • 每条SQL命令以; 或\G结束
  • 每条命令可以很局需要缩进或换行
  • SQL命令不区分字母大小写 (密码、变量值除外)

根据命令功能分类如下:

  • DQL :数据库查询语言
    • 负责进行数据查信而不会对数据本身进行修改的语句,这个是最基本的SQL语句
  • DDl :数据定义语言
    • 负责数据结构定义与数据库对象定义的语言 由create alter drop 三个语法所组成
  • DML :数据操作语言
    • 负责对数据库对象运行数据访问工作的指令集,以insert update delete 三种指令为核心,分别代表插入,更新与删除
  • DCL : 数据控制语言
    • 它可以控制特定用户账户对数据访问权限,由grant revoke两个指令组成

基础查询

查询使用的命令是select:对数据做查询的命令

语法格式:

  • select 表头名 from 库.表;
  • select 表头名 from 库.表 where 筛选条件;
  • select命令的其他用法:
    • 常量 select 5 ;
    • 变量 select @@version ;
    • 表达式 select 3 + 2 ;
    • 函数 select count(*) from user ;
    • 所有字段 1个字段 、多个字段
    • × 字段名 字段名,字段名

命令格式

  • 只查看与条件匹配的记录
  • select 字段名列表 from 库名.表名 where 条件;
命令 说明 例子
as 或空格 别名 select name 用户名,homedir as 家目录 from tarena.user
concat() 拼接 select concat(name,‘-’,uid) from user ; 任意字段为NULL返回值为null
distinct 去重 select distinct gid from user ;

数值比较

  • 符号两边必须是数据类型

    select * from user where uid =3 ;

比较符号 说明
= 等于
> 大于
>= 大于或等于
< 小于
<= 小于或等于
!= 不等于

字符比较/匹配空/非空

  • 字段必须是字符类型
比较符号 说明 例子
= 等于 name =“root”
!= 不等于 name != “root”
is null shell is null
is not null 非空 shell is not null

范围匹配

  • 匹配范围内的任意一个值即可
比较符号 说明
in(值列表) 在…里…
not in (值列表) 不在…里…
between 数字 and 数字 在…之间

模糊匹配

  • 用法
where   字段名   like  '通配符'
_表示1个字符
%表示0到多个字符

正则匹配

  • 用法
where 字段名 regexp  '正则表达式'
元字符:
^  行首
$  行尾
.  1个字符
[]  范围内
*  前面表达式出现0或多次
|  或

准备环境

[root@mysql1 ~]# mysql -uroot -p123456 < tarena.sql 
mysql: [Warning] Using a password on the command line interface can be insecure.

mysql> show databases;

mysql> select * from tarena.user; # 所有表头


mysql> select id,name,uid from user ;  # 多个表头


mysql> select id,name,uid from user where uid<10;  # 后面的就是筛选条件


mysql> select name as 姓名 from user ; #as 或 空格都是可以的

mysql> select  concat(name,'-',uid) as 姓名 from user where uid < 5 ; # 拼接 任意字段为 NULL返回值null

mysql> select distinct shell from tarena.user;  # 去重


mysql> select * from user where id <=3 ;

mysql> select * from user where id = 1;

mysql> select * from user where id != 1 ;
显示的内容太多了

mysql> select id,name,uid,gid from user where uid = gid ;

mysql> select name,shell from user where shell != "/bin/bash";

mysql> select name,shell from user where shell ="/bin/bash";


mysql> select name from user where id = 1 ;

mysql> select name from user where id = 1 and name is not null;  # 这个是两个条件都成立

mysql> select name from user where id = 1 and name is null;  # 有一方不成立
Empty set (0.00 sec)


mysql> insert into tarena.user(name,uid) values(null,2001)
mysql> select * from user where name is null ;

如果null加了双引号就变成字符串了,不表示空字符了。
mysql> insert into tarena.user(name,uid) values("null",2001)
mysql> insert into tarena.user(name,uid) values(" ",2001)
mysql> insert into tarena.user(name,uid) values("",2001)



mysql> select name ,shell  from user 
    -> where
    -> shell in ("/bin/bash","/sbin/nologin");

mysql> select name,uid from user where uid not in (1,2,3,21,12,312) ;

mysql> select name,id from user where id between 10 and 20 ;

mysql> select name from user where name like '____';  # 一个下划线表示一个字符


mysql> select name from user where name like '_%_';  # 表示至少是两个字符的 % 表示任意多个

mysql> select name from user where name like 'a%';  # 以a开头的


mysql> select name from user where name regexp '^a' ;  # 正则 以a开头

mysql> select name from user where name regexp '^a.*t$';  # 正则 以a开头 以t 结尾
Empty set (0.00 sec)

筛选条件的写法

  • 数据比较 select * from tarena.user id <=3 ;
  • 字符比较
  • 空 表头下没有数据 使用null表示 is null
  • 非空 表头下有数据 is not null

逻辑匹配

查找数据的时候有多个查找条件

逻辑与 and && 多个查找条件必须全部成立

逻辑或 or || 多个查询条件某个条件成立即可

逻辑非 not ! 取反

() 提高优先级别 (条件)

优先级 () and or

and 和 or 同时存在是先判断and再判断or

mysql> select name ,uid from user where  name = "root" and uid = 1;

mysql> select name ,uid from user  where name = 'root' or uid = 1;



mysql> select name ,uid from user 
    -> where 
    -> uid != 1 ;

mysql> select (2+2)*7 as 结果;

mysql> select name ,uid from user where name ='root'  and uid =0 or uid =1;

mysql> select name ,uid from user where name = 'root' or name ='bin' and uid = 1;

mysql> select name ,uid from user 
    -> where 
    -> (name = 'root'or  name = 'bin') and uid = 1;

表管理

表放在

[root@mysql1 ~]# ls /var/lib/mysql
auto.cnf         client-key.pem  ib_logfile1  mysql.sock.lock     server-cert.pem
ca-key.pem       ib_buffer_pool  ibtmp1       performance_schema  server-key.pem
ca.pem           ibdata1         mysql        private_key.pem     sys
client-cert.pem  ib_logfile0     mysql.sock   public_key.pem      tarena

[root@mysql1 ~]# cd /var/lib/mysql/tarena/
[root@mysql1 tarena]# ls
db.opt           departments.ibd  employees.ibd  salary.ibd  user.ibd
departments.frm  employees.frm    salary.frm     user.frm

建库

建库

原有的四个库不能删除,

裤:存放表的目录

create database [if not exists] 数据库名

[] 表示可选项

mysql> create database game ;

mysql> show databases;


mysql> use game ;
Database changed
mysql> show tables;
Empty set (0.00 sec)

[root@mysql1 ~]# ls /var/lib/mysql
auto.cnf         game            ibtmp1              private_key.pem  tarena
ca-key.pem       ib_buffer_pool  mysql               public_key.pem
ca.pem           ibdata1         mysql.sock          server-cert.pem
client-cert.pem  ib_logfile0     mysql.sock.lock     server-key.pem
client-key.pem   ib_logfile1     performance_schema  sys
 # 就多了一个game库
 
 mysql> create database if not exists game ;  # 假如库不存在的话,创建,存在不报错
Query OK, 1 row affected, 1 warning (0.00 sec)

库名:

  • 仅可以使用数字、字母、下划线、不能纯数字
  • 区分字母大小写
  • 具有唯一性
  • 不可使用指令关键字,特殊字符、

删库

库文件下面的文件也会一并删除

mysql> show databases;

mysql> drop database buy;

mysql> drop database game;

mysql> show databases ;

mysql> drop database if exists game ;  # 当库不存在的时候删除库,不会报错;

建表

定义:就是定义存储数据的文件有哪些表头

比如 创建一张表存储学生信息

姓名 性别 年龄 班级 电话号码 住址 身份证号

建表的命令格式

create table 库名.表名(表头名 数据类型 , 表头名 数据类型);

数据类型

每种类型都有规定好的命令表示

比如字符类型的数据 使用char

比如数字类型的数据 使用 int

create database studb ;
create table studb.stuinfo(name char(10),age  int(2));
insert into studb.stuinfo  values('jim' ,19),("tom",16);
select * from studb.stuinfo;

[root@mysql1 ~]# ls /var/lib/mysql/studb/
db.opt  stuinfo.frm  stuinfo.ibd


mysql> desc studb.stuinfo;  可以查看到表的结构;后面的4列是约束条件


[root@mysql1 ~]# ls /var/lib/mysql/tarena/salary.frm  # 存放表的结构.frm
/var/lib/mysql/tarena/salary.frm
[root@mysql1 ~]# ls /var/lib/mysql/tarena/salary.ibd  # 存放表的信息.ibd
/var/lib/mysql/tarena/salary.ibd

注意:表必须存放在库里

desc 库.表名; # 查看表结构

drop table 库.表名 # 删除表

E-R模型

提问1;建表时 如何确定表中应该有几个表头名 表头名都叫什么

E-R模型(标准)

  • 实体-关系 模型

提问2:如何判断好的表 是否创建的 合理?

建表范式(标准)

建表范式
  • 建表的遵循的规则: 可以分为6个等级:1NF 2NF 3NF 4NF 5NF BCNF
  • NF是Normal Form 的缩写。一般情况下,只要把数据规范到第三范式标准就可以满足需要了
  • 第一范式(确保每列保持原子性)【属性不可分】
  • 第二范式(2NF)(确保表中的每列都和主键相关)【符合第一范式,同时非主属性完全以来于主键】
  • 第三范式(3NF)(确保每列都和主键列直接相关,而不是间接相关)【符合2NF,并且消除传递依赖】

2NF与3NF的区别:

在于有没有分出2张表,2NF如果一张表中含有多种不同实体的属性那么必须要分成多张表。3NF已经分成多张表后,一张表中只能有另一张表中的主键,而不能有其他信息。

修改表

删除表中的数据

mysql> delete from studb.stuinfo;  # 慎用
mysql> select * from studb.stuinfo;

使用studb.stuinfo表练习修改表结构

工作中是把表的结构修改好后,再存储数据的

delete from studb.stuinfo ; 删除表里的所有行

修改并表结构的命令格式:

alter table 库名.表明 操作命令‘

操作命令 说明
add 添加新字段,一起添加多个字段使用,分隔add命令(frist after)
modify 修改字段类型,也可以修改字段的位置
change 修改字段名,也可以同时修改字段类型
rename 修改表名
drop 删除字段 删除多个字段使用 , 分隔drop命令

操作命令包括那些

添加新标头

add 表头名 数据类型 ,add 表头名 数据类型 ;

mysql> desc studb.stuinfo;

mysql> alter table studb.stuinfo add class char(7) ,add mail char(20);

mysql> desc studb.stuinfo;

mysql> alter  table studb.stuinfo add 学号 int first ;  # 在表第一列添加first

mysql> desc studb.stuinfo;

mysql> alter table studb.stuinfo add 住址 char(50) after name ; # 在name后面添加

mysql> desc studb.stuinfo;

删除已有表头

drop 表头名

mysql> alter table studb.stuinfo drop 学号,drop 住址;

mysql> desc studb.stuinfo;

修改表头数据类型

modify 表头名 数据类型 [约束条件];

mysql> desc studb.stuinfo;

mysql> alter table studb.stuinfo modify class varchar(10), modify mail varchar(30) not null default '[email protected]';

mysql> desc studb.stuinfo;

mysql> alter table studb.stuinfo modify class varchar(10) after name ;

mysql> desc studb.stuinfo;

修改表头名

change 源表头名 新表头名 数据类型 约束条件;

mysql> alter table studb.stuinfo change name 姓名 char(10);

mysql> desc studb.stuinfo;

如果想把数据类型和约束条件也修改的话,直接写新的数据类型和约束条件即可

mysql> alter table studb.stuinfo change mail 邮箱 char(50) not null default  '163.com';

mysql> desc studb.stuinfo;

修改表命令

rename

mysql> alter table studb.stuinfo rename studb.学生信息表;

mysql> show tables ;

复制表

语法格式

​ 仅复制表的结构

create table 库.表 select 列名 from 库.表 where 1=2;

​ 仅复制表结构及数据

create table 库.表 select 列名 from 库.表 [where 条件]

create table studb.部门表 select * from tarena.department

mysql> desc studb.部门表;

注意: 原表的key,不会复制给新表,新表数据与select语句决定

​ 仅复制表结构

create table 库.表 like 库.表

create table studb.部门表 like tarena.departments

mysql> desc studb.部门表2 ;

注意:原有的key 同时复制给新表

修改已有的字符集

指定表使用中文字符集utf8 才可以给表存储汉字

create table studb.stuinfo2(姓名 char(10),住址 char(50),职业 char(5)) default charset utf8

mysql> create table studb.stuinfo2(姓名 char(10),住址 char(50),职业 char(5)) default charset utf8;
mysql> desc stuinfo2;

mysql> insert into stuinfo2 values("小奶狗","狗窝","运维汪");
 
mysql> insert into stuinfo2 values("小奶狗","狗窝","运维汪");

mysql> select * from stuinfo2;

mysql> show create table stuinfo2 \G

管理表记录

对表中的行做管理:包括

查询:select 查看表里已经存储的数据(最多)

插入:inster into 向表中添加新行

修改:update 修改行中列的值

删除记录 delete 把表中的行删除

mysql> select * from tarena.departments;

插入表记录

  • 不知定列名插入记录
  • 制定列名插入记录

常用格式1

给所有表头赋值 值必须与表头的数据类型匹配

inert into 库. 表 values (表头值列表);

intert into 库. 表 values (表头值列表),(表头值列表); 一次添加多行

常用格式2

仅给指定的表头赋值,没有赋值的标头是有默认值或自增长赋值

insert into

  1. 使用set进行赋值
mysql> insert into user values (30,'dc','x',666,666,'testuser','/home/dc','/sbin/nologin');

mysql> select * from user where id=30;

# 指定字段赋值
mysql> insert into user(name,id) values("john",888);

mysql> insert into user(name,uid) values("john1",888);

mysql> select * from user where uid=888;

# 使用查询结果存进记录
mysql> select name from user where shell = '/sbin/halt';

mysql> insert into user(name) (select name from user where shell = '/sbin/halt') ;
mysql> select name from user where name = 'halt';

# 使用set进行赋值
mysql> insert  into user set  name = 'dachui'  ,uid = 999;

mysql> select * from user where name = 'dachui';


修改表中记录

格式1

update 库. 表 set 字段名= 值,字段名= 值… where 筛选条件; 只修改符合条件的字段

类型匹配才能允许修改

格式2

update 库. 表 set 字段名= 值 ;批量修改

mysql> select name,comment,password from user where name="root";

mysql> update user set comment='admin user',password='a' where name ='root';

mysql> select name,comment,password from user where name="root";

mysql> update user set password= 'F';

mysql> select id,password from user ;

删除表中记录

格式1:

delete from 库.表 where 筛选条件 ; 仅删除表中与条件匹配的行

格式2

delete from 库.表 ; # 谨慎,会将表中所有的数据删除

mysql> select * from user where shell is null ;  # 删除前查看

mysql> delete from user where shell is null ;

mysql> select * from user where shell is null ;  # 删除后查看

delete from user;  # 慎用,删除所有的行

数据类型

每种类型都有规定好的命令表示

​ 比如字符类型char

mysql服务常用数据类型有;

​ 数值类型 如 身高 体重 成绩

​ 字符类型 如 地址 籍贯 姓名

​ 枚举类型 如 爱好 性别 婚姻状况 (列举出来,给你选择的类型)set (多选) enum(单选)

​ 日期时间类型 如 生日 上课时间 入职时间

数值类型

整数类型
  • 仅存储数值的整数部分
浮点类型
  • 存储有小数点的数
类型 名称 有符号类型 无符号类型
tinyint 微小整数 -128~127 0~255
smallint 小整数 -32768~32767 0~65535
medliumint 中整数 -223~223-1 0~2^24-1
int 大整数 -231~231-1 0~2^32-1
bigint 极大整数 -263~263-1 0~2^32-1
unsigned 使用无符号存储范围
create table t3(姓名 char(10), 年龄 tinyint unsigned,  工资 float,  圆周率 double , 游戏级别 smallint);

mysql> desc t3;# 第二个值出现了负值,就出现错误了,因为表结构写了是正整数
mysql> insert into t3 values ("jim",256,205555.88,301415426, -1);# 在范围内,所以不会报错
mysql> insert into t3 values ("jim",25,205555.88,301415426, -1);



不能存负数的效果

mysql> desc t3;
mysql> insert into t3(姓名,年龄) values ('jon',-1);
mysql> insert into t3(姓名,年龄) values ('jon',0);

小数可以存整数和小数

整数只能存整数(四舍五入)

mysql> insert into t3(姓名,年龄,工资)  values ('tom',19.5,55555 );
 
 mysql> select * from t3 where 姓名= 'tom';

字符类型

表头下存储英文字母 或 汉字

常用的字符类型有:

定长类型 char 最多存储255个字符,不写的话是默认4

变长类型 varchar 最多存储65532个字符 不写()的话,出现语法错误

定长:超出的话,报错,不够的话系统自动以空格补齐

变长:也是不能超出,长度是变化的,是根据存储的数量而定,不会补齐

mysql> create table t4(姓名 varchar(10), 班级 char(7)  ,电话号码 char(11)   ,邮箱 varchar(30) )default charset utf8;

mysql> desc t4;

# 没加引号
mysql> insert into t4 values('沙调',nsd2110,122212112,[email protected]);

mysql> insert into t4 values('沙调','nsd2110','122212112','[email protected]');

mysql> select * from t4;

其他字符类型 比如 大文本 二进制….

常用字符类型
  • 用来存储如:姓名、收货地址、工作单位、家庭地址、、
其他字符类型
  • 通常用来存储视频、音频、图片、较大的文件。
  • 使用说明
    • 日期时间类型
    • year类型
    • 可以使用时间函数给日期时间类型的字段赋值

日期类型

  • 存储如 生日、注册时间、出生年份、入职日期

年 year 赋值 YYYY 例如 2022

日期 date 赋值YYYYMMDD 例如20220209

时间 time 赋值HHMMSS 例如223000 晚上十点半

日期时间 datetime 或 timestanp 赋值YYYYMMDDHHMMSS 例如20220209091618

# 创建表
mysql> create table studb.t1(name char(10),birthday date , work time , party datetime);

mysql> desc studb.t1;

mysql> alter table studb.t1 add start year after name;

mysql> insert into studb.t1 values("ds",20221120,090000,20220218183000);

mysql> desc studb.t1;

mysql> select * from studb.t1;

mysql> update studb.t1 set start = 2000 where name = 'ds';

mysql> select * from studb.t1
    -> ;

year 数据类型的表头 可以使用2位数赋值,但是会自动补全4位数

01~69 2001-2069

70~99 1970-1999

mysql> insert into studb.t1(name,start) values ('jim',52);

mysql> select * from studb.t1 where name = 'jim';

mysql> insert into t1(name,start) values('hh',99);

mysql> select * from t1 where name = 'hh';

datetime 和 timestanp区别
  1. 存储范围不一样
  2. 赋值方式不同
mysql> create table t2(开会时间 datetime , 聚会时间 timestamp);
mysql> insert into t2 values(20220209183000,20220212203000);
mysql> select * from t2;
# 没给timestamp赋值的话,会默认写入数据库系统时间去复制
mysql> insert into t2(开会时间) values(20180209183000);
mysql> select * from t2 ;
# 每给datetime赋值的话是NULL
mysql> insert into t2(聚会时间) values(20180202213000);
mysql> select * from t2;

枚举类型

  • enum类型
    • 单选 (字段值仅能在范围内选择1个值)
  • set类型
    • 多选 (字段值仅能在范围内选择1个或多个值)

数据的导入导出

对数据做批量处理

数据导入

把系统文件的内容存储到数据库的表里

文件的必须是有规律的

数据导入的命令格式

load data infile ‘/目录名/文件名’ into table 库.表

fileds terminated by “符号(表头的间隔符号)”

lines terminated by “符号(行的间隔符号)” ;

在mysql登录状态先执行系统命令

system cp /etc/passwd /myload

# 先将文件复制到/myload目录下面
mysql> load data infile "/myload/passwd" into table studb.user
    -> fields  terminated by ":" lines  terminated by "\n";

mysql> select * from studb.user ;

练习:

将/etc/passwd文件的内容存储到studb.user表里

create table user(
用户名 varchar(20),
密码 char(1),
uid  int,
gid  int,
说明信息 varchar(150),
家目录  varchar(100),
shell varchar(30)
);

mysql> desc user;

操作步骤:

  1. 创建存储数据的库和表(其中表头要根据文件的内容创建)
  2. 把系统文件拷贝的mysql服务要求的目录下
  3. 导入数据
  4. 查看表记录

检索目录(导入导出存放文件的目录)

  • 查看默认要求的检索目录
mysql> show variables like "%file%";

mysql> show variables like "secure_file_priv";

[root@mysql1 ~]# ls /var/lib/mysql-files/
[root@mysql1 ~]# ll -d /var/lib/mysql-files/
drwxr-x--- 2 mysql mysql 6 11月 29 2016 /var/lib/mysql-files/


  • 自定义检索目录(修改检索目录)
[root@mysql1 ~]# vim /etc/my.cnf
[mysqld]
secure_file_priv=/myload  # 手动添加
#skip-grant-tables
validate_password_policy=0
validate_password_length=6

[root@mysql1 ~]# mkdir /myload
[root@mysql1 ~]# ls /myload/
# 使得mysql能有多这个文件有操作的能力
[root@mysql1 ~]# chown -R  mysql:mysql /myload  
# selinux 必须关闭
[root@mysql1 ~]# setenforce 0  
setenforce: SELinux is disabled
[root@mysql1 ~]# systemctl restart mysqld
# 如果重启失败:配置文件可能写错,目录没有权限

# 再次登陆查看就可以看到文件已经修改了;说明修改成功
mysql> show variables like "secure_file_priv";

数据导出

把数据库表里 存储到系统文件

说明

文件名不需要创建 会自动创建文件并存储数据文件名具有唯一性

导出数据的内容,由select命令决定

导出的只有内容,没有表头名

表里1条的记录 就是文件里的1行

  • 命令格式1
    • seletc 查询命令 into outfile ‘/检索目录/文件名’;(文件名是不需要事先创建的,导出的时候会自动创建的,自定义文件名,文件名具有唯一性)
  • 命令格式2
    • select查询命令 into outfile ‘/检索目录/文件名’ fields terminated by ‘符号’
  • 命令格式3
    • elect查询命令 into outfile ‘/检索目录/文件名’ fields terminated by ‘符号’ lines terminated by ‘符号’ ;
# 格式1
mysql> select name ,hire_date,birth_date from tarena.employees limit 3;

mysql> select name ,hire_date,birth_date from tarena.employees limit 3  into outfile
    -> "/myload/employees.text" ;

mysql> system cat /myload/employees.text
梁伟	2018-06-21	1971-08-19
郭岩	2010-03-21	1974-05-13
李玉英	2012-01-19	1974-01-25

# 格式2
mysql> select name ,hire_date,birth_date from tarena.employees limit 3
    -> into outfile "/myload/employees.text1" fields terminated by ":";
Query OK, 3 rows affected (0.00 sec)

mysql> system cat /myload/employees.text1
梁伟:2018-06-21:1971-08-19
郭岩:2010-03-21:1974-05-13
李玉英:2012-01-19:1974-01-25

# 格式3
mysql> select name ,hire_date,birth_date from tarena.employees limit 3
    -> into outfile "/myload/employees.text2"
    -> fields terminated by ":"
    -> lines terminated by "\t";

mysql> system cat /myload/employees.text2
梁伟:2018-06-21:1971-08-19	郭岩:2010-03-21:1974-05-13	李玉英:2012-01-19:1974-01-25	

字段约束

  • 约束是一种限制,设置在字段上,用来控制字段的赋值
    • primary key :主键 ,用来版中呢过该字段的值具有唯一性并非空
    • not null :非空,用来保证该字段的值不能为空
    • default:默认值,用来保证该字段有默认值
    • unique: 唯一索引,用来保证该字段的值具有唯一性,可以为空
    • foreign key :外键,用来限制两个表的关系,用来保证该字段的值必须来自于主表的关联列的值,在从表添加外键约束,用于应用主表某些的值

所用;限制如下给表头存储数据

查看字段约束: desc 库.表;输出结果的后4列统称为约束字段

mysql> desc user;

NULL :空 

Key:键值

default:默认值

Extra:额外设置

基本的字段约束

  1. 不允许给表头存储null(默认是允许的)

    • create table t5(name char(10) not null ,class char(7));

    • mysql> create table t5(name char(10) not null ,class char(7));
      mysql> desc t5;
      
      # name添加的时候就不能再设置为空值了
      mysql> insert into t5 values(null.null);
      
      # 只有class可以为null
      mysql> insert into t5 values ("ii",null);
      
      
      
  2. 给表头设置默认

    • 什么是默认值 添加记录时 不给表头存储数据 使用默认值赋值

    • 默认值要与表头的数据类型一致

    • mysql> create table t6(name char(3) not null , class char(7) default'nsd2110',sex enum('w','m') not null default 'm');
      
      mysql> desc t6;
      
      
    • mysql> insert into t6(name) values ('jj');
      
      mysql> select * from t6;
      
      
    • mysql> insert into t6 values ('hh',"nn111","w");
       
      mysql> select * from t6 where name = 'hh';
      
      
  3. 唯一索引 unique

    • 所用:表头下的数据不能重复

    • 例如:身份证号码 、护照号、证书编号

    • 所有存放证件信息的数据都是不能重复

    • mysql> create table t7(
          -> 学号 char(9),name char(10),age tinyint unsigned default 21,unique(学号));
      
      mysql> desc t7;
      
      # unsigned 表示无字符
      
    • mysql> insert into t7 values("nsd211011","jim",29);
      
      # 学号是唯一索引,不允许重复,所以会报错。
      mysql> insert into t7 values("nsd211011","tom",19);
      
      # 空不算重复,没有数据不涉及到重复
      
      
 
4. 主键 primary ley 

 - 表头下的数据 即不能重复  也不能允许赋予null值

 - ```mysql
   mysql> create table t8(
       -> 身份证  char(18),
       -> 姓名 char(4),primary key(身份证)
       -> );
   # 没有设置not null 设置了primary key,自动设置为不能为null
   # 主要是有key PRI 都是不能允许重复,也不允许赋予null值
   mysql> desc t8;
   

  • mysql> insert into t8 values('888','jim');
    # 不能重复
    mysql> insert into t8 values('888','tom');
    # 不能为空
    
mysql> insert into t8 values(null,'hh');
 
 ```
   
   
   
 - 删除主键
 
   ```mysql
   mysql> desc t8;
   
   mysql> alter table t8 drop primary key;
   # 删除主键之后就可以插入相同的'身份证‘记录
   mysql> insert into t8 values('888','dsa');

  • 给表头添加主键约束(表头下存储的数据不满组主键时 主键添加不上)就是如果有重复或者是为空的表头值 就添加不上primary key

    mysql> alter table t8 add primary key(身份证);
    
    解决方案是删除或者修改记录
    
    
  1. 复合主键

    • 什么是复合主键:多个表头一起做主键

    • 约束的方式 :不允许复合主键表头的值同时重复

    • mysql> create table t9(ip varchar(15) ,prot int ,status enum("allow","deny"),primary key(ip,prot));
      
      mysql> desc t9;
      
      
      mysql> insert into t9 values('1111',22,'deny');
      
      mysql> insert into t9 values ('2111',22,'allow');
      
      mysql> insert into t9 values('2111',80,'allow');
      mysql> select * from t9;
      
      
      
    • 删除表的复合主键

    mysql> alter table t9 drop primary key;
    
    mysql> desc t9;
    
    
    • 删除复合主键

    • mysql> alter table t9 add primary key(ip,prot);
      
      mysql> desc t9 ;
      
      
    
    
  2. 主键与auto_increment 连用

    • auto_increment的作用: 不给表头赋值时候 是自加1 的计算结果给表头赋值

    • 注意:给表头加auto_increment设置,表头的数据类型必须是数值类型的

    • mysql> create table t10(id int primary key auto_increment, name char(10),age int ,class char(7),socr int );
      
      mysql> desc t10;
      
      
      mysql> insert into t10 (name ,age ,class ,socr) values ('a',19,'2111',93); 
      mysql> select * from t10;
      
      mysql> insert into t10 (name ,age ,class ,socr)  values ('b',12,'123',456);
      
      mysql> select * from t10 ;
      
      
    • 自增长的扩展

      mysql> truncate t10;
      
      mysql> select * from t10 ;
      
      mysql> insert into t10 (name ,age ,class ,socr)  values ('b',12,'123',456);
      
      mysql> select * from t10;
      
      
      # truncate 不支持where条件
      # 自增长列,truncate后从1开始;delete继续编号(继上次的编号)
      # truncate不能回滚,delete可以
      # 效率略高于delete
      
    • 复制表 不会复制 主键和 自增长的

主键

  • 使用规则
    • 字段值不允许重复,且不允许赋予NULL值
    • 一个表中只能有一个primary key字段
    • 多个字段都作为主键,成为复合主键,必须一起创建
    • 主键字段的标志是PRI
    • 主键通常与auto_increment 连用
    • 通常把表中唯一标识记录的字段设置为逐渐[记录编号]

外键

  • 使用规则

    • 作用
      • 插入记录时,字段值在另一个表字段值范围内选择
      • 给外键 表头存储数据时 要在外键要求的数据范围内才可以
  • 使用规则

    • 表存储引擎必须是innodb
    • 字段类型要一致
    • 被参考表头的值要有唯一性
    • 被参照字段必须要是索引类新您过的一种(primary key)
  • 创建外键

    • 命令格式

    • create table 库.表 (表头名列表, foreign key(表头名) references 库名.表名(表头名)

      on update cascade on delete cascade

      ) engine=innodb;

      on update cascade : 同步更新

      on delete cascade: 同步删除

# 在员工表中没有199的id,所以添加不上,因为外键限制了
mysql> insert into salary (date,employee_id ,basic ,bonus)
    -> values 
    -> (20220809,199,30000,2000);

mysql> insert into salary (date,employee_id ,basic ,bonus)
    -> values 
    -> (20220809,8,30000,2000);


mysql> desc salary;

mysql> create table yg_tab(yg_id int primary key  auto_increment,name char(5))engine=innodb;

mysql> insert into yg_tab(name) values ('dc'),('hh');

mysql> select * from yg_tab;


mysql> desc yg_tab;

mysql> create table gz_tab(gz_id int ,pay int,foreign key(gz_id) references yg_tab(yg_id) on update cascade  on delete cascade )engine=innodb;

mysql> desc gz_tab;

验证外键的

mysql> select * from yg_tab;
# 在里面没有3 的编号 # 在外键表头名添加数据的时候必须要符合
mysql> insert into gz_tab values (3,3000);

# 在符合外键的要求之下就可以添加了。
mysql> insert into gz_tab values (1,121313);

mysql> select * from gz_tab;

mysql> insert into yg_tab(name) values ('lili');

mysql> select * from yg_tab ;

mysql> insert gz_tab values (3,456);

mysql> select * from gz_tab;

验证 on update cascade

mysql> update yg_tab set yg_id = 8 where yg_id = 3;

mysql> select * from yg_tab;

# 由于添加了on update cascade 所以在修改yg_tab的时候gz_tab也会自动修改
mysql> select * from gz_tab;


验证 on delete cascade

mysql> delete from  yg_tab  where yg_id=2;
mysql> select * from yg_tab;

mysql> select * from gz_tab;

外键的使用扩展

mysql> alter table gz_tab add primary key(gz_id);

mysql> desc gz_tab;

# 设置主键之后避免出现重复发工资

查看外键

mysql> show create table gz_tab \G

删除外键

mysql> alter table gz_tab drop foreign key gz_tab_ibfk_1;
# 删除外键之后就没有了 gz_tab_ibfk_1
mysql> show create table gz_tab \G

添加外键

mysql> alter table gz_tab add foreign key(gz_id)
    -> references yg_tab(yg_id)
    -> on update cascade on delete cascade ;

mysql> show create table gz_tab \G
*************************** 1. row ***************************

mysql索引

  • 表里的行比较少或表里的列有重复数据的时候不建议使用

  • 经常修改表的话,也不建议使用索引,这会大大降低服务器的性能

什么是索引(类似书的目录)
  • 给表头下存储的数据生成排队信息保存到表对应的文件里
  • 是帮助Mysql搞笑获取数据的数据结构
  • 为快速查找数据而排好序的一种数据结构
  • 类似书的目录
  • 可以用来快书查询表中的特定记录,所有的数据类型都可以被索引
  • Mysql索引主要有三种结构:Btee、B+Tree、Hash
索引的优点和缺点
  • 优点
    • 加快查询数据的速度

    • 具体操作

      • 可以大大提高Mysql的检索速度
      • 索引大大减少了服务器需要扫描的数据量
      • 索引可以帮助服务器避免排序和临时表
      • 索引可以随机10变成10
  • 缺点
    • 会占用物理磁盘空间,会影响对数据做写操作(insert update delete) 的速度
    • 具体操作
      • 虽然索引大大提高查询速度,同时却会降低更新表的速度,如对表进行insert update delete 。因为更新表时,Mysql不仅要保存数据,还要保存索引文件
      • 建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。
      • 如果某个数据列包含许多重复的内容,为他建立索引就没有太大的实际效果。
      • 对于非常小的表,大部分情况下简单的全表扫描更高效

索引类型

  • 普通索引(index):工作中使用最多

    • 任何数据类型的表头都可以用普通索引生成排队信息
    • 不应用任何限制条件的索引,该索引可以在任何数据类型中创建
    • 字段本身的约束条件可以判断其值是否为空或唯一
    • 创建该类型索引后,用户在查询时,便可以通过索引进行查询
    • 使用规则
      • 一个表中可以有多个index
      • 字段的值可以重复,且可以赋值为null
      • 通常在where条件中的字段上配置index
      • index索引字段的标志为mul
  • 唯一索引

    • 唯一索引 和 主键 (也是索引的一种)给表头生成排队信息
    • 使用UNIQUE参数可以设置唯一索引
    • 创建该索引时,索引的值必须是唯一
    • 通过唯一索引,用户可以快速定位某条记录
    • 主键是一种特殊唯一索引
      • 与普通索引的区别:
        • 普通索引对数据的存储没有任何约束限制
  • 全文索引 fulltext

    • 只能设置在 字符类型的表头上
    • 使用FULLTEXT参数可以设置索引为全文索引
    • 全文索引只能创建CHAR、VARCHAR或者TEXT类型的字段上。查询数据量较大的字符串类型的字段时,使用全文索引可以提高查询速度
    • 在默认情况下,应用全文搜索大小写不敏感。如果索引的列使用二进制排序后,可以执行大小写敏感的全文索引
  • 单列索引

    • 只给表中的一个表头生成排列信息 index(name )
    • 顾名思义,单列索引即只对应一个字段的索引
    • 应用该索引的条件只需要保证该索引值对应一个字段即可
    • 可以包括普通、唯一、全文索引
  • 多列索引

    • 多个表头一起生成排列信息 index(name ,age ,class)
    • 多列索引是在表的多个字段上创建一个索引
    • 该索引指向创建时对应的多个字段,用户可以通过这个几个字段进行查询
    • 要想应用该查询,用户必须使用这些字段中的第一个字段

索引的使用

  • 查看 desc 库.表 ;

    • 输出的信息中key列的值是MUI

    • mysql> desc tarena.employees;
      
      # 查看表里的索引
      mysql> show index from tarena.employees \G
      
      
      
  • 创建

    • 建表时给表设置排队索引

      mysql> create table t1(name char(10) ,class char(11), addr char(20),age int ,index(name),index(addr));
      
      mysql> show index from t1 \G
      
      
      
  • 删除

    • d

      mysql> drop index name on t1 ;
      
      mysql> desc t1;
      
      
  • 添加

    • 添加索引

      mysql> create index name on t1(name);
      
      mysql> desc t1;
      
      mysql> create index iiii on t1(age);
      
      mysql> desc t1;
      
      
      mysql> show index from t1 \G 
      
      # Key_name : 表头的索引名
      # Column_name : 这个是表头名
      
    • 外键没有去掉,是删除不了索引

验证索引的功能

  • 通常把做查询条件的表头 添加索引标记 可以加快查询数据的速度

    • mysql> select * from user where 用户名 = 'halt';
      
      mysql> 这个是从第一行开始找^C
      mysql> 想知道是怎么查的,知道怎么查的在命令面前加上explain^C
      mysql> explain select * from user where 用户名 = 'halt';
      # 得知搜索了22行的数据
      # Using where 是使用了where命令查找了表里记录
      
    • 添加了索引之后

      mysql> create index 用户名 on user(用户名);
      
      # 添加索引之后再次查找的话先去找索引,再去找表里的记录,类似与书的目录。
      
      mysql> explain select * from user where 用户名 = 'halt';
      
      # rows 这里就是直接在表里查找的多少行
      
    • explain可以检查查询有没有使用到索引,具体有没有使用索引看keys下面有没有索引名称

    • 生成排队信息的是查询的时候先访问排队文件中先去找,不是在表中直接找

Mysql用户管理

用户授权
  • 说明

    • 授权就是在数据库服务器上添加用户并设置权限及密码
    • 重复执行grant命令时如果库名和用户名不变时,是追加权限
    • with grant option 授权权限可选的项目
  • 语法格式

  • 添加新用户的命令格式

    • create user 用户名@“客户端地址” indentified by ”密码“ with grant option ;

    • mysql> create user zhangsan@'%' identified by '123456';
      
      mysql -h192.168.4.50 -uzhangsan -p123456
      
      mysql> select user();  # 查看远程登录的用户
      
      mysql> select user();
      
      
  • 授权命令格式:

    • 格式1(创建用户并设置权限)

      grant 权限列表 on 数据库名 to 用户名 @“客户端地址” identified by “密码” with grant option

    • 格式2

      grant 权限列表 on 数据库名 to 用户名 @“客户端地址”

    # 查看所有的权限
    mysql> show grants;  
    
    # 给zhangsan用户添加select权限对tarena.user的操作
    mysql> grant user on studb to zhangsan@'%' identified by '123456'^C
    mysql> grant select on tarena.user to zhangsan@'%';
    
    
    

    mysql> grant all on . to yaya@‘192.168.4.%’ identified by ‘123456’ with grant option ;
    Query OK, 0 rows affected, 1 warning (0.00 sec)

    
    
  • 参数说明

    • 权限表示方式
      • all # 所有权限
      • usage # 无权限
      • select , update ,insert # 个别权限
      • select , update (字段1,字段N) # 指定字段
    • 库名
      • *. * # 所有裤的所有表
      • 库名.* # 一个库
      • 库名.表名 # 一张表
    • 用户名
      • 授权时自定义 要有标识性
      • 存储在mysql库的user表里
    • 客户端地址
      • % # 所有主机
      • 192.168.4.% # 网段内的所有主机
      • 192.168.4.1 # 1台主机
      • localhost # 数据库服务器本机
  • 权限说明

  • 授权库(指的是mysql库)

  • grant命令 的执行对mysql下面的表的操作

    • mysql库 存储用户权限信息,主要表如下:
      • user 表 记录已有的授权用户的权限
      • db表 记录已有授权用户对数据库的访问权限
      • tables_priv表 记录已有授权用户对表的访问权限
      • columns_priv表 记录已有授权用户对字段的访问权限
    • 查看表记录可以获取用户访问权限:
    • 也可以更新记录达到修改用户权限的目的(就是修改类似于grant)
例子
grant select,update(name,uid) on studb.user to hh@'localhost' identified by '123456';
select 是对所有表头都有查询的权限
update 只对name,uid 有修改的权限

select * from mysql.tables_priv
desc mysql.tables_priv 
select host,user,db,table-name from mysql.tables_priv
select * from mysql.tables_priv where user = hh;
desc mysql.columns_priv
select * from msyql.columns_priv where user = hh;

show grants for hh@'localhost';
update mysql.tables_priv set Tables_priv = "select,delete" where user = 'hh';
flush privileges;
show grants for hh@'localhost';


update mysql.columns_priv set Column_name = "name"  where user = 'hh';
flush privileges;
show grants for hh@'localhost'




查看用户权限

mysql> select host ,user from mysql.user;

# 查看用户的密码

mysql> select host,user ,authentication_string from mysql.user;

修改已经添加的用户密码
mysql> set password for admin@'192.168.4.51'=password("NSD2110...a");
Query OK, 0 rows affected, 1 warning (0.00 sec)

# 修改之后也是以加密的方式存储进mysql.user里面
查看已有用户的权限
mysql> show grants for zhangsan@'%';

测试with grant option

在设置有这个命令的用户下面,创建可以创建用户,最大权限是创建主的最大权限

授权的扩展
  • 不是说有使用with grant option就有添加用户的权限,因为添加用户是存储到mysql库的
  • 追加权限的方式的,用户名和客户端一样才是可以追加,不一样的话需要设置密码是设置了新的用户了

撤销权限(就是删除已有的用户权限)

  • 语法格式

    • 注意:
      • 删除已有授权用户的权限
      • 库名必须和授权时的表示方式一样
    • 语法
      • revoke 权限列表 on 库名 from 用户名@’客户端地址‘;
    • 实例
  • 相关命令

    命令 作用
    select user(); 显示登录用户名及客户端地址
    show grants; 用户显示自身访问权限
    show grants for 用户名@’客户端地址‘; 管理员查看已有授权用户权限
    set password=password(“密码”); 授权用户连接后修改连接密码
    set password for 用户名@“客户端地址” = password(“密码”); 管理员重置授权用户连接密码
    drop user 用户名@’客户端地址‘; 删除授权用户(必须有管理员权限)
    rename user 原用户名 to 新用户名 修改用户名

删除用户

  • 命令格式
    • drop user 用户名@’客户端‘;

基础查询进阶

常用函数

函数介绍
  • 介绍
    • Mysql服务内置的命令
    • 语法 : 函数名(字段名)
  • 实例
    • select 函数(字段名) from 库名.表名字;
    • select 函数(字段名) from 库名.表名字 where 条件;
mysql> select user();

mysql> select now();

password()
这个函数就要添加参数了eg:password('aaa')



函数查询的基本格式

select 函数(字段名) from 库名

字符函数
  • 作用:处理字符或字符类型的字段

    • 函数名称 说明
      length(str) 返回字符串长度,以字节为单位
      char_length(str) 返回字符串长度,以字母为单位
      upper(str)和ucase(str) 将字符串中的字母全部换成大写
      lower(str)和 lcase(str) 将str中的字母全部换成小写
      substr(s,start,end) 从s的start位置开始取出到end长度的字串
      instr(str,str1) 返回str1参数,在str参数内的位置
      trim(s) 返回字符串s删除了两边空格之后的字符串
    • select name,length(name),stubstr(name,1,1),instr(name,’a’) from tarena.user where name regexp ‘a’;

数学函数
  • 作用:处理数据或数据类型的字段

    • 函数名 说明
      abs(x) 返回x的绝对值
      pi() 返回圆周率,默认显示6位小数
      mod(x,y) 返回x被y除后的余数
      gril(x)、ceiling(x) 返回不小于x的最小整数(x是小数)
      floor(x) 返回不大于x的最大整数(x是小数)
      round(x) 返回最接近于x的整数,即对x进行四舍五入(x是小数)
      round(x,y) 返回最接近x的数,其值保留小数点后面y位,若y为负值,则将保留到x到小数点左边y位(x是小数)
    • select name ,uid from tarena.user where mod(uid,2)=0;

聚集函数
  • 作用:数据统计命令

    • 函数名 说明
      avg(字段名) 计算平均值
      sum(字段名) 求和
      min(字段名) 获取最小值
      max(字段名) 获取最大值
      count(字段名) 统计字段值个数
    • select count(*) from tarena.user;

数学计算
  • 作用: 对行中的列做计算

符号 用途
+ 加法
- 减法
* 乘法
/ 除法
% 取余数(求模)
() 提高优先级

select name ,uid ,uid+1,gid,uid+gid,(uid+gid) from tarena.user where id%2 !=0;

日期函数
  • 作用:获取系统或指定的时间与日期

    • 函数 说明 函数 说明
      curtime() 获取时间 hour() 获取小时
      curdate() 获取日期 minute() 获取分钟
      now() 获取时间和日期 second() 获取秒
      year() 获取年 quarter() 获取一年中第几个季度
      month() 获取月 monthname() 获取月份名称
      day()/week() 获取日/一年中的第几周 datname() 获取日期对应的星期名
      date()/weekday() 获取日期/一周中的周几 dayofyear() 获取一年中第几天
      time() 获取时间 dayofmonth() 获取一月中第几天

流程控制函数

if函数

  • 语法:

    • if(条件1,v1,v2) 如果条件是true则返回v1,否则返回v2

    • ifnull(v1,v2) 如果v1不为null,则返回v1,否则返回v2

      • select name,uid,if(uid<1000,”系统用户“,”创建用户“) from tarena.user

      • select name,shell,if(shell=“/bin/bash”,”交互账号”,”非交互账号”) from tarena.user;

      • insert into tarena.user(name,homedir) values(“bob”,”NULL);

        select name 姓名 ,ifnull(homedir,”no home”) as 家目录 from tarena.user;

  • 例子

    mysql> select  ifnull(null,"abc");
    
    mysql> select ifnull("abc","aaa");
    
    mysql> select name ,ifnull(shell,"NULL") from user;
    

case函数

  • 语法;如果字段名等于某个值,则返回对应位置then后面的结果,如果与所有值都不相等,则返回else后面的结果

  • 是if()函数扩展 case可以有多个判断

    • case 字段名
      when 值1 then 结果
      when 值2 then 结果
      when 值3 then 结果
      else  结果
      end
      
    
- 例子
  
    ```mysql
    mysql> select name ,shell,
        -> case shell
        -> when "/bin/bash" then "yes login"
        -> when "/sbin/nologin" then "no login"
        -> else "other shell"
        -> end as 登录类型
        -> from tarena.user ;
    +-----------------+----------------+--------------+
    | name            | shell          | 登录类型     |
    +-----------------+----------------+--------------+
    | root            | /bin/bash      | yes login    |
    | bin             | /sbin/nologin  | no login     |
    | daemon          | /sbin/nologin  | no login     |
    | rpcuser         | /sbin/nologin  | no login     |
    | nfsnobody       | /sbin/nologin  | no login     |
    | haproxy         | /sbin/nologin  | no login     |
    +-----------------+----------------+--------------+
    23 rows in set (0.01 sec)
    
    mysql> select dept_name ,case dept_name 
        -> when "运维部" then "技术部门"
        -> when "开发部" then "技术部门"
        -> when "测试部" then "技术部门"
        -> else "非技术部门"
        -> end as 部门类型
        -> from departments;
    # 格式2
    select dept_name ,case 
    when dept_name="运维部" then "技术部门"
    when dept_name="开发部" then "技术部门"
    when dept_name="测试部" then "技术部门"
     else "非技术部门"
     end as 部门类型
     from departments;

查询结果处理

介绍

  • 说明:对select语句查找到的数据再做处理
  • 语法
    • select 字段名列表 from 库.表 【where 条件】 分组 | 排序 | 过滤| 分页;

分组

  • 语法:

    • select 字段1 (要求出现在group by 后面) ,分组函数(),。。 from 表名 where 条件 group by 字段1,字段2;
  • 说明:

    • 查询列表必须是分组函数和出现在group by 后面的字段
    • 字段中值相同的为一组
    • 分组后的数据筛选放在having字句中 分组前使用where
    • 通常单独使用 或与聚集函数一起使用 分组的表头必须在select 擦和讯表头列表里
  • 例子

    # 会报错
    select name ,shell from user group by shell ;  # 没有单独使用
    select name from user group by shell;  # 没有单独使用,搜索的字段没有在组里
    
    # 单独使用,或与聚集函数一起使用
    select count(name ) ,shell from user group by shell ;
    select shell from user group by shell ;
    
    # 使用每种shell 的用户有几个
    select count(name) ,dept_id from employees where dept_id = 1 group by dept_id ;
    select count(name) ,dept_id from employees  group by dept_id having dept_id = 1 ;
    select count(name) ,dept_id from employees group by dept_id limit 1;
    

排序

  • 语法:

    • select 语句 order by字段名 【asc|desc】

    • asc 升序排序(默认)

      desc 降序排序

    • 表头 是数据类型的表头

  • 例子:

    select name ,uid from user where uid between 10 and 100 order by uid ;
    
    select name ,uid from user where uid between 10 and 100 order by uid desc ;
    

过滤

  • 作用:对查询到的数据做筛选

  • 语句:sql语句 having 条件;

  • 在select命令 查询结果里再查找符合条件的数据

  • 例子

    select * from salary where basic between 21000 and 30000 having employee_id = 7 limit 5;
    
    select * from salary where basic between 21000 and 30000 having employee_id = 7;
    
    

分页

  • 作用:限制查询结果显示行数(默认显示全部的查询结果)

  • 语法:

    • select 语句 limit 数字 //显示查询结果前多少条记录
    • select 语句 limit 数字1 ,数字2 //显示指定范围内的查询记录
      • 数字1 起始行(0表示第1行)
      • 数字2 总行数
  • 例子

    select name ,uid from user where uid between 10 and 100 limit 4;
    
     select name ,uid from user where uid between 10 and 100 limit 0,10;
    
    select name,uid from user where uid between 10 and 100 order by uid limit 1 ;
    

连接查询

概述

连接查询介绍
  • 连接查询也叫多表查询 常用与查询字段来自于多张表
  • 通过不同连接方式把多张表重新组成一张新表对数据做处理
  • 如果直接查询两张表,将会得到笛卡尔积(表中行数相乘的积,就是查询结果的总行数)
  • 通过添加有效的条件可以尽心查询结果的限定
  • 笛卡尔积(表中行数相乘的积,就是查询结果的总行数),如何加了条件,只显示符合条件的行
连接查询分类
  • 按功能分类

    • 内连接 inner join
    • 外连接 left|right join
    • 交叉连接
  • 按年代分类

    • SQL92标准:支持内连接

    • SQL99标准;支持所功能的连接

      • SQL99标准多表查询

        select 字段列表

        from 表1【as】 别名 【连接类型】

        join 表2 【as】 别名

        on 连接条件

        where 分组前筛选条件

        group by 分组

        having 分组后筛选条件

        order by 排序字段

连接查询时候给表头起别名

不知道显示那个表里dept_id 表头是那个表的值的时候

内连接

  • 语法格式 : inner join …on…

    select 字段列表
    from1  别名
    inner  join2  别名  on  连接条件
    inner  join3  别名  on  连接条件
    【where   筛选条件】
    【group  by  分组】
    【having  分组后筛选】
    【order  by 排序列表】
    
  • 根据筛选条件分类:

    • 等值连接
      • 使用相等判断做连接条件
    • 非等值连接
      • 连接条件不是相等判断
    • 自连接
      • 自己连接自己,把1张表当做2张表,需要给表定义别名
  • 例子

    -- 等值连接
    select name ,employee_id ,dept_name from employees a inner join departments b on a.dept_id = b.dept_id where employee_id =8;
    
    select name,basic+bonus,date from salary s inner join employees e on s.employee_id = e.employee_id where e.employee_id = 11 and year(date) = 2018;
    找出2018每个人的总工资的
    select e.employee_id ,sum(basic+bonus) 总工资 from employees e inner join salary s on e.employee_id = s.employee_id where year(date)=2018 group by employee_id order by employee_id limit 4;
     
     2018年总工资并且大于30万的员工
     输出的结果按照工资降序排序
     select e.employee_id ,sum(basic+bonus) 总工资 from employees e inner join salary s on e.employee_id = s.employee_id where year(date)=2018 group by e.employee_id having  总工资 > 300000 order by employee_id ;
     
     
     -- 非等值连接
     -- 环境准备
      create table wage_grade(id int primary key auto_increment,grade char(1) , low int , high int ) ;
      insert into wage_grade(grade ,low,high) values('A','5000',8000),('B',8001,10000),('C',10001,15000),('D',15001,20000),('E',20001,100000);
                                                     
    -- 查看2018年12月份员工基本工资级别
    select basic,grade,date  from salary  inner join wage_grade  on  basic between low and high where year(date) = 2018 and month(date) = 12;
    
    -- 查看2018年12月份基本工资级别的员工个数
    select count(employee_id),grade  from salary  inner join wage_grade  on  basic between low and high where year(date) = 2018 and month(date) = 12 group by grade;
    
    -- 查看2018年12员工基本工资级别,员工需要显示姓名
    select name,date ,basic ,grade from 
    employees e inner join salary  s on e.employee_id = s.employee_id
    inner join wage_grade g on s.basic between g.low and g.high
    where year(date) = 2018 and month(date) = 12 order by grade;
    
    -- 内连接(查看入职月份与生日的月份相同的)
    select a.name,a.hire_date ,b.birth_date from employees a inner join employees b on month(a.hire_date)=month(b.birth_date) and a.employee_id =b.employee_id;
    -- 不用内连接也可以查询
    select * from employees where month(hire_date)=month(birth_date);
    
    

外连接

  • 分类如下

    • 左外连接 left join
    • 右外连接 rigth join
    • 全外连接(mysql不支持,可以使用nuion实现相同的效果
    • 常用于查询一个表中有,而另外一个表中没有的记录
  • 例子

    -- 向部门里面添加3个部门 行政部 小卖部  公关部
    insert into departments(dept_name) values ('行政部'),('小卖部'),('公关部');
    -- 
    insert into employees(name) values ('bob'),('tom'),('lily');
    
    -- 把没有员工的部门名称输出
    select name,d.dept_id from employees e left join departments d on e.dept_id  = d.dept_id where d.dept_id is null;
    select d.*,e.name from employees e left join departments d on e.dept_id  = d.dept_id where d.dept_name is null ;
    select d.*,e.name from employees e right join departments d on e.dept_id  = d.dept_id where name is null ;
    select d.dept_name from employees e right join departments d on e.dept_id  = d.dept_id where name is null ;
    

左连接

  • 语法格式 表名 left join 表名 on 连接条件
  • 查询输出结果
    • 左表中的所有记录全显示
    • 右表只显示与条件匹配的记录,比左表少的记录使用NULL匹配

右连接

  • 语法格式 表名 right join 表名 on 连接条件
  • 查询输出结果
    • 右表中的所有记录全显示
    • 左表只显示与条件匹配的记录,比右表少的记录使用NULL匹配
select d.dept_name ,e.name from departments d left join employees e  on d.dept_id = e.dept_id ;
-- 仅仅是把没有的员工部门查找出来
select dept_name  from departments d left join employees e  on d.dept_id = e.dept_id where name is null;
-- 仅仅是把没有部门的员工名称打印出来
select name  from departments d right join employees e  on d.dept_id = e.dept_id where dept_name is null;



联合查询

  • 说明

    • 也称联合查询,用来合并查询结果
    • 可以合并同一中的表的查询记录(不同表的查询记录也可以合并)
    • 要求查询时,多个select语句的检索到的字段数量必须一致
    • 每一条记录的个字段类型和顺序最好是一致的
    • union关键字默认去重,可以使用union all 包含重复项
  • 语法格式

    • (sekect 语句) union (select 语句) ;
    • (sekect 语句) union all(select 语句 );
  • 例子

    select name ,birth_date from employees where year(birth_date)=1972 or year(birth_date ) >2000;
    
    (select name ,birth_date from employees where year(birth_date)=1972) union (select name ,birth_date from employees where year(birth_date ) >2000);
    
    select min(uid) from user;
    select max(uid) from user ;
    select min(uid),max(uid) from user ;
    (select min(uid) from user)union (select max(uid) from user);
    
    

交叉连接

  • 返回笛卡尔积(表记录行数相乘的积)
  • 语法格式
    • select [字段名] from 【表1】 cross join 【表2】 【where 字句】;

子查询

  • 也叫嵌套查询(俄罗斯套娃)

  • 通常是把内部查询语句的输出数据作为外层查询语句的查询条件

  • 介绍

    • 子查询:是指在一个完整的查询语句之中,潜逃若干个不同功能的小查询,从而一起完成复杂查询的一种编写形式
    • 简单的说就是在select查询语句了潜逃select查询语句
  • 子查询长出现的位置

    • select 之后
    • from 之后
    • where 或 having 之后
  • 命令格式

    • 子查询语句可以出现在select 命令之后
    • 子查询语句可以出现在from 命令之后
    • 子查询语句可以出现在where 命令之后
  • 例子

    -- 查询运维所有员工信息
    -- 分析 运功信息 只存储在employees表 但没有 部门名称 dept_name 表头 只有部门编号dept_id表头
    select dept_id from departments where dept_name = "运维部"
    select * from employees where dept_id =3 
    select * from  employees where dept_id = (select dept_id from departments where dept_name = '运维部') ;
    select * from  employees e inner join departments d on e.dept_id = d.dept_id where dept_name = "运维部";
    
    -- 查询2018年12月所有比100号员工基本工资高的工资信息
    -- 查询2018年12月 比100号员工基本工资高  工资信息
    year(date)= 2018 and month(date) = 12
    select * from salary 
    select basic from salary where year(date)= 2018 and month(date) = 12 and employee_id = 100;
    select employee_id,basic ,date from salary where year(date)= 2018 and month(date) = 12 and basic > (select basic from salary where year(date)= 2018 and month(date) = 12 and employee_id = 100);
    
    select name ,basic ,date from salary s inner join employees e on e.employee_id = s.employee_id where year(date)= 2018 and month(date) = 12 and basic > (select basic from salary where year(date)= 2018 and month(date) = 12 and employee_id = 100);
    
    -- 查询部门员工人数 比 开发部门人数少的部门
    -- 查找的部门员工人数 条件是 比开发部门人数少的
    select dept_id from departments where dept_name = '开发部'
    select count(name) from employees where dept_id = 4;
    select count(*) 人数,dept_id  from employees group by  dept_id  having count(name) < 6;
    -- 只查询出来少于开发部门的人数
    select count(*) 人数,dept_id  from employees group by  dept_id  having count(name) < (select count(name) from employees where dept_id = (select dept_id from departments where dept_name = '开发部'));
    -- 使用内连接加上限制部门名字
    select count(*) 人数,dept_name  from employees e inner join departments d on e.dept_id = d.dept_id  group by  e.dept_id  having count(name) < (select count(name) from employees where dept_id = (select dept_id from departments where dept_name = '开发部'));
    
    
    -- 查看每个部门的人数
    select count(*) 人数,dept_name  from employees e inner join departments d on e.dept_id = d.dept_id  group by  e.dept_id 
    
    -- 自己写的
    select count(employee_id)  from employees group by dept_id;
    select dept_name, (select count(employee_id)  from employees  e where d.dept_id = e.dept_id) r from departments d ;
    
    -- 课程写的
    select d.* ,(select count(employee_id)  from employees e where e.dept_id = d.dept_id)  总人数 from departments  d;
    
    
    
    -- 查询认识部门和财务部门员工的信息
    -- 查看人数部门和财务部门的 部门id
    select dept_id from departments where dept_name = '人事部' or dept_name = '财务部';
    
    select dept_id ,name from employees where dept_id in (1,2);
    
    select * from employees where dept_id in (select dept_id from departments where dept_name = '人事部' or dept_name = '财务部');
    
    
    -- 查询认识部2018年12月所有员工的工资
    year(date)= 2018 and month(date) = 12
    select * from salary where year(date)= 2018 and month(date) = 12 
    and employee_id  in (select employee_id from employees where dept_id = 
     (select dept_id from departments where dept_name = '人事部'));
     
    
    select id,date,basic,bonus,name from salary s inner join employees e on e.employee_id = s.employee_id  where year(date)= 2018 and month(date) = 12 
    and s.employee_id  in (select employee_id from employees where dept_id = 
     (select dept_id from departments where dept_name = '人事部'));
     
     
     -- 查询2018年12月基本工资和奖金都是最高的工资信息
     select max(basic) from salary where year(date)= 2018 and month(date) = 12;
     select max(bonus) from salary where year(date)= 2018 and month(date) = 12;
    
    select * from salary where year(date)= 2018 and month(date) = 12 and basic =(select max(basic) from salary where year(date)= 2018 and month(date) = 12) and bonus = (select max(bonus) from salary where year(date)= 2018 and month(date) = 12);
    -- 添加了内连接的
    select id,date,basic,bonus,name from salary  s inner join employees e on e.employee_id = s.employee_id where year(date)= 2018 and month(date) = 12 and basic =(select max(basic) from salary where year(date)= 2018 and month(date) = 12) and bonus = (select max(bonus) from salary where year(date)= 2018 and month(date) = 12);
    
    
    
    
    -- 查询3好部门及其部门内 员工的编号、名字和email
    select employee_id ,name ,email from employees where dept_id = 3;
    -- 同时需要显示部门名称
    select dept_id ,dept_name ,employee_id ,name ,email from ( select d.dept_name ,e.* from departments d inner join employees e  on d.dept_id = e.dept_id )  tmp_table  where dept_id = 3 ;
    

多表更新与删除

  • 就是执行1条命令可以修改或删除多张表里 的数据

  • 多表更新

    update 表1  as 别名
    inner | left  | right  join  表2   AS  别名
    on  连接条件
    set  列=值  ,列=值....
    [where  筛选条件]
    
  • 多表删除

    delete  表1 别名,表2 别名
    from  表1  as 表1 别名
    inner | left | right join  表2 as  表2 别名
    on  连接条件
    [where  筛选条件]
    
  • 例子

    create table t3 as select name ,uid from user limit 2;
    create table t4 as select uid ,homedir ,shell from user limit 4;
    
    select * from t3 inner join t4 on t3.uid=t4.uid ;
    
    update t3 inner join t4 on t3.uid = t4.uid set t3.uid = 101 ,t4.uid = 102 where t3.name = 'bin' ;
    
    select * from t3 ;
    select * from t4;
    
    
    select * from t3 inner join t4 on t3.uid = t4.uid;
    delete t3,t4 from  t3 inner join t4 on t3.uid = t4.uid ;
    select * from t3 ;
    select * from t4;
    

小结

mysql视图

概述

视图介绍

  • 视图:是只有表头的表 数据是存放创建视图时 使用的物理表

  • 什么是物理表:既有表头又有数据的表

  • 视图是什么?

    1. 试图是由数据库中的一个表或多个表导入的虚拟表,是一种虚拟存在的表
    2. 视图是一张虚拟表,是从数据库中一个或多个表中导出来的表,其内容由查询定义
    3. 同真实表一样,视图包含一系列带有名称的列和行数据
    4. 数据库中只存在了视图的定义,而并没有存在视图中的数据。这些数据存放在原来的表中
    5. 使用视图查询数据时,数据库系统会从原来的表中取出对应的数据
    6. 一旦表中的数据发生改变,显示在视图中的数据也会发生改变。

视图优点

  • 为什么要使用视图
    • 简单
      • 用户无需关心视图中的数据如何查询获得的视图中的数据已经是过滤好的符合条件的结果
    • 安全:用户只能看到视图中的数据
    • 数据独立
      • 一旦视图结构确定,可以屏蔽表结构对用户的影响

视图基础

基础视图

  • 语法格式(需要牢记)

    • create view 库.视图名称 as sql查询;
    • create view 库.视图名称(字段名列表) as sql 查询
      • 在视图表中不定义字段名的话,默认使用基表的字段名,若定义字段名的话,视图表中的字段必须和基表的字段个数相等
  • 例子

    create view vdb.v1 as select host ,user  from mysql.user limit 3;
    drop table vdb.v1; # 第一中删除,是删除不了视图的
    drop view vdb.v1;  # 第二种 才是删除视图的方式
    create view v1 as select name ,uid ,shell from user ;
    create view v2(姓名,家目录, 登陆状态) as select name, homedir,shell from tarena.user ;
    
    # 说明了创建视图是可以使用连接查询的
    create view v3 as select name ,email ,dept_name from employees e inner join departments d on e.dept_id = d.dept_id ;
    
    # 查看一个库里面有那些视图  就描述信息里面有view是视图
    show table status where comment = "view" \G
    
    # 查看库下所有的表的状态信息
    show table status \G
    
    # 怎么知道视图的元数据在那里
    show create view v2 \G
    
    # 查看视图的
    select * from  v1 where name = 'root ';
    
    # 修改视图的数据
    update v1 set uid = 2088 where name ='root ';
    
    # 再去查看元数据的表
    select * from tarena.user where name = 'root ';
    
    # 删除视图中的数据
    delete from vi where name = 'root '
    
    # 再去查看元数据的表,发现没有数据了
    select * from tarena.user where name = 'root ';
    
    # 直接去元数据的表添加数据,
    insert into tarena.user(name ,uid ,gid ,homedir ) values ('yaya',888,888,"/home/yaya");
    
    # 直接去视图查看数据
    select * from v1 where name = 'yaya';
    
    

查看试图

  • 查看当前库下所有表的状态信息
    • show tables status ;
    • show tables status where comment=‘view’ \G
  • 查看创建视图具体select 命令
    • show create view 视图名;

操作试图

  • 视图被创建后,可以像普通表一样来使用,主要是查询
  • 对试图操作基表会改变,反之亦然
  • 查询记录
    • select 字段名列表 from 视图名 where 条件;
  • 插入记录
    • insert into 视图名(字段名列表) values (字段值列表)
  • 更新记录
    • update 视图名 set 字段名=值 where 条件;
  • 删除记录
    • delete from 视图名 where 条件

删除视图

  • 语法格式
    • drop view 视图名

视图进阶

创建视图

  • 完成语法格式

    create  [or replace ]
    [algorithm  = { undefined | merge | temptable}]
    [definer = { user | current_user }]
    [sql securiy {definr | invoker }]
    view  view_name[(column_list)]
    as  select_statement
    [with[cascaded | local] check option]
    

参数说明

  • 具体如下:
    • [or replace ] 覆盖原有视图,能实现修改试图的目的
    • [algorithm = { undefined | merge | temptable}] 可选项,表示视图选择的算法
      • merge :将视图的定义和查询视图的语句合并处理
      • temptable ;视图查询的结果保存到临时表,而后在该临时表基础上执行查询视图的语句;
      • undefined :(默认) 由mysql选择使用那种算法
      • 一般首选merge ,因为merge 更有效率,temptable也不支持更新操作
    • [definer = { user | current_user }];创建视图用户
      • 默认是当前用户,也可以手动指定所有者
    • [sql securiy {definr | invoker }] :查询时的验证方式
      • definer 默认 ,创建视图时 是否有权限访问视图所引用的数据;
      • invoker 指查询视图时,验证查询的用户是否拥有权限访问视图及试图所引用的对象;
    • [(column_list)] :字段清单
    • [with[cascaded | local] check option] :可选项,表示更新视图时要保证在该视图的权限范围之内

设置字段别名

  • 视图表段名默认与select查询相同
  • 视图中的字段名不可以重复
  • sql查询结果有重复字段时要定义字段别名

重要参数演示

  • or replace
    • create or replace view 视图名 as select 查询;
    • 创建时 ,若视图已存在,会替换已有的视图
    • alter view 视图名 as select 查询
  • with check option
    • local 首先满足自身的限制,同时满足基表的限制
    • cascaded 满足视图自身限制即可(默认值)
# 进阶的开始,前提
craete view v2  as  select date, employee_id ,basic from tarena.salary where employee_id between 1 and 10 and year(date) = 2018 and month(date)=10;

update v2 set basic = 40000 where employee_id =1 ;

select date, employee_id ,basic from tarena.salary where employee_id = 1  and year(date) = 2018 and month(date)=10;

# 设置限制范围
# 1.视图的修改


create table t1 select name ,uid from tarena.user limit 3;
create table t2 select name ,uid from tarena.user limit 5;
-- 有重名,需要设置别名(说明创建视图的时候,表头名是不允许重复的)
create view v3 as select t1.namne as username ,t2.name as 姓名 from t1  inner join t2 on t1.name = t2.name ;
select * from v3;

-- 覆盖视图(如果不加上or replace 的话,已经重名的会报错的,加上的话,就会直接覆盖上去,相当于修改的效果了)
create or replace view  v4 as  select name ,uid ,gid from tarena.user 

-- 支持检查选项(选项 local  满足自身的限制,同时要满足基本的限制)
-- with  check  option  (支持检查选项)
-- 选项 local  满足自身的限制,同时要满足基本的限制
-- 选项 cascaded (默认值)  满足视图自身限制即可

-- 没有加上with check option的,就是没有做修改限制的,
create view tarena.v21 as select name ,uid from tarena.user where uid > 10 ;
update tarena.v21 set uid = 9 where name = 'games ' -- 说明了可以修改,但是再次查看试图的话,就没有查到games了,因为满足不了生成视图的条件了,所以显示不了
select * from tarena.user where name = 'games '  -- 发现uid变成了9

-- 覆盖创建
create  or replace view tarena.v21 as select name ,uid from tarena.user where uid > 10 with check option ; -- 满足自身条件的限制是 uid > 10
update tarena.v21 set uid = 9 where name = 'games ' -- 再修改的话,会发现不满足条件

select * from tarena.v21 where name ='zzz'
update tarena.v21 set uid = 3 where name = 'zzz'; -- 虽然没有满足用户,但是视图没有满足修改,所以就不会报错

-- local 创建的
create view v31 as select name ,uid from tarena.user where uid <= 100 ;
create view v41 as select name ,uid from v31  where uid >=10 with local check option;
-- 现在去修改v41的视图的话需要满足 大于10 并且小于100,但是修改的话大于100 的话,是可以的,因为v31里面的没有 with check option,如果要达到上面的效果的话,需要
create or replace view v31 as select name ,uid from tarena.user where uid <= 100 with check option ;

show create view v31;
show create view v41;

select * from tarena.v41;
update tarena.v41 set uid = 9 where name = 'nobody';  -- 没有满足自身限制
update tarena.v41 set uid = 200 where name = 'games'; -- 没有满足基表v31限制
update tarena.v41 set uid = 55 where name = 'games'; -- 既满足自身限制,又满足v31限制


mysql存储过程

基本管理

存储过程介绍

  • 什么存储过程
    • mysql服务中的脚本(脚本是由sql命令组成的、写脚本的时候也支持 变量、判断、循环、循环控制、)
    • 由一系列过程可以对数据做批量处理和重复操作
    • 可以防止对表的直接访问
    • 避免重复的sql操作
  • 统计游戏网站用户注册的总数量(公司 里 的存储过程 是已经写好了 的)

创建存储的过程

  • 语法格式

    delimiter //
    create procedure  名称(参数列表)
    begin
          一组合法的sql命令
    end
    // 结束存储过程
    delimiter;
    
    delimiter 制定命令结束符号
    mysql默认以";" 为分隔符,没有声明分隔符,编译会存储过程当成sql语句进行处理,则存储过程的编译过程会报错,所以需要加上delimiter 改为结束符号为//
    
    
    
  • 说明:存储过程 是代码 不是表 归属于某个库如果存储过程没有参数()可以省略

  • 例子

    select count(*) from user ;
    delimiter //
    select count(*) from user //
    delimiter ;
    select count(*) from user ;
    
    -- 创建存储的过程
    delimiter //
    create procedure tarena.p1()
    begin
    select count(*) from tarena.user ;
    select count(*) from tarena.employees ;
    select count(*) from tarena.salary ;
    end //
    delimiter ;
    
    call tarena.p1;
    call tarena.p1();   -- 执行存储脚本
    drop procedure tarena.p1;    -- 删除存储过程
    
    

查看执行删除

  • 查看存储的过程

    • 方法1:show procedure status
    • 方法2: show db,name,type from mysql.proc where name =“存储过程名”;
  • 执行存储过程

    • call 存储过程名();
  • 删除存储过程

    • drop procedure 存储过程名;
  • 例子

    -- 存储过程是代码 不是表 归属与某个库
    -- 存储过程的代码是保存在库下的表里
    use tarena
    show procedure status ;  -- 只有type是procedure才是存储过程
    -- 想看那个库的存储过程就需要先进库
    
    -- 查看存储在表里的记录
    use mysql;
    desc proc \G  -- 存放存储过程的表
    select db,name,type from mysql.proc  where name = "存储过程名字" ;
    select db,name,type from mysql.proc where type='procedure';
    -- 查看自定义的存储过程
    select db,name,type from mysql.proc where type='procedure' and name = "存储过程名字" ;
    
    -- 查看代码
    select body,db,name,type from mysql.proc where type='procedure' and name = 'p1'; -- body标头是放代码的地方
    
    

进阶管理

  • 在些存储过程的时,可以使用变量、循环语句、判断语句、循环控制语句 参数
  • 依次学习 变量、判断语句、循环语句、循环控制语句、参数
  • 如果不使用如上内容写脚本 脚本的功能比较弱 用的话脚本的功能就比较灵活

变量分类

  • mysql变量可分为2大类:
    • 系统变量:
      • 由系统提供,不是由用户定义的。
      • 包括全局变量、会话变量
    • 用户自定义变量
      • 用户i定义的变量
      • 包括用户变量、局部变量
  • 写存储过程时:只要使用到局部变量和自定义变量

系统变量

  • 全局变量( mysql读物运行后定义的变量 变量值 根据运行环境赋值)

    • 影响服务器整体操作,作用于所有会话
    • 当服务启动时,他将所有全局变量初始化为默认值
    • 更改全局变量,必须具有super权限
    • 其作用域为server的整个生命周期,服务重启消失
  • 会话变量

    • 服务器为每个连接的客户端维护一系列会话变量
    • 其作用域 仅限于当前连接,即每个连接中的会话变量是独立的
  • 例子

    -- 查看全局变量
    show global variables ;
    -- 例子
    show global variables like "%password%" ;
    show global variables like "%time%" ;
    show global variables like "%file%" ;
    show global variables like "%version%" ;
    -- 修改变量
    set global 
    
    set global validate_password_length = '值'
    
    -- 输出全局变量的值
    select  @@变量名
    
    select @@version ,@@version_comment;
    
    -- 会话变量(根据当前登录数据库服务的用户产生的变量)
    -- 会话变量的值有一部分和全局变量一样
    -- 查看所有会话变量
    show session  variables ;
    -- 例子
    show session variables like "%timeout%";
    show session variables like 'connect_timeout';
    
    -- 修改会话变量
    show session variables like "%buffer%"
    set session sort_buffer_size=400000; -- 仅仅修改当前登录数据库的用户的会话变量
    show session variables like 'sort_buffer_size';
    
    -- 输出会话变量的值
    select @@sort_buffer_size;
    

用户变量

  • 局部变量 只能用在begin/end语句块中

    • declare 变量 类型
    • declare 变量 类型 default 值
  • 用户变量

    • 用户变量不用提前声明,在用的时候直接用“@变量名” 使用就可以。仅对当前登录用户有效
  • 例子

    -- 
    set @name = 'bob';
    set @name = 'bob' , @birth = '2022-11-22';
    
    select @name,@birth;
    -- 断开之后再连接的话就会发现没有这变量了
    select @name ; -- 返回的值就是null了
    select @name,@birth
    
    
    -- 把查询结果赋予变量
    select count(name) from tarena.user where shel;='/bin/bash';
    select count(name) into @user_num from tarena.user where shell='/bin/bash';
    select @user_num;
    -- 变量名重复时候,是被覆盖的,变量名是不可以使用中文的
    select count(*) into @user_num from mysql.user ;  -- 这样上面的变量名字就重复,所用到的值就会被覆盖
    select @user_num;
    
    
    -- 局部变量: 只能定义在begin和end 之间
    -- 并且只在存储过程执行中有效  存储过程执行结束 局部变量会消失
    declare  变量  类型
    declare name char(10)
    declare 变量  数据类型  default  值;
    declare class char(7)  default 'nsd2110'
    
    -- 给局部变量赋值
    set  变量名= 值 ;
    declare age int;   -- 只定义了变量
    set age = 21 ;  -- 给变量赋值
    
    -- 局部变量使用的例子
    delimiter //
    create procedure  tarena.o2()
    begin
     declare x int default 9;
     declare y char(10);
     set y = 'bob';
     select x,y;
     set x = 89;
     select x,y;
    end //
    delimiter ;
    
    select body from mysql.proc where name ='o2'; -- 查询存储过程密码
    call tarena.o2 ;
    drop procedure tarena.o2;
    
    
    
    
  
  

### 存储过程参数

- 调用参数时,名称前也不需要加@

  - create  procedure  名称 (类型  变量名  数据类型 ,类型  变量名  数据类型,。。。。)

- | 命令  | 类型      |                             作用                             |
  | ----- | --------- | :----------------------------------------------------------: |
  | int   | 输入      | 给存储过程传值,必须在调用存储过程时赋值,在存储过程中该参数的值不允许修改(默认类型) |
  | out   | 输出      |                    接受存储过程的处理结果                    |
  | inout | 输入/输出 |                 既可以作为输入又可以作为输出                 |

- 例子

  ```mysql
  in  -- 把数据传给存储过程处理
  out -- 用来保存存储过程的执行结果
  inout  -- 既有in类型参数的功能又有out类型参数的功能
  -- 语法格式
  create procefure 库名.名称(参数类型  参数名  数据类型 ,……)
  begin
     调用定义的参数;
  end  
  -- 注意: 在调用有参数的存储过程时,必须给存储过程传参,不然 属于语法错误
  -- 例子
  -- in 类型
  user tarena;
  delimiter //
  create procedure tarena.p3(in  dept_no  int)
  begin
   select dept_id ,count(*) 总人数 from tarena.employees where dept_id = dept_no group by dept_id ;
  end // 
  delimiter ;
  
  call tarena.p3(3) ;  -- 就是根据参数的变化,所处的部门就会跟随变化
  
  delimiter //
  create procedure tarena.p4(in  dept_no  int)
  begin
   select dept_name ,count(*) 总人数 from tarena.employees e inner join tarena.departments d on e.dept_id = d.dept_id where e.dept_id = dept_no group by e.dept_id ;
  end // 
  delimiter ;
  
  call tarena.p4(3) ;
  
  -- out 的例子
  select email  from employees where name = '刘倩';
  select email  into @mail from employees where name = '刘倩';
  select @mail
  
  delimiter //
  create procedure tarena.p5( in emp_name varchar(10) ,out mail varchar(25)  )
  begin
    select email into mail from tarena.employees  where name = emp_name;
  end //
  delimiter ;
  
  insert into tarena.employees(name,email) values ('john','[email protected]'),('jerry','[email protected]');
  call tarena.p5('john', @x);  -- 调用创建过程使用并赋值函数
  select @x
  call tarena.p5('汤华', @x);  -- 没有设置相应的字符集,所以会报错
  -
  show create database tarena \G  -- 查看tarena的字符集
  
  
  --  例子
  select name from tarena.employes ;
  -- 想让存储过程处理中文数据,必须保证存储过程归属使用的字符集是中文字符集才行
  show create database tarena\G
  alter database tarena default character set utf8;
  -- 每改之前创建的存储过程是无效的
  drop procedure tarena.p5;
  -- 在次创建上面的p5 的存储过程;
  -- 再次测试
  call tarena.p5('汤华', @x); -- 再此测试,就发现是可以使用中文的存储过程赋值了
  
  -- inout例子(既有in和out的)
  delimiter //
  create procedure tarena.myadd(INOUT i int)
  begin
   set i = i+100;
  end  //
  delimiter ;
  
  call tarena.myadd(2)
  select body from mysql.proc where name = 'myadd';
  
  -- 输入输出参数时候时,必须要变量接
  set @x = 100;
  call tarena.myadd(@x);
  select @x;
  --
  

流程控制

  • 没有流程控制的存储过程是顺序执行每一条命令
  • 有流程控制后,会跟据流程控制判断语句的结果执行 命令

流程控制结构

  • 具体如下
    • 顺序结构:自上向下执行
    • 分支结构:从多条路径中选择一条路径执行
    • 循环结构:条件执行时,反复执行一段代码
顺序结构
  • if语句 语法(自上向下遇到匹配就执行并结束if语句)

    if 条件 then 
    语句;
    end if ;
    
    

if 条件 then
语句1;
else
语句2;
end if;

if 条件 then
语句1;
elseif 条件2 then
语句2;
else
语句3;
end if;


- 例子

```mysql
-- 
delimiter //
create procedure tarena.deptype_pro
(IN no int ,OUT dept_type varchar(5))
begin
declare type varchar(5);
select dept_name into type from departments where dept_id = no;
if type = '运维部' then set dept_type = '技术部';
elseif type = '测试部' then set dept_type = '技术部';
elseif type = '开发部' then set dept_type = '技术部';
else set dept_type = '非技术部' ;
end if ;
end //
delimiter ;

call deptype_pro(1,@x);
select @x;

分支结构
  • case 语句 语法(多条路径中选择一条路径执行)

    case  变量|表达多| 字段
    when  判断的值1 then 返回值1;
    when  判断值2  then  返回值2;
    。。。
    else  返回值n;
    end  case;
    
循环结构
  • 什么是循环:要重复执行的命令 放在循环语句 ,循环多少次取决于循环语句的判断条件

  • 存储过程支持的循环结构有:while 循环 loop循环 repeate 循环

  • while 、loop、repeat 语法如下

  • [标签:] while  循环条件  do  //只有条件成立才执行循环,如果首次判断没满足直接推出循环
    循环体;
    end while[标签];
    
    [标签:]loop    /无条件的死循环  没有判断条件  
    循环体;
    end  loop [标签]
    
    [标签:] repeat    //至少循环1次,(先执行循环体,再判断条件 条件不成立时再次执行循环)
    循环体;
    untile  循环结束条件
    end  repeat  [标签];
    
  • 例子

    -- while 循环例子
    delimiter //
    create procedure tarena.while_pro(in i int)
    begin
      declare j int default 1;
      while j < i do insert into tarena.departments(dept_name) values ('hr');
      set j = j + i;
      end while ;
      end //
    delimiter ;
    
    select * from tarena.departments ;
    call tarena.while_pro(3);
    select * from tarena.departments ;
    
    
    -- loop循环例子
    delimiter //
    create procedure  tarena.loop2()
    begin
    declare i int default 1 ;
    loop select sleep(1),i;
    end loop;
    end //
    delimiter ;
    -- sleep()  睡眠1秒
    
    call tarena.loop2();
    show processlist;  -- 相当于 ps aux
    kill 相应的id  ;
    
    
    -- repeate 循环 例子
    delimiter //
    create procedure tarena.repeat_pro(in i int)
    begin
    declare j int default 1;
    repeat
      set j = j + 1 ;
      insert into tarena.departments(dept_name) values ('sales');
    until j > i
    end repeat ;
    end //
    delimiter ;
    
    select * from departments ;
    call tarena.repeat_pro(3);
    select * from departments ;
    
    
循环控制语句
  • 控制循环的执行

    • leave 标签名 //跳出循环
    • iterate 标签名 // 放弃本次循环 ,执行下一次循环
  • 默认只有符合循环的判断条件,都会重复执行循环体

  • 我们可以通过循环结构控制语句,在不改变循环判断条件的情况下 跳过某次循环

  • 例子

    -- 例子
    delimiter //
    create procedure  tarena.p11()
    begin p:loop leave p;
    select sleep(1);
    select 'one';
    end loop p ;
    end //
    delimiter ;
    
    
    call tarena.p11(); -- 会发现什么也没有输出
    
    
    delimiter //
    create procedure  tarena.p12()
    begin 
    declare i int default 1;
     set i = 1 ;
     loop 
    select i= i + 1 结果 ;
    select sleep(1);
    end loop;
    end //
    delimiter ;
    
    call p12;
    
    
    -- iterate 
    delimiter //
    create procedure  tarena.while_pro3( in i int)
    begin
      declare j int default 0;
      a:while j < i do set j = j+ 1;
      if mod(j,2)=0 then iterate a;
      end if;
      insert into tarena.departments(dept_name) values (concat('hr',j));
      end while a;
    end //
    delimiter ;
    
    call tarena.while_pro3(20);
    
    select * from departments ;
    

数据备份与恢复

  • 什么是数据备份

  • 为什么要做备份

  • 什么是恢复

  • 怎么恢复

  • 数据备份方式:

    • 按照服务器状态分:冷备份 热备分
  • 根据备份方法分为:物理备份 逻辑备份

备份概述

备份方式

  • 物理备份
    • 冷备:cp、tar。。。
  • 逻辑备份
    • mysqldump //备份命令
    • mysql //恢复命令

备份策略

  • 完全备份
    • 备份所有数据(只对一张表做完全备份 一个库 或一台服务器 的所有数据备份)
  • 增量备份
    • 备份上次备份后,所有新产生的数据(每次是跟上次备份去比较)
  • 差异备份
    • 备份完全备份后,所有新产生的数据 (每次都是跟完全备份去比较)

完全备份与恢复

  • 工作使用的备份策略
    • 完全备份+增量备份
    • 完全备份+差异备份
  • 例如
    • 每周一 晚上12点 对数据库服务器做完全备份
      • 实现的方法 周期性计划任务执行对数据做完全备份的脚本
        • 59 23 * * * 1 /root/allbak.sh
        • 00 22 * * 2-7 /root/new.sh
    • 没周二 到 周日 晚上10 点对数据库做增量备份

物理备份及恢复

  • 备份操作

    • cp -r /var/lib/mysql 备份目录/mysql.bak
    • tar -zcvf /root/mysql.tar.gz /var/lib/mysql/*
  • 恢复操作

    • cp -r /备份目录/mysql.bak /var/lib/mysql、
    • tar -zxvf /root/mysql.tar.gz -C /var/lib/mysql/
    • chown -R mysql:mysql /var/lib/mysql
  • 实例

    [root@mysql1 ~]# mkdir /bakdir
    [root@mysql1 ~]# systemctl stop mysqld.service 
    [root@mysql1 ~]# cp -r /var/lib/mysql /bakdir/
    [root@mysql1 ~]# ls /bakdir/
    [root@mysql1 ~]# systemctl start mysqld
    [root@mysql1 ~]# tar zcf /bakdir/mysql.tar.gz /var/lib/mysql 
    [root@mysql1 ~]# ls /bakdir/
    [root@mysql1 ~]# rm -rf /var/lib/mysql
    
    # 有些数据库会发现数据库没有了,会做数据库初始化
    [root@mysql1 ~]# rm -rf /var/lib/mysql
    [root@mysql1 ~]# systemctl stop mysqld.service 
    [root@mysql1 ~]#  killall -9 mysqld
    [root@mysql1 ~]# cp -r /bakdir/mysql /var/lib/mysql 
    [root@mysql1 ~]# chown -R  mysql:mysql /var/lib/mysql
    [root@mysql1 ~]# ll -d /var/lib/mysql
    [root@mysql1 ~]# systemctl start mysqld
    [root@mysql1 ~]# mysql -uroot -p123456
    
    
    

mysqldump 备份及恢复

  • 完全备份

    • mysqldump -uroot -p密码 库名 > /目录/xx.sql
    • 库名的表示方式很重要
  • 完全恢复

    • mysql -uroot -p密码 [库名] < /目录/xx.sql
  • 注意:恢复库时库名可以省略

  • 注意:备份和恢复数据库服务必须是运行状态

  • 库名表示方式

    • 库名  表名列表      //备份1张表或多张表
      -B  库名列表        //备份1个库或多个库
      -all-databases  或 -A     //备份1台服务器所有数据
      
      
    • 注意:恢复数据时,会删除目标服务器同名的库表 再恢复数据

  • # mysqldump是mysql安装后提供的命令
    mysqldump -uroot -p123456 tarena user > /bakdir/user.sql -- 一个表
    ls /bakdir/
    mysqldump -uroot -p123456 -B tarena > /bakdir/tarena.sql -- 一个库
    mysqldump -uroot -p123456 tarena employees salary > /bakdir/emplotees_salary.sql -- 多个表
    mysqldump -uroot -p123456 -B tarena studb > /bakdir/tarena_studb.sql   -- 多个库
    mysqldump -uroot -p123456 -A > /bakdir/all.sql  -- 一个服务器
    
    # 使用恢复
    drop database tarena;
    [root@mysql1 ~]# mysql -uroot -p123456 < /bakdir/tarena.sql 
    show databases;
    use tarena ;
    show tables ;
    # 51 恢复备份
    [root@mysql1 ~]# scp -r /bakdir/ 192.168.4.51:/
    [root@mysql2 ~]# mysql -uroot -pNSD2110...a < /bakdir/tarena_studb.sql 
    [root@mysql2 ~]# mysql -uroot -pNSD2110...a
    mysql> show databases;
    
    
    # 51 删除表跟恢复表
    mysql> use tarena
    mysql> drop table user ;
    [root@mysql2 ~]# mysql -uroot -pNSD2110...a tarena < /bakdir/user.sql 
    [root@mysql2 ~]# mysql -uroot -pNSD2110...a
    mysql> use tarena
    mysql> show tables ;
    use tarena;
    select count(*) from tarena.user 
    insert into tarena.user(name,id) values ('a',211); -- 插入数据
    delete from tarena.user ;
    select * from tarena.user ;
    source /bakdir/user.sql  -- 恢复数据 
    select count(*) from tarena.user ; -- 恢复的数据会发现直线插入的数据是没有的
    
    
  • 适合备份数据量少的数据

    • 因为mysqldump 在备份没有完成的情况下 会锁表
    • 锁表,在没有释放锁之前 不允许对表执行 读写
    • mysqldump的备份文件恢复,是覆盖恢复

binglog日志

说明 启用mysql的binlog日志文件 实现对数据的实时备份

日志介绍

  • 什么是binlog日志
    • 也称做 二进制日志
    • mysql服务日志文件的一种
    • 记录出查询之外的所有sql命令
    • 可用与数据的备份和恢复
    • 配置mysql主从同步的必要条件
    • 启用后,可以实时记录在数据库服务器上执行除查询以外的sql命令
      • 就是出查看数据的sql命令 都不记录到日志文件

启动日志

配置项 用途
server_id=数字 指定id值(1-255)
log_bin 启用binlog日志
max_binlog_size=数值m 指定日志文件容量,默认1G
  • binlog相关文件

    • /var/lib/mysql 默认存放目录
    • 主机名-bin.index 索引文件
    • 主机名-bin.000001 日志文件
  • show master status ;  -- 说明是空的,没有binlog日志
    vim /etc/my.cnf
    log_bin  -- 删除#
    server_id = 50  -- 手动添加
    [root@mysql1 ~]# systemctl restart mysqld
    mysql> show master status ;  -- 编号为1 到达1G 的容量 会自动创建编号为2 的文件 
    -- 这个文价存放在
    ls /var/lib/mysql/mysql1-bin.000001 
    /var/lib/mysql/mysql1-bin.index
    
    
    mysqlbinlog bin.000001 -- 命令行查看binlog内容
    

自定义日志

  • 修改日志文件存放的目录和名称

  • [root@mysql1 ~]# vim /etc/my.cnf
    log_bin=/mylog/plj  -- 删除#
    server_id = 50  -- 手动添加
    [root@mysql1 ~]# mkdir /mylog
    [root@mysql1 ~]# chown mysql /mylog/
    [root@mysql1 ~]# setenforce 0
    [root@mysql1 ~]# systemctl restart mysqld
    [root@mysql1 ~]# ls /mylog/  -- 发现下面会有文件
    mysql> show master status;  -- 发现file名字会有发生更改
    -- 每个文件的编号都是从1开始的
    
    

日志管理

  • 创建新日志文件

    systemctl  restart  mysql   -- 重启服务
    mysqldump  -u用户名 -p密码  -flush-logs    -- 加-flush-logs  选项
    
    flush  logs  ;  -- mysql刷新日志命令
    show master  status ;  -- 查看正在使用的日志
    show binary  logs ;   -- 查看已有的日志文件
    purge  master  logs  to'日志名'   -- 删除编号之前的日志
    reset  master  ;   -- 删除所有日志,重新创建日志
    show  binlog  events   in  '日志文件名'    -- 查看日志文件内容
    
  • 例子

    -- 手动创建新的日志文件   正常情况下,只有大于1G才会创建新的日志文件
    mysql> flush logs; -- 生成新的日志文件
    mysql> show master status ;
    [root@mysql1 ~]# systemctl restart mysqld  -- 重启就会无条件创新新的日志文件
    mysql> show master status ;
    mysqldump -uroot -p123456 --flush-logs -B tarena  > /opt/tarena.sql -- 也会创建新的日志文件
    mysql -uroot -p123456 -e'show master status';
    
    
    -- 删除已有的日志文件
    reset  master;   -- 删除所有日志,重新创建日志
    purge  master  logs  to'日志名'   -- 删除编号之前的日志
    -- 插入数据,直接访问日志内容
    insert into tarena.user(name,uid) values('ss',123);
    show binlog events in 'plj.000001';
    
    

使用日志恢复数据

命令格式

  • 把查看到的文件内容管道给连接mysql服务的命令执行

    • 查看文件全部内容,适用于恢复所有数据

    • – 适用于日志没有记录delete from命令

      mysqlbinlog /目录/文件名 | mysql -uroot -p密码

    • 查看文件制定范围内容,使用恢复部分数据

      mysqlbinlog 选项 /目录/文件名 |mysql -uroot -p密码

  • 选项说明

    选项 用途
    -start-datetime=‘yyyy-mm-dd hh:mm:ss’ 起始时间
    -stop-datetime=‘yyyy-mm-dd hh:mm:ss’ 结束时间
    -start-postion=数字 起始偏移量
    -stop-postion=数字 结束偏移量
  • 例子

    -- 在50 完成实验
    -- 对tarena库做完全备份
    mysql -uroot -p123456 -e 'select count(*) from tarena.user '
    mysql -uroot -p123456 -e 'show master status;'
    mysqldump -uroot -p123456 --flush-logs tarena user > /bakdir/user1.sql
    mysql -uroot -p123456 -e 'show master status ' -- 发现出现了新的日志文件
    mysql -uroot -p123456 -e "insert into tarena.user(name) values('sss')"-- 同样操作,3行
    mysql -uroot -p123456 -e 'show master status '
    mysql -uroot -p123456 -e 'select count(*) from tarena.user '
    
    -- 在51数据库tarena库下的user记录删除,使用50 的备份文件加binlog日志恢复日志文件
    mysql -uroot -pNSD2110...a -e'delete from tarena.user'
    mysql -uroot -pNSD2110...a -e'select count(*) from tarena.user '
    scp /bakdir/user1.sql  192.168.4.51:/opt/
    scp /mylog/plj.000002 192.168.4.51:/opt/
    mysql -uroot -pNSD2110...a tarena < /opt/user1.sql
    mysql -uroot -pNSD2110...a -e'select count(*) from tarena.user '
    mysqlbinlog  /opt/plj.000002 | mysql -uroot -pNSD2110...a 
    mysql -uroot -pNSD2110...a -e'select count(*) from tarena.user '
    
    
    -- 使用binlog日志回复指定的数据
    -- 适用于日志文件里面交替出现插入 insert更新update 删除delete 的命令
    mysqldump  选项  /目录/日志文件名  | mysql -uroot -p密码
    -- 通过选项控制读取日志文件记录命令的范围
    -- 可以通过时间范围选项 只读取指定时间范围内记录sql命令
    -- 也可以通过偏移量范围选项 只读取制定偏移量范围内记录的sql命令
    
    !!说明  要执行命令所在  范围要自己查看 日志的内容 获得
    例如
    mysqlbinlog  --start-position=9088 --stop-position=10923  /mylog/plj.000002  | mysql -uroot -p123456 
    
    -- 接着上个实验做
    mysql -uroot -p123456 -e 'show master status'
    mysql -uroot -p123456 -e 'select count(*) from tarena.user '
    mysql -uroot -p123456 -e "insert into tarena.user(name) values ('jj')"
    mysql -uroot -p123456 -e "insert into tarena.user(name) values ('ajj')"
    mysql -uroot -p123456 -e "insert into tarena.user(name) values ('bjj')"
    mysql -uroot -p123456 -e "delete from tarena.user"
    mysql -uroot -p123456 -e "insert into tarena.user(name) values ('cjj')"
    scp /mylog/plj.000002 192.168.4.51:/opt/
    mysqlbinlog  /opt/plj.000002 | mysql -uroot -pNSD2110...a -- 直接恢复就会报错(主键的错误) 但是会把删除的命令执行一遍
    -- 就是说明表里有交替的记录 不适用从到读到尾巴
    mysql -uroot -p123456 -e 'show master status'
    mysql -uroot -p123456 -e  “show binlog events in 'plj.000002'”
    -- 直接查看的话没法断定那条记录跟那条记录
    -- 指定范围,要先修改日志文件的格式
    
    
    
    
    

修改日志格式

  • 查看日志当前记录格式

    • 三种记录方式
      • statement 报表模式
      • row 行模式
      • mixed 混合模式
  • 修改日志记录格式

    • vim /etc/my.cof
      [mysql]
      binlog_format='名称'
      
      systemctl  restart  mysqld
      
  • 实例

    mysql -uroot -p123456 "show variables like '%binlog%'"
    binlog_format -- 查处这个变量名  默认格式就是row 就是行模式 ,修改为混合模式
    vim /etc/my.cnf
    [mysqld]
    binlog_format='mixed'  -- 修改这一项
    systemctl restart mysqld
    -- 重启之后日志就会自动更新,然后查看的日志就是plj.000003最新的这个
    mysql -uroot -p123456 -e "show master status "
    mysql -uroot -p123456 -e "show binlog events in 'plj.000004'"
    mysql -uroot -p123456 -e "delete from tarena.user" 
    mysql -uroot -p123456 -e " show binlog events in 'plj.000004'"
    -- 再次查看就会看到正条sql命令
    mysql -uroot -p123456 -e " insert into tarena.user(name) values('A')"
    mysql -uroot -p123456 -e " insert into tarena.user(name) values('B')"
    mysql -uroot -p123456 -e " insert into tarena.user(name) values('C')"
    mysql -uroot -p123456 -e " update tarena.user set name = 'abc' where name = 'B'"
    mysql -uroot -p123456 -e " insert into tarena.user(name) values('XY')"
    mysql -uroot -p123456 -e " show binlog events in 'plj.000004'"
    mysql -uroot -p123456 -e "select count(*) from tarena.user"
    -- 就可以查看到范围了
    
    -- 在51里面操作
    scp /mylog/plj.000004 192.168.4.51:/opt/
    -- 在51是直接看不了plj.000003的,只能在50里面查要执行命令的范围,然后在51主机执行日志范围命令记录内的数据
    mysql -uroot -p123456 -e " show binlog events in 'plj.000004'" -- 50主机
    mysql -uroot -pNSD2110...a -e 'select count(*) from tarena.user '
    
    mysqlbinlog  --start-position=1558 --stop-position=2338 /opt/plj.000004 | mysql -uroot -pNSD2110...a
    
    mysql -uroot -pNSD2110...a -e 'select count(*) from tarena.user '
    
    
    -- 在50主机使用自己的binlog日志文件恢复数据
    使用mysql -uroot -p123456 -e " show binlog events in 'plj.000004'"是查不到时间的,只能查到起始偏移量
    mysql -uroot -p123456 -e "select count(*) from tarena.user"
    mysqlbinlog /mylog/plj.000004 -- 可以看到相应的时间, 命令的上方的#就是起始时间 结束时间的话必须要包含commit的时间 
    mysql -uroot -p123456 -e "delete from tarena.user" 
    mysql -uroot -p123456 -e "select count(*) from tarena.user"
    mysqlbinlog --start-datetime="2022-02-17 16:49:20" --stop-datetime="2022-02-17 16:49:29" /mylog/plj.000004 | mysql -uroot -p123456 
    mysql -uroot -p123456 -e "select count(*) from tarena.user"
    

innobackupex

概述

备份工具

  • 物理备份缺点
    • 跨平台性差
    • 备份时间长、冗余备份、浪费存储空间
  • mysqldump备份缺点
    • 效率较低、备份和还原速度慢、锁表
    • 备份过程中、数据插入和更新操作被阻塞

软件介绍

  • 优点:在线热备不锁表 适合生产环境下的备份要求

  • 一款强大的在线热备份工具

    • 备份过程中不锁库表,适合生产
    • 由专业组织percona提供(改进muysql分支)
scp percona-xtrabackup-24-2.4.7-1.el7.x86_64.rpm  libev-4.15-1.el6.rf.x86_64.rpm 192.168.4.50:/root
yum -y install percona-xtrabackup-24-2.4.7-1.el7.x86_64.rpm   libev-4.15-1.el6.rf.x86_64.rpm


-- 完全备份与恢复
innobackupex -uroot -p密码 /备份文件存放的目录  [--no-timestamp]  目录不需要事先创建,目录一次只能存放一次目录
-- 恢复数据的命令格式


[root@mysql1 ~]# ls /fullbak
[root@mysql1 ~]# innobackupex -uroot -p123456 /fullbak 
[root@mysql1 ~]# ls /fullbak  -- 发现存放了以系统时间为名的文件夹

[root@mysql1 ~]# rm -rf /fullbak/
[root@mysql1 ~]# innobackupex -uroot -p123456 /fullbak --no-timestamp
[root@mysql1 ~]# ls /fullbak -- 蓝色的是库 黑色是记录备份记录的备份信息
[root@mysql1 ~]# cat /fullbak/xtrabackup_checkpoints  -- 备份信息
backup_type = full-backuped  # 说明了是完全备份数据
from_lsn = 0
to_lsn = 8794342
last_lsn = 8794351
compact = 0
recover_binlog_info = 0
-- 备份的过程中不锁表,也就是说在备份的时候允许客户进行读写的操作


完全备份与恢复

  • 准备恢复数据
    • innobackupex --apply-log /备份目录
  • 拷贝数据
    • innobackupex --copy-back /备份目录

恢复步骤

  • 要求数据库清空

  • 具体如下

    • 准备恢复数据
    • 停止数据库服务 (如果不停止服务,去删除数据库目录的话,会删除不干净)
    • 清空数据库目录
    • 拷贝数据
    • 修改所有者/组用户
    • 启动数据库服务
    • 使用数据管理员root去使用
  rm -rf /var/lib/mysql/*
  cat /fullbak/xtrabackup_checkpoints 
  innobackupex --copy-back /fullbak/
  chown -R mysql:mysql /var/lib/mysql/ 
  systemctl start mysqld
  ll -d /var/lib/mysql/
  ll  /var/lib/mysql/
  systemctl start mysqld

恢复单张表

操作步骤

  • 具体如下:

    • 删除表空间(表空间:指的是表明.ibd 存储表里数据的文件)
    • 导入表信息 (
    • 拷贝表信息文件到数据库目录下
    • 修改信息文件的所有者及组用户为mysql
    • 导入表空间
    • 删除数据库目录下的表信息文件
    • 查看表记录
  • 相关命令

    alter  table  库名.表名  discard  tablespace  # 删除表空间
    innobackupex --apply-log --export  数据完全备份目录  # 导出表信息
    cp /备份目录/库名/表名/{ibd,cfd,exp} /var/lib/mysql/库名 # 拷贝表信息文件
    chown -R mysql:mysql /var/lib/mysql/库名  # 修改所有者/组
    alter table 库名.表名 import tablespace  # 导入表空间
    rm -rf /var/lib/mysql/库名/表名.{cfd,exp}  # 删除表信息文件
    select * from 库名.表名 ; # 查看表记录
    
  • 例子

    mysql -uroot -p123456 -e 'select * from tarena.user '
    mysql -uroot -p123456 -e 'alter table tarena.user discard tablespace;'
    ls /var/lib/mysql/tarena/user.*
    ls /fullbak//tarena/user.*
    innobackupex --apply-log --export /fullbak/
    ls /fullbak//tarena/user.*
    ls /var/lib/mysql/ib_logfile*
    cp /fullbak/tarena/user.ibd /var/lib/mysql/tarena/
    cp /fullbak/tarena/user.cfg /var/lib/mysql/tarena/
    cp /fullbak/tarena/user.exp /var/lib/mysql/tarena/
    ll /var/lib/mysql/tarena/
    chown -R mysql:mysql /var/lib/mysql/tarena/ 
    ll /var/lib/mysql/tarena/
    mysql -uroot -p123456 -e 'alter table tarena.user import tablespace'
    mysql -uroot -p123456 -e 'select * from tarena.user '
    rm -rf /var/lib/mysql/tarena/user.cfg 
    rm -rf /var/lib/mysql/tarena/user.exp 
    
    

增量备份与恢复

  • 增量备份定义:备份上次备份后新产生的数据(所以在执行增量备份之前 必须要有过一次备份)
  • 通常在执行增量备份之前的的首次备份就应该执行完全备份

命令格式

  • 增量备份

    • innobackupex -u用户名  -p密码  -incremental  /增量备份存放的目录名 --incremental-basedri=/上次备份文件存放的目录名 [--no-timestamp:不使用时间戳格式的创建目录存放数据]
      
      
  • 增量恢复

    • innobackupex --apply-log  -redo-only  /首次备份目录名  #准备恢复数据
      innobackupex  --apply-log  -redo-only  /首次备份目录名  --incremental-dir=/目录名 # 合并数据
      innobackupex  --copy-back  /目录名 # 拷贝数据
      
    • 准备恢复数据(声明合并的起始位置)

    • 合并数据(把增量数据合并)(合并数据的顺序要与备份的顺序一致)

    • 拷贝数据

选项说明

常用选项 含义
–apply-log 准备恢复数据
–redo-only 日志合并
–incremental /目录名 新数据存放目录
–incremental-basedir=/目录名 备份新数据参考目录
–incremental-dir=/目录名 合并数据存放目录
  • 例子

    innobackupex -uroot -p123456 /allbak --no-timestamp
    ls /allbak/
    mysql -uroot -p123456 -e "insert into tarena.user(name,uid) values('sda',31231)"
    
    mysql -uroot -p123456 -e "select count(*) from tarena.user"
    innobackupex -uroot -p123456 --incremental /newldri --incremental-basedir=/allbak/ --no-timestamp
    ls /newldri/
    
    # 判断数据是
    [root@mysql1 ~]# cat /allbak/xtrabackup_checkpoints 
    backup_type = full-backuped
    from_lsn = 0  # 完全被分是从0 开始备份的
    to_lsn = 7924691  # 这是结束的序列号
    last_lsn = 7924700  
    compact = 0
    recover_binlog_info = 0
    [root@mysql1 ~]# cat /newldri/xtrabackup_checkpoints 
    backup_type = incremental
    from_lsn = 7924691  # 因为是增量备份,所以是接着上次备份结束的序列号开始
    to_lsn = 7929110# 这是结束的序列号
    last_lsn = 7929119  
    compact = 0
    recover_binlog_info = 0
    
    ls /var/lib/mysql/ib_logfile*
    # 就是参看下面的日志文件的lsn 的序列号是否相同,如果参考的数据不一致的话,说明了数据是有过变化的,有变化的话,就参看上次备份的序列号,接着上次备份的数据的序列号,备份到最新的数据的序列号
    
    # 增量恢复例子
    innobackupex --apply-log  -redo-only  /首次备份目录名 
    innobackupex  --apply-log  -redo-only  /首次备份目录名  --incremental-dir=/目录名 
    innobackupex  --copy-back 
    
    scp -r /allbak 192.168.4.51:/root/
    scp -r /newldri/ 192.168.4.51:/root/
    scp -r /newldir1/ 192.168.4.51:/root/
    scp -r libev-4.15-1.el6.rf.x86_64.rpm  percona-xtrabackup-24-2.4.7-1.el7.x86_64.rpm 192.168.4.51:/root/
    
    #  51主机使用备份文件恢复数据
    systemctl stop mysqld.service 
    rm -rf /var/lib/mysql/*
    yum -y install libev-4.15-1.el6.rf.x86_64.rpm percona-xtrabackup-24-2.4.7-1.el7.x86_64.rpm
    # 指定首次备份的目录
    innobackupex --apply-log --redo-only  /root/allbak/
    cat allbak/xtrabackup_checkpoints 
    # 合并数据
    innobackupex --apply-log --redo-only  /root/allbak/ --incremental-dir= /root/newldri/
    innobackupex --apply-log --redo-only  /root/allbak/ --incremental-dir=/root/newldri/
    cat allbak/xtrabackup_checkpoints 
    cat newldri/xtrabackup_checkpoints 
    innobackupex --apply-log --redo-only  /root/allbak/ --incremental-dir=/root/newldir1/
    cat allbak/xtrabackup_checkpoints 
    cat newldri/xtrabackup_checkpoints 
    cat newldir1/xtrabackup_checkpoints 
    rm -rf newldri/ newldir1/ # 因为已经把数据都合并了/root/allbak/ ,所以这两个文件没什么用了,但是还是有数据的
    # 数据回复
    innobackupex --copy-back /root/allbak/  # 将数据拷贝回复到数据库目录下
    ls /var/lib/mysql
    ll /var/lib/mysql
    chown -R mysql:mysql /var/lib/mysql
    ll /var/lib/mysql
    
    # 重启服务
    systemctl start mysqld
    mysql -uroot -p123456 -e 'select count(*) from tarena.user '
    
    
  • 具体操作

    • 停止服务
    • 清空数据库目录
    • 准备回复数据
    • 合并数据
    • 拷贝数据
    • 修改数据库目录的所有者和组
    • 启动mysql

mysql主从同步

主从同步概述

mysql主从同步

  • 主从同步介绍
    • 实现数据同步的服务结构
    • 主服务器;接受客户端访问连接
    • 从服务器:自动同步主服务器数据

主从同步介绍

是实现数据自动备份的存储结构 分为两种角色

主数据库服务器master : 被网站连接的数据库服务器

从数据库服务器slave : 同步主数据库服务器上数据的 数据库服务器

工作原理

master角色的数据库服务器 必须启用binlog日志

slave角色的数据库服务器有IO线程和sql线程

IO线程: 负责拷贝master服务器binlog日志里的sql命令 到本机 并把名存放到本机的中继日志文件里

sql线程: 负责执行本机中继日志文件里保存的sql命令 把数据存放到本机的表里

主从同步结构模式

  • 一主一从
  • 一主多从(当主坏掉之后,从服务器当主了,就没有备份的服务器了
  • 主从从(就是给从服务器也配置从服务器) (当主服务器坏了之后,从服务器当主了,还有备份的服务器)
  • 主主(就两台服务器它当它的主,它当它的从)(互为主从)

配置主从同步存储架构

主服务器需要做的配置

  • 启动binlog日志
  • 用户授权:添加用户给从服务器拷贝sql命令连接使用
  • 查看日志信息: show master status

从服务器需要做的配置

  • 制定server_id并重启数据库服务器

  • 要确保与主数据库服务器数据一致(只能大于或等于主服务器,不能小于主服务器)(如果是2台崭新的数据库服务器 数据默认是一样的)

  • 管理员登录指定主服务器信息

    • change master to 主服务器ip 连接用户 连接密码 日志文件名 偏移量
    • master_host=‘主服务器ip’, master_user=‘用户名’ ,master_password=‘密码’ ,master_log_file=‘日志文件名’,master_log_pos=偏移量
  • 启动slave进程 (mysql内置的进程)

    • 在登录状态下 start slave;
  • 查看进程状态信息

    • IO线程 :yes

      SQL线程 : yes

配置

配置51

# 开启binlog日志
vim /etc/my.cnf
log_bin=master51
server_id=51

systemctl restart mysqld
mysql -uroot -p123456
grant replication slave on *.* to repluser@"%" identified by "123456";
# 如果密码没有改过策略的话,还是原来那种复杂的密码 类似于123qqq...a
show master status;

配置52

vim /etc/my.cnf
[mysqld]
server_id=52

systemctl restart mysqld
mysql -uroot -p123456
show slave status \G  # 没有配置之前不是从服务器
change  master  to master_host='192.168.4.51',  master_user='repluser',master_password='123456',master_log_file='master51.000001',master_log_pos=441;
show slave status \G # 已经发现有数据了
Slave_IO_Running: No  IO没有启动
Slave_SQL_Running: No  SQL没有启动
start slave;
show slave status \G 

# 如果启动了了没有发现是两个都是yes,那么先
stop slave;
change master to master_host='192.168.4.51',master_user='repluser',master_password='123456',master_log_file='master51.000001',master_log_pos=441;
#由于是直接复制配置文件跟数据库过去的,所以需要在vim /var/lib/mysql/auto.cnf 里面的内容换以一个字母或数字就行,然后再重启,再进去重启slave

查看报错信息 show slave status \G 
Last_IO_Error: 
Last_SQL_Error: 
Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work # 说明了 UUIDs相同 所以需要在vim /var/lib/mysql/auto.cnf 里面的内容换以一个字母或数字就行,然后再重启,再进去重启slave

测试配置:

在主数据库服务器51本机管理员登录创新库表

添加51上面添加数据

[root@mysal51 ~]# mysql -uroot -p123456 -e 'create database db1'
[root@mysal51 ~]# mysql -uroot -p123456 -e 'create table db1.a(id int)'
 mysql -uroot -p123456 -e 'grant all on db1.* to yaya@"%" identified by "123qqq...A"'

在50上面登录51数据库服务器以yaya身份

[root@mysql51 ~]# mysql -h192.168.4.51 -uyaya -p123qqq...A
use db1;
insert into a values(123);

在52上面就可以查看所有的数据了

接下来就是一主多从的结构

vim /etc/my.cnf
[mysqld]
server_id=52

systemctl restart mysqld
# 51对数据做完全备份 把备份文件拷贝给从服务器
[root@mysal51 ~]# mysqldump -uroot -p123456 -B mysql db1 > /root/two.sql
[root@mysal51 ~]# scp two.sql 192.168.4.53:/root
# 53数据恢复
mysql -uroot -p123456 < two.sql
mysql -uroot -p123456

show slave status \G  # 没有配置之前不是从服务器

change  master  to master_host='192.168.4.51',  master_user='repluser',master_password='123456',master_log_file='master51.000001',master_log_pos=1295;  # 注意日志文件名需要事先查看文件名和偏移量
start slave ;
show slave status \G 

测试

在50里面使用yaya用户添加数据,然后在53数据库服务器查看数据

主从同步数据复制模式

主从从模式

将53 还原为独立的数据库服务器

[root@mysql53 ~]# cd /var/lib/mysql
[root@mysql53 mysql]# cat master.info 
[root@mysql53 mysql]# rm -rf master.info
[root@mysql53 mysql]# ls mysql53-relay-bin.
[root@mysql53 mysql]# ls mysql53-relay-bin.
[root@mysql53 mysql]# ls *-relay-bin*
[root@mysql53 mysql]# cat mysql53-relay-bin.index 
[root@mysql53 mysql]# rm -rf *-relay-bin*
[root@mysql53 mysql]# ls relay-log.info 
[root@mysql53 mysql]# cat relay-log.info 
[root@mysql53 mysql]# rm -rf relay-log.info
[root@mysql53 mysql]# systemctl restart mysqld
[root@mysql53 mysql]# mysql -uroot -p123456
mysql> show slave status \G
mysql> drop database db1;

准备54 和 55 数据库服务器

第一步:配置主服务器53
启用binlog日志文件
用户授权
查看日志信息
第二步:配置技术主服务器又是从服务器的54
注意:从服务器自己也有服务器的时候,要启用级联复制功能
第三步:配置从服务器55
制定server_id并重启数据服务
管理员的登录制定


# 53 
[root@mysql53 mysql]# vim /etc/my.cnf
binlog=master
server_id=53
[root@mysql53 mysql]# systemctl restart mysqld
[root@mysql53 mysql]# mysql -uroot -p123456
grant replication slave on *.* to repluser@"%" identified by '123456';
show master status ;
# 54 
vim /etc/my.cnf
[mysqld]
server_id=54
validate_password_policy=0
validate_password_length=6
log_bin=master54
log_slave_updates

mysql -uroot -p123456
grant replication slave on *.* to repluser@'%' identified by '123456';
change master to master_host='192.168.4.53' ,master_user='repluser' , master_password='123456',master_log_file='master53.000001',master_log_pos=441;

start slave ;
show slave status;
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
show master status ;


# 55
vim /etc/my.cnf
server_id=55
change master to master_host='192.168.4.54' ,master_user='repluser' , master_password='123456',master_log_file='master54.000002',master_log_pos=441;
start slave ;
show slave status \G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
# 在主服务器53添加用户

# 客户端使用添加的用户连接主服务器  建库建表 存储数据

# 客户端分别连接服务器54和55 可以查看到同样的数据

# 53
mysql -uroot -p123456
grant all on webdb.* to yaya6688@'%' identified by '123456'; 

# 50
mysql -h192.168.4.53 -uyaya6688 -p123456
create database webdb;
show databases;
create table webdb.t1(id int);
insert  into webdb.t1 values(101);
select * from webdb.t1;

# 54和55 查看创建的记录
show databases;
select * from webdb.t1;

主主结构准备数据库服务器56和57

# 主主同步结构:2太数据库服务器互为主从
# 具体配置步骤如下
第一步  配置服务器56 
# 启用binlog 日志
# 用户授权
# 查看日志信息
第二步 配置数据库服务器57
# 启用binlog日志
# 用户授权
# 指定主服务器侵袭
查看binlog信息
第三步 配置数据库服务器56 
#指定主服务器信息

# 56
vim /etc/my.cnf
server_id=56
binlog-master56

systemc	retstart mysqld
mysql -uroot -p123456
grant replication slave on *.* to repluser@'%' identified by '123456';
show master status ;


# 57
server_id=57
log_bin=master57
systemctl restart mysqld
mysql -uroot -p123456
grant replication slave on *.* to repluser@'%' identified by '123456';
change master to master_host='192.168.4.56' ,master_user='repluser' , master_password='123456',master_log_file='master56.000001',master_log_pos=441;
start slave ;
show slave status \G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
show master status ;

# 56 配置57 的从服务器
change master to master_host='192.168.4.57' ,master_user='repluser' , master_password='123456',master_log_file='master57.000001',master_log_pos=441;
start slave ;
show slave status \G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

# 测试配置
# 具体操作如下
# 在任意一台数据库服务器添加用户都可以
# 客户端使用添加用户连接 任意数据库存储数据都可以
# 客户端连接任意一台查看数据
# 56
grant all on db2.* to haha@'%' identified by '123456';
# 57
create database db2;
create table db2.t1(id int );
insert into db2.t1 values(199);
# 56 
select * from db2.t1;
insert into db2.t1 values (100);
# 57
select * from db2.t1;


主从同步数据复制模式(实验在50主机完成

讲的是:从数据库服务器与主数据库服务器 做数据同步时的工作方式

分为2中工作方式

  • 异步复制模式:(默认)

    • 主从结构中,主数据库服务器把数据存储完成即可,不关心自己的从服务器是否把数据同步到本机
  • 半同步复制模式:

    • 主从结构中,至少保证一台从服务器 把数据同步到本机
    • 好处:就是当主服务器宕机之后,访问从数据库效果也是一样

思考:两种模式的优缺点?

# 在50数据库服务器启用半同步复制功能
# 具体操作如下
# 第一步:安装功能模块并查看 安装状态
# 安装master模块
# 安装slave模块

# 第二步:启用功能模块查看状态
# 启用master模块

# 启用slave模块

# 查看启用状态
# 第三步:永久配置(命令配置数据库服务后会还原)
# 第四步
验证永久配置
重启数据库服务,查看模块的状态依然还是启动状态
# 50
mysql -uroot -p123456
install plugin  rpl_semi_sync_master soname "semisync_master.so"; # master模块
install plugin  rpl_semi_sync_slave soname "semisync_slave.so";  # slave模块
select plugin_name ,plugin_status from information_schema.plugins where plugin_name like "%semi%"; 

第二步
set global rpl_semi_sync_master_enabled=1;
set global rpl_semi_sync_slave_enabled=1;
show variables like "rpl_semi_%_enabled";

第三步在配置文件中编辑
vim /etc/my/cnf
# 安装模块
plugin-load="rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so;"
rpl_semi_sync_master_enabled=1
rpl_semi_sync_slave_enabled=1

第四步
systemctl restart mysqld
mysql -uroot -p123456
show variables like "rpl_semi_%_enabled";

主服务必须配置步骤

启用binlog日志文件 用户授权 查看日志信息

从服务器的必须配置步骤

制定server_id 并重启数据库服务

确保与主服务器数据一致:在主服务器做

数据读写分离

50 做客户端

51、52 mysql一主一从结构

56 做读写分离服务器

mysql数据读写分离 相关理论

什么是mysql数据续写分离

    • 指的就是对数据的select访问
    • 指的就是对数据的insert update delete 访问
  • 数据读写分离指的就是 把客户端对数据的读访问和写访问分别给不同的数据库服务处理
  • 为什么要使用数据读写分离架构?
    • 减轻数据库服务器的访问压力
    • 架构存储的缺点就是 单点故障 解决办法靠可用集群解决

图扑结构

客户端(网站) --》 读写分离服务器–》如果是查询的话直接发给slave服务器;如果是更改数据的话,直接发送发哦master服务器

实现数据读写分离功能的服务软件(mysql中间件)

中间件:指的就是架设在数据库服务和客户端之间的服务软件

中间件软件的功能各不相同,有实现分布式存储的 读写分离的

实现数据读写分离的开源服务前软件有:mysql-proxy maxscale MyCat

# 配置数据读写分离存储架构,具体操作如下
# 第一步:准备数据库服务器
# 配置mysql主从同步结构
# 把数据库服务器51配置master服务器
# 把数据库服务器52配置slave服务器
# 配置过程见上面的主从配置
# 查看52 从数据库服务器上面的IO和SQL线程是否为yes
show slave status \G
 Slave_IO_Running: Yes
Slave_SQL_Running: Yes

# 在主机56配置读写发额不您里服务
# 说明56主机不他哦共数据存储服务器mysql
# 不需要运行mysqld
具体操作如下
1.安装软件
2.修改主配置文件
3.配置数据库服务前器
4.启动读写分离服务
5.查看监视信息
6.测试配置
yum -y install maxscale-2.1.2-1.rhel.7.x86_64.rpm 
cp /etc/maxscale.cnf /root/    # 主配置文件的备份
vim /etc/maxscale.cnf

[maxscale] # 就是读写分离启动后的线程个数
threads=auto# threads=auto   设置为自动的个数,根据cpu的性能和个数去创建

[server1]
type=server
address=192.168.4.51
port=3306
protocol=MySQLBackend

[server2]
type=server
address=192.168.4.52
port=3306
protocol=MySQLBackend

[MySQL Monitor]
type=monitor
module=mysqlmon
servers=server1,server2
user=mysqla# 这里是监视server1和server2的用户
passwd=123456#这里是监视server1和server2的密码
monitor_interval=10000

[Read-Write Service]# 检查server1和2里面创建的用户
type=service
router=readwritesplit
servers=server1,server2
user=mysqlb  # 检查mysql里面的用户 
passwd=123456
max_slave_connections=100%

[MaxAdmin Service]
type=service
router=cli

[Read-Write Listener]
type=listener
service=Read-Write Service
protocol=MySQLClient
port=4006

[MaxAdmin Listener]
type=listener
service=MaxAdmin Service
protocol=maxscaled
socket=default
port=4016
   
# 51 和 52 数据库添加用户mysqla和mysqlb
# 因为两台数据库是主从同步结构,所以只需要在51上面添加的就可以,52会自动同步
# 51  
grant replication slave ,replication client  on *.* to mysqla@"%" identified by '123456';
replication slave   获取主从角色状态的权限
replication client  获取数据库服务状态的权限
grant select on mysql.* to mysqlb@"%" identified by '123456';
# 52
select user   from mysql.user where user in ('mysqla','mysqlb');

# 启动56主机的读写分离服务
# 说明: 如果第二步和第三步配置有问题,及时启动了服务也不能正常工作
# 测试授权用户mysqla  和  mysqlb
mysql -h192.168.4.51 -ymysqla -p123456
mysql -h192.168.4.52 -umysqlb -p123456
# 启动读写分离服务
无论服务启动成功与否,都是会有日志文件 /var/log/maxscale/
maxscale /etc/maxscale.cnf
怎么查看服务有没有起来:直接查看端口4406
ss -tunlp | grep 4006
ss -tunlp | grep 4016
读写分离服务为期必须指定51和52 上数据库服务是否是运行
那台数据库是master角色服务器 那台是slae角色服务器
才能
maxadmin -uadmin -pmariadb -P4016

P(大写): 是指定端口号
p(小写):指定的是密码
MaxScale> list servers  # 直接查看里面的状态master和slave


# 杀死进程
killall -a maxscale 

# 总结一下

# 测试配置
具体操作如下
第一步:在主服务器上面51 添加用户 (给客户端连接服务使用)

第二步: 给客户端联机分离服务器,查询数据和存储数据

第三步: 测试数据读写分离

# 51
 create database bbsdb;
create table bbsdb.a(id int);
grant select ,insert on bbsdb.* to jing99@'%' identified by '123456';

# 在客户端访问51
mysql -h192.168.4.56 -P4006 -ujing99 -p123456 # 这里提示一下就是mysqlb是检查上面的用户和对应的访问权限
insert into bbsdb.a values(666);
select * from bbsdb.a;

# 检测
select @@hostname;  显示主机名
mysql -h192.168.4.56 -P4006 -ujing99 -p123456
select @@hostname; 显示的是52的主机名
insert into bbsdb.a values (999); # 如果这过数据没有在51上面添加的话,在52上面查的话,是不会查的到数据的,
select * from bbsdb.a;
# 所以验证了,查的就是在52上面查的,插入数据的就是在51上面操作的

测试读写分离的第二种方法
第一步 在从服务器添加新数据(在从服务器添加主服务器不会同步)
第二步 客户端连接写分离服务器连接查询

# 52
insert into bbsdb.a values (252);
# 51
select * from bbsdb.a; # 发现上面是没有252 的
# 56
select * from bbsdb.a;  # 发现上面是有252的,所以说明了查询是在52上面查询的,而不时是在51上面查询的。

mysql多实例

什么是多实例

  • 在一台物理主机上运行多个数据库服务

为什么要使用多实例

  • 节约运维成本
  • 提高硬件利用率
在56主机mysql多实例的配置
说明  要把5.7 版本的mysql服务停止
rpm -qa |grep mysqld
systemctl stop mysqld
systemctl disable mysqld
rm -rf /etc/my.cnf
scp -r /linux-soft/4/mysql/mysql-5.7.20-linux-glibc2.12-x86_64.tar.gz  192.168.4.56:/root 
tar xf mysql-5.7.20-linux-glibc2.12-x86_64.tar.gz 
mv mysql-5.7.20-linux-glibc2.12-x86_64 /usr/local/mysql
# 部署服务运行环境
id mysql || useradd mysql
rpm -q libaio || yum -y install libaio
# 把命令添加到系统环境变量$PATH
ls /usr/local/mysql/bin/  # 源码路径
vim /etc/bashrc 
export PATH=/usr/local/mysql/bin:$PATH
echo $PATH
source /etc/bashrc # 执行环境变量 ,将/usr/local/mysql/bin/添加到path里面
echo $PATH

编写多实例服务的配置文件(要求在56主机运行2个数据库服务)

说明:在一台物理主机上运行多个数据库服务器,每个服务都要有如下的独立文件

  • 数据库目录 datadir:这个是指定目录在那里的
  • 端口号 prot=
  • 存放进程pid号文件
  • 存放服务启动信息和报错信息的日志文件
  • socker文件(数据库服务自己连接自己时候 ,通过socker文件进行通信)
vim /etc/my.cnf
socket=/var/lib/mysql/mysql.sock  这一行是自带的:
ls /var/lib/mysql # 就是如果服务停止了就,没有这个文件了,没有这个文件,就会连接失败
# 就是如果在一台服务器跑多个数据库的时候必须要有多个socker文件啦


独立文件:
管理多实例服务的运行参数
[mysqld_mulit]  指定管理多实例  服务的运行参数

修改数据库管理员密码使用的命令
user=root  去启动多实例服务的用户名
mysqld=/usr/local/mysql/bin/mysqld_safe   多实例服务启动是调用的启动文件
mysqladmin= /usr/local/mysql/bin/mysqladmin

[mysqld数字]  
datadir=数据库目录
port=端口号
pid-file=存放进程pid号文件
log-error=存放服务启动信息和报错信息的日志文件


如果上面有/etc/my.cnf的话需要删除

启动实例

在56主机运行2个数据库服务
ls /etc/my.cnf   # 没有,因为上面已经删除了
vim /etc/my.cnf
[mysqld_multi]
user=root
mysqld=/usr/local/mysql/bin/mysqld_safe
mysqladmin= /usr/local/mysql/bin/mysqladmin

[mysqld1]
datadir=/dir1
port=3307
log-error=/dir1/mysqld1.err
pid-file=/dir1/mysqld2.pid
socket=/dir1/mysqld1.sock

[mysqld2]
datadir=/dir2
port=3308
log-error=/dir2/mysqld2.err
pid-file=/dir2/mysqld2.pid
socket=/dir2/mysqld2.sock


# 启动实例1
mysqld_multi start 1 # 会创建数据库目录的,最后一行会出现密码
ss -tunlp | grep 3307
ls /dir1/
mysql -uroot -p'VTq(X+S -S /dir1/mysqld1.sock  # 初始密码
set password='123456';   # 没有密码策略要求
mysql -uroot -p123456 -S  /dir1/mysqld1.sock

# 停止服务,需要跟上用户名和密码 
mysqld_multi stop --user=root --password=123456 2  # 停止实例2
ls /dir2/  # 发现没有/dir2/mysqld2.sock   文件了
ss -tumlp | grep 3308  # 端口号也没有了

MySQL数据分布式存储

使用mysql服务存储数据时,实现数据的分布式存储

分布式存储 是怎么存储数据的?

把数据存储在不同地点的数据库服务器里,每台数据库里存储的数据各不相同

分布式存储的相关概念

数据分片概述

相关概念

  • 分库/分表

    • 什么是分库分表
      • 将存放在一台数据库服务器中的数据,按照特定方式进行拆分,分散存放到多台数据库服务器中,以达到分散单台服务器负载的效果
  • 水平分割

    • 横向切分
      • 按照表中指定字段的分片规则,将表记录按行切分,分散存储到多个数据库中
  • 垂直分割

    • 纵向切分
      • 将单个数据库的多个表按业务类型分类,分散存储到不同的数据库

MyCAT介绍

软件介绍

  • mycat是基于java的分布式数据库系统中间件,为高并发环境的分布式存储提供解决方案
    • 适合数据大量写入的存储需求
    • 支持mysql、oracle、sqlserver、mongodb等
    • 提供数据读写分离服务
    • 提供数据分片服务
    • 给予阿里巴巴cobar进行研发的开源软件

分片规则

  • mycat支持提供10中分片规则

    1. 枚举法 sharding-by-infile
    2. 固定分片 rule1
    3. 范围约定 auto-sharding-long
    4. 求模法 mod-long
    5. 日期列分区法 sharding-by-date
    6. 通配取模 sharding-by-pettern
    7. ASCII码求模通配 sharding-byprefixpattern
    8. 变成指定 sharding-by-substring
    9. 字符串拆分hash解析 sharding-by-stringhash
    10. 一致性hash sharding-by-murmur
  • 主要讲的是

    • 枚举分片规则 sharding-by-infile

      • 分片字段的值必须在分片规则配置文件定义的值里选择
      • 表使用了分片规则存储数据 ,建表时必须创建分片规则要求的表头名
      • 枚举分片规则表里必须有名称叫做;sharding_id 的表头名
      • 数据管理员在分片规则配置文件定义分片字段的值
    • 求模分片规则

      • 使用分片字段的值与指定 的数字做取余计算 根据余数存储数据到后端的数据库服务器里

        • 如果余数是数字0 就把记录存储到第一台数据库服务器里面(dn1)
        • 如果余数是数字1 就把记录存储到第一台数据库服务器里面(dn2)
        • 如果余数是数字2 就把记录存储到第一台数据库服务器里面(dn3)
      • 使用求模分片规则存储数据的表里必须有名称叫id的表头(分片字段)

      • <table name="employee" primaryKey="ID" dataNode="dn1,dn2,dn3"
        			   rule="sharding-by-intfile" />
        <table name="customer" primaryKey="ID" dataNode="dn1,dn2,dn3"
        			   rule="sharding-by-intfile">
        
      • sharding-by-intfile 分片规则的配置文件

        vim /usr/local/mycat/conf/partition-hash-int.txt # 定义分片字段的值
        10000=0      0代表dn1数据库  51   10000代表分片字段的值
        10010=1      1代表dn2数据库  52
        10020=2      # 手动添加,这是第三台主机
        /usr/local/mycat/bin/mycat restart
        ss -tunlp | grep 8066  # 一定要检查端口
        # 如果没查到端口,直接去查看/usr/local/mycat/logs/wrapper.log 日志文件
        
      • 在客户端50连接mycat服务建表

        说明:执行任何命令都要use TESTDB 库里执行,所有命令直接写表名
        mysql -h192.168.4.57 -P8066 -uroot -p123456
        show databases;
        use TESTDB
        show tables ;
        create table employee(sharding_id int, name char(10),basic int );
        insert into employee(sharding_id ,name,basic) values (10000,'jin',28000);
        insert into employee(sharding_id ,name,basic) values (10020,'tom',12345);
        insert into employee(sharding_id ,name,basic) values (10010,'toed',12345);
        insert into employee(sharding_id ,name,basic) values (10030,'to',12345)  #   can't find any valid datanode :EMPLOYEE -> SHARDING_ID -> 10030这个就不能存储了,因为分片规则里面没有10030的值
        
        # 接下来在每台数据库服务器上面查看数据 ,就会发现每台服务器个一行
        select * from db1.employee;  
        select * from db2.employee;
        select * from db3.employee;
        
        
      • 查看使用求模分片规则的表

        <table name="hotnews" primaryKey="ID" autoIncrement="true" dataNode="dn1,dn2,dn3"
        			   rule="mod-long" />
        
      • 创建hotnews的表

        mysql -h192.168.4.57 -P8066 -uroot -p123456
        show databases;
        use TESTDB
        show tables ;
        create table hotnews(id int, title char(10),comment varchar(100),worker char(10));
        # 余数是0的都会往第一台服务器上面存储
        insert into  hotnews(id ,title,comment,worker) values(3,'a','aaa','AAA'),(6,'b','aaa','fff'),(9,'c','ccc','cccc');
        # 余数是1的都会往第二台服务器上面存储
        insert into  hotnews(id ,title,comment,worker) values(10,'a','aaa','AAA'),(10,'b','aaa','fff'),(10,'c','ccc','cccc');
        # 依此类推
        # 51
        select * from db1.hotnews;
        # 52
        select * from db2.hotnews;
        # 53
        select * from db3.hotnews; # 因为没有余数是2的,所以第三个数据库是没有数据的
        

工作过程

  • 当mycat收到一个sql命令时
    • 解析sql命令涉及到的表
    • 然后看对表的配置,如果有分片规则,则获取sql命令里分片字段的值,并匹配分片函数,获取分片列表
    • 然后将sql命令发往对应的数据库服务器去执行
    • 最后收集和处理所有分片结果数据,并返回客户端

目录结构

ls /usr/local/mycat
bin    # mycat命令
catlet      # 扩展功能
conf      # 配置文件
lib      # mycat使用的jar包
logs      # mycat启动日志和运行日志
wrapper,log      # mycat服务启动日志
mycat.log      # 记录SQL脚本执行后的报错内容

# 重要配置文件说明
server.xml      # 设置连接账号与逻辑库
schema.xml      # 配置数据分片存储的表
rule.xml      # 分片规则
其他文件      # 分片规则配置文件

拓扑结构

  • 数据分片拓扑结构
    • 客户端–》分片服务器(根据表分配规则)–》数据库服务器(多台)
  • 数据库服务器51.52.53 ,分片服务器57(不需要数据库服务器),客户端50

配置分布式存储服务器

第一步: 配置分片服务器57,具体操作如下
# 安装软件
# 了解安装文件列表

# 配置数据库服务器

# 启动mycat服务  并查看服务器状态


# 57
scp -r /linux-soft/4/mysql/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz    192.168.4.57:/root
systemctl stop mysqld.service 
systemctl disable mysqld.service
# 因为mycat是用java编写的所以需要安装jdk软件
# 而且版本有要求
yum list | grep openjdk.x
yum -y install java-1.8.0-openjdk.x86_64  # 因为mycat 的版本所以需要的是这个版本
tar xf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz 
mv mycat/ /usr/local/
ls /usr/local/mycat/  # 通过修改下面的文件来达到分片处理

cat /usr/local/mycat/version.txt  # 查看软件的说明信息
/usr/local/mycat/log  
/usr/local/mycat/lib/  # 存放的是java脚本,不能动的
/usr/local/mycat/conf/  # 存放的是配置文件,一共有三种类型的配置文件
# .xml 是mycat的主配置文件
# .txt 和 .properties 都是分片规则的配置文件,不同的名称就是不同的分片规则
# .conf
/usr/local/mycat/catlet/ # 就是与其他软件协同工作存放文件的目录
/usr/local/mycat/bin/  # 主要操作的是mycat这个文件  
# /usr/local/mycat/bin/mycat --help  查看主要的操作步骤

# 修改配置文件(修改两项)
定义客户端连接mycat服务使用的用户名、密码、虚拟库名(修改配置文件所在的目录/usr/local/mycat/conf/server.xml,这个文件使用默认配置即可,不需要修改)xml是扩展标记语言,就是需要成对出现  要有开始,要有闭合 
# 定义用户的是 ·····   这就表明是一个用户
 # 注释符号  
 
# 第二个是修改 /usr/local/mycat/conf/schema.xml  这个文件是极其重要的
# 定义数据分片存储数据的表,及使用的分片规则
user 枚举分片规则  就是在这里修改的
在没有修改之前看一下这个文件的语法规则,,头两行内容是不能动的,动了会起不来服务
所有的配置想都是要在<mycat:schema .....>  <mycat:schema>
这对标签里面
在配置里面的三项配置
# 定义存储数据的表名和使用的分片规则
<schema name..>  </schema>
# 定义数据服务器主机名及存储数据的库名
<dataNode ..... />  单标签 

# 定义数据库的IP地址
<dataHost....>  </dataHost>


这个文件里面是有读写分离的配置的
wc -l /usr/local/mycat/conf/schema.xml  查看里面有77行
vim /usr/local/mycat/conf/schema.xml
# 删除56-77行的内容,删除部分都是注释
sed -i '56,77d' /usr/local/mycat/conf/schema.xml
sed -i '16,18d' /usr/local/mycat/conf/schema.xml
cp /usr/local/mycat/conf/schema.xml /root  # 备份文件

# 开始修给数据的第一项
<table> 这个标签是指定表的
<table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />
# 将里面的表后面每与后dataNode没有dn3的都添加上dn3,其他项不需要修改

# 定义数据库服务器的定义数据库
修改
<dataNode name="dn1" dataHost="mysql51" database="db1" />
<dataNode name="dn2" dataHost="mysql52" database="db2" />
<dataNode name="dn3" dataHost="mysql53" database="db3" />
dataHost="mysql51" # 这里的名称是可以随意的,但是一般是以主机名指定
database="db1" # 接下来需要在51 上面创建db1的数据库

# 定义数据库服务器的IP
删除单标签的<writeHost>u<readHost>
删除完了之后就是这些
<dataHost name="mysql51" maxCon="1000" minCon="10" balance="0"
                  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select user()</heartbeat>
        <writeHost host="hostM1" url="192.168.4.51:3306" user="pljadmin"
                           password="123qqq...A">
        </writeHost>
</dataHost>
最终修给了name="mysql51" host="hostM1"# 这个说明是第一台主机 
url="192.168.4.51:3306" user="pljadmin" password="123qqq...A"

# 配置数据库服务器(51,52,53)添加schema.aml文件中设置内容
create database db1 ;  51
create database db2 ;  52
create database db3 ;  53
grant all on *.* to pljadmin@'%' identified by '123qqq...A'; 51 52 53 
以上数据库的内容就配置完了

# 接下来就是启动mycat服务
# 准备工作  定义主机名
把57的物理内存调制到1G以上,不然会带不动mycat
检查3台数据库服务器的授权信息pljadmin
which mariadb || yum -y install mariadb
mysql -h192.168.4.51 -upljadmin -p123qqq...A
mysql -h192.168.4.52 -upljadmin -p123qqq...A
mysql -h192.168.4.53 -upljadmin -p123qqq...A
检查完三个用户,才能开启mycat
ls /user/local/mycat/logs/   没有启动的时候,没有日志消息的
/usr/local/mycat/bin/mycat  start  启动mycat
ss -tunlp | grep 8066 
ls /user/local/mycat/logs/  # 启动之后就可以看的到有日志文件了
# 如果启动了。没有查看到端口的话,就查看/user/local/mycat/logs/waepper.log 日志文件


# 测试
# 在客户端50连接mycat服务查看存储数据的表
mysql -h192.168.4.57 -P8066 -uroot -p123456

show databases; 就可以看到假的库名
show tables ; 就可以查看到在/usr/local/mycat/conf/schema.xml文件里面设置的表了

添加新库新表

服务器配置

  • 添加新库
    • 添加server.xml
  • 添加新表
    • 修改schema.xml

注意:分布式存储数据,表名是不允许重复的

例子:想gamedb库下的user 表存储数据时,把数据分别存储在51、52、53服务器上

第一步:添加新库
第二步:添加新表
第三步:重启mycat
第四部:客户端mycat服务建表存储数据
第五步:
vim /usr/local/mycat/conf/server.xml 
<user name="root">
        <property name="password">123456</property>
        <property name="schemas">TESTDB,GAMEDB</property>
</user>

<user name="user">
        <property name="password">user</property>
        <property name="schemas">TESTDB,GAMEDB</property>
        <property name="readOnly">true</property>
</user>
vim /usr/local/mycat/conf/schema.xml  # 手动添加一个数据库
<schema name="GAMEDB" checkSQLschema="false" sqlMaxLimit="100">
        <table name="user" rule="mod-long"  dataNode="dn1,dn2,dn3"/>
</schema>

/usr/local/mycat/bin/mycat  restart
ss -tunlp | grep 8066

# 客户端50
mysql -h192.168.4.57 -P8066 -uroot -p123456
show databases ;
use GAMEDB;
show tables;
create table user(id int ,name char(10),password char(6));
# 余数是2 ,所以直接在53上面查看数据
insert into user(id,name ,password)  values(5,"a","aaa"),(5,"b","bbb");
# 53
select * from db3.user ;

MHA集群概述

什么是集群? 多台服务器一起提供相同的服务 比如提供网站服务 就是web集群 再比如提供数据库服务 就是数据库集群 比如提供的内存存储服务 就是缓存集群

集群的类型?

高性能(HPI) 高可用 负载均衡集权(LB)

负载均衡集群

  • nginx

高可用集群 集群中的服务器是怎么工作的?

  • 工作模式是 主备模式
  • 主角色的服务器 :正在提供服务前的主机
  • 备用角色服务器:监视主服务器 发现主不能提供服务器时候 ,自动顶替主继续提供服务
  • keepalived

高性能集群

  • 集群中的服务器一起做运算

MHA介绍

MHA简介(perl脚本语言编写的功能软件)

  • MHA(master high availability)
    • 由日本DeNA公司youshimaton开发
    • 是一台优秀的实现mysql高可用的解决方案
    • 数据库的自动故障切换操作能做到在30秒内完成
    • MHA能确保在故障切换过程中最大限度保障数据的一致性。以达到真正意义上的高可用
    • 切换的时候会有数据丢失(一丢丢)

MHA组成

  • MHA manager (管理节点)
    • 管理所有数据库服务器
    • 可以单独部署在一台独立的机器上
    • 也可以部署在某台数据库服务器上
  • MHA Node(数据节点)
    • 存储数据的Mysql服务器
    • 运行在每台mysql服务器上

MHA工作过程

MHA工作过程

  • 具体如下
    • 有Manager定时检测集群中的master节点
    • 当master故障时,Manager自动将有最新数据的slave提上为新的master

如果默认情况 relay_log_purge=1 时,SQL 线程就会自动将之前的 relay log 全部删除。而当 relay_log_purge=0 时,旧的 relay log 则会被保留。虽然这并不会影响从库复制本身,但还是会有地雷:

  • 由于崩溃或停止 MySQL 时,SQL 线程可能没有执行完全部的 relay log,最后一个 relay log 中的一部分数据会被重新下载到新的文件中。也就是说,这部分数据重复了两次。
  • 如果 SQL 跟得很紧,则可能在 IO 线程写入 relay log ,但还没有将同步到磁盘时,就已经读取执行了。这时,就会造成新的文件和旧的文件中少了一段数据。
集群搭建准备
51、52、53 数据服务器分别启用半同步复制
开启自动

集群环境准备
所有数据库服务器做公共配置(51、52、53)
创建集群
验证集群功能
把宕机的数据库服务器在添加到集群里

# 51、52、53
vim /etc/my.cnf
[mysqld]
validate_password_policy=0
validate_password_length=6
plugin-load="rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so;"
rpl_semi_sync_master_enabled=1
rpl_semi_sync_slave_enabled=1
server_id=51     # 这里的51 是根主机IP写的,也可以随便写
log_bin=master51   # 这里的51 是根主机IP写的,也可以随便写
relay_log_purge=0   #禁止自动删除本机的中继日志文件
systemctl restart mysqld
mysql -uroot -p123456
grant replication slave on *.* to repluser@'%' identified by '123456';
select * from mysql.user \G

# 配置面秘登录  配置ssh
# 所有数据库服务器之间免密登录
# 管理主机能够免密登录所有数据库
# 所有主机都要操作的步骤 # 57 也需要做作,可以无密码登录51  52  53 
ssh-keygen 
ssh-copy-id 192.168.4.51 52 53

# 配置mysql一主多从结构
51配置为master服务器
52配置slave服务器
53 配置slave服务器

启用binlog日志文件  用户授权   
从服务器 制定serverid    数据库管理员登录制定主服务器信息  启动slave
# 51
mysql -uroot -p123456
show master status ;
# 52 53
mysql -uroot -p123456
change  master  to master_host='192.168.4.51',  master_user='repluser',master_password='123456',master_log_file='master51.000001',master_log_pos=441;
start slave;
show slave status \G
           Slave_IO_Running: Yes
           Slave_SQL_Running: Yes
# 一主两从配置完成了
# 创建集群   配置管理主机(57)   配置数据库服务器(51、52、53)  测试配置   验证集群功能
# 57  安装软件 (先安装依赖包)   创建并修改主配置文件   创建故障切换脚本
scp -r /linux-soft/4/mysql/mha-soft-student 192.168.4.57:/root
# yum源需要配置好
cd mha-soft-student/
app1.cnf  master_ip_failover  是事先写好的配置文件
perl 开头的是依赖软件
yum -y install perl-*.rpm  # yum没有的
yum -y install ExtUtils-* perl-CPAN*  # 这个是yum里面有的
tar xf mha4mysql-manager-0.56.tar.gz
cd mha4mysql-manager-0.56/
perl Makefile.PL # 发现有两个包没有
yum list | grep -i perl | grep -i mysql
yum -y install perl-DBD-MySQL.x86_64
yum -y install mha4mysql-node-0.56-0.el6.noarch.rpm
cd mha4mysql-manager-0.56/
perl Makefile.PL # 可以了  这个是解压源码
make && make install   # 安装  masterha_ tab键 可以tab出来 就说明安装成功了  这个是管理软件
# 创建并修改管理服务的主配置文件
mkdir /etc/mha  # 创建工作目录
 cd mha-soft-student/mha4mysql-manager-0.56/ #拷贝主配置文件的模板到工作目录下
cp samples/conf/app1.cnf  /etc/mha/
vim /etc/mha/app1.cnf
         [server default]  # 管理服务运行配置参数
         manager_workdir=/etc/mha    # 工作目录
         manager_log=/etc/mha/manager.log  # 日志文件
         # 故障切换脚本
         master_ip_failover_script=/etc/mha/master_ip_failover  
         # 免密登录的用户和端口
         ssh_user=root  
         ssh_port=22
         # 拷贝binlog日志命令时候的连接用户
         repl_user=repluser
         repl_password=123456
         # 监控数据库服务状态时候的用户  监控用户
         user=plj
         password=123456
         [server1]   # 第一台数据库服务器
         hostname=192.168.4.51
         port=3306
         candidate_master=1    # 竞选主服务器
         
         [server2]  # 第二台数据库服务器
         hostname=192.168.4.52
         port=3306
         candidate_master=1
         
         [server3]   # 第三太数据库服务器
         hostname=192.168.4.53
         port=3306
         candidate_master=1

# 创建故障切换脚本
cp /root/mha-soft-student/master_ip_failover /etc/mha/  # 将写好的脚本拷贝
chmod +x /etc/mha/master_ip_failover 
# 指定ip地址及地址部署在那块网卡上
# 注意 :网卡名要根据数据库使用的网卡名填写
vim +35 /etc/mha/master_ip_failover
my $vip = '192.168.4.100/24';  # Virtual IP 
my $key = "1";
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip";  # 部署vip地址
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down";   # 释放vip地址

# 配置数据库服务器(51、52、53)
# 根据vip 地址部署在当前mysqld主从结构中的主数据库服务器51上
# 51
 ifconfig eth0
 ifconfig eth0:1 192.168.4.100/24  # 添加虚拟IP 临时的虚拟IP 因为是虚拟IP,必须是临时的
 # 如果添加错误了,需要在真机上面去掉 ifdown eth0:1
 # 创建监控用户plj (51\52\53)
grant all on *.* to plj@'%'  identified by '123456';  # 在主数据库服务器添加,从会自动添加 
# 52.53 
select user from mysql.user ;  # 可以查看到用户


# 测试配置  说明: 要求环境准备是对的 关路主机的appl.cnf文件是正确的 数据库服务器的配置是正确的   如果不对,测试命令会输出相应的报错信息
# 57
masterha_check_ssh  --conf=/etc/mha/app1.cnf  # 测试免密登录 
masterha_check_repl  --conf=/etc/mha/app1.cnf # 测试mysqld主从同步
# 测试没过  /usr/local/share/perl5/MHA/MasterMonitor.pm line 374 
# 所有数据库服务器上安装mha_node 软件 
scp -r /linux-soft/4/mysql/mha-soft-student 192.168.4.53:/root # 51/52/53
cd mha-soft-student/
yum -y install perl-*.rpm  # 安装依赖环境
yum -y install mha4mysql-node-0.56-0.el6.noarch.rpm

masterha_check_repl  --conf=/etc/mha/app1.cnf # 再次测试 Health is OK
# 启动管理服务
masterha_manager --conf=/etc/mha/app1.cnf   # 默认是占用一个终端显示的
masterha_manager --conf=/etc/mha/app1.cnf  & #这样不能保证在后台运行的
nohup masterha_manager --conf=/etc/mha/app1.cnf  &  # 这样一定是运行的
masterha_check_status --conf=/etc/mha/app1.cnf # 检查是否运行
jobs # 查看后台运行的程序
kill %1  # 杀掉后台的程序
# nohup
# 用途:不挂断地运行命令。
# 语法:nohup Command [ Arg … ] [ & ]
#   无论是否将 nohup 命令的输出重定向到终端,输出都将附加到当前目录的 nohup.out 文件中。
#   如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。
#   如果没有文件能创建或打开以用于追加,那么 Command 参数指定的命令不可调用。
# 退出状态:该命令返回下列出口值:   
#   126 可以查找但不能调用 Command 参数指定的命令。   
#   127 nohup 命令发生错误或不能查找由 Command 参数指定的命令。   
#   否则,nohup 命令的退出状态是 Command 参数指定命令的退出状态。
优化参数
--remove_dead_master_conf  把党纪的master服务器的配置在app1.cnf文件里删除
--ignore_last_failover  做多次vip迁移 默认只做一次故障迁移
nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  &  # 添加优化参数之后再运行程序

# 验证集群功能
# 在主数据库服务添加客户端连接使用的用户和密码
# 客户端连接vip192.168.4.100访问数据库服务
# 存储数据
# 查询数据
# 51  : 从服务器会自定同步了
mysql -uroot -p123456
create database db1;
create table db1.a(id int);
grant select,insert on db1.* to yaya666@'%'  identified  by '123456';
# 客户端50连接100访问数据库
mysql -h192.168.4.100 -uyaya666 -p123456
select * from db1.a;
insert into db1.a values  (1);


# 测试高可用  : 把master角色服务器51的数据库停止  客户端依然可以连接vip访问192.168.4.100进行连接   在app1.cnf文件里面没有[server1] 的配置了, 管理服务会停止  启动查看管理服务的运行状态  启动管理服务会监视新的主数据库服务器   另一台会数据库服务器会自定做新的master服务器的从机

# 把51数据库服务器停止的
systemctl stop mysqld
# 57  检测到51宕机了,就会执行/etc/mha下面的脚本,将vip放到从服务器
masterha_check_status --conf=/etc/mha/app1.cnf
服务状态就会停止了,
# 50
mysql -h192.168.4.100 -uyaya666 -p123456
select * from db1.a;
insert into db1.a values(999);
# 57 
cat /etc/mha/app1.cnf # 会发现没有server1的配置了,因为在运行程序的时候加入了优化参数,所以会将配置文件中server1删除 ,主服务器就变成了52,53就变成了52的从服务器了,因为规定MHA集群必须是主从或主从从结构,其他结构的话会报错
nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  &  # 再将程序开启,
masterha_check_status --conf=/etc/mha/app1.cnf # 再次查看监视的主服务器
# 52 查看vip
ifconfig eth0:1  #就会发现是有虚拟IP
# 53 
mysql -uroot -p123456
show slave status \G # 查看masterhost 主是52


# 注意:管理服务监控到当前master服务器宕机后,管理服务会停止
要让管理服务监视新的主服务器,要管理员手动启动管理服务才可以
写一个计划任务去执行监视管理服务的脚本,  脚本的功能发现管理服务停止了,就启动管理服务
*/10 * * * * 每隔十分钟去执行一遍监视管理服务状态的脚本

# 把宕机的数据库服务器51再添加到集群上面
# 想要进集群必须是当前主服务器的从才可以
# 启动51主机的数据库服务器
# 把51配置为当前master服务器slave主机
# 把51主机添加到app1.cnf文件里面
# 测试主从配置
# 重启管理配置
#51
systemctl start mysqld 
ss -tunlp | grep 3306
ifconfig eth0:1 
mysql -uroot -p123456 -e 'show slave status ;'
# 52 数据完全备份
mysqldump -uroot -p123456 -B db1 > /root/db1.sql
scp /root/db1.sql 192.168.4.51:/root 
mysql -uroot -p123456 -e 'show master status ;'
# 51 
mysql -uroot -p123456 < /root/db1.sql
mysql -uroot -p123456
change  master  to master_host='192.168.4.52',  master_user='repluser',master_password='123456',master_log_file='master52.000001',master_log_pos=688;
start slave ;
show slave status \G
# 57
vim /etc/mha/app1.cnf
[server1]   # 第一台数据库服务器
hostname=192.168.4.51
port=3306
candidate_master=1
masterha_check_status --conf=/etc/mha/app1.cnf
masterha_stop  --conf=/etc/mha/app1.cnf # 停止配置服务
jobs
nohup masterha_manager --conf=/etc/mha/app1.cnf --remove_dead_master_conf --ignore_last_failover  &  # 重新开启,既是将51添加到集群里面了
masterha_check_status --conf=/etc/mha/app1.cnf # 再次查看主还是52

PXC集群

PXC概述

内置了mysqld服务

PXC介绍

  • percona XtraDB Cluster (简称PXC)
    • 是基于Galera 的MySQL高可用集权解决方案
    • Galera Cluster 是Codership 公司开发的一套免费开源的高可用方案
    • PXC集群主要有两部分组成:Percona server Wuth CtraDB 和 Write Set Replication patchs(同步、多主复制插件)
    • 官网http://galeracluster.com

PXC特点

  • 具体如下
    • 数据强一致性、无同步延迟
    • 没有主从切换,无需使用虚拟IP
    • 支持InnoDB存储引擎
    • 多线程复制
    • 部署使用简单
    • 支持节点自动加入,无需手动拷贝数据

相应端口

  • 服务端口

    端口 说明
    3306 数据库服务端口
    4444 SST端口
    4567 集群通信端口
    4568 IST端口
    SST state snapshot Transfer 全量同步
    IST incremental state Transfer 增量同步
创建3台新的虚拟机(不安装任何版本的mysqld数据库服务软件)
ip  71 72 73
将pxc拷贝到三台机器上面
scp -r /linux-soft/4/mysql/pxc 192.168.4.73:/root 
# 配置PXC  mysql高可用集群,具体操作如下
第一步  分别 71 72 73 安装pxc软件  
# 注意: 软件之间有以来  所有软件

# 71 72 73
cd pxc/
yum -y install libev-4.15-1.el6.rf.x86_64.rpm percona-xtrabackup-24-2.4.13-1.el7.x86_64.rpm qpress-1.1-14.11.x86_64.rpm  # 顺序不能变,相互之间是有依赖的
rm -rf libev-4.15-1.el6.rf.x86_64.rpm percona-xtrabackup-24-2.4.13-1.el7.x86_64.rpm qpress-1.1-14.11.x86_64.rpm
tar xf Percona-XtraDB-Cluster-5.7.25-31.35-r463-el7-x86_64-bundle.tar
yum -y install Percona-XtraDB-*.rpm

# 修给各个配置文件
cd /etc/percona-xtradb-cluster.conf.d/
vim mysqld.cnf  
[mysqld]
server-id=71   # 修改为71 以IP为主  指定server-id
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
log-bin
log_slave_updates
expire_logs_days=7

# 修改集群配置文件  说明:3台数据库服务器都要修改 其中如下配置项的值必须相同
vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf   # 这是集群配置文件,每台服务器都要修改
wsrep_cluster_address=gcomm://192.168.4.71,192.168.4.72,192.168.4.73   # 指定的是成员列表  三台数据库服务器必须是一样的
wsrep_node_address=192.168.4.72  # 25行   # 修改为本机IP地址 
wsrep_cluster_name=pxc-cluster  # 三台数据库服务器必须是一样的
wsrep_node_name=pxc72 # 指定本机的主机名
wsrep_sst_auth="sstuser:123qqq...A"  # 39  用户名跟密码 三台数据库服务器必须是一样的

# 初始化集群信息  说明: 在三台任意一台都可以执行初始化,但是初始滑操作只能执行一遍
# 在71上做集群初始化操作
ls /var/lib/mysql  # 空的 
systemctl start [email protected]  # tab不出来 必须记住
ls /var/lib/mysql 
ss -tunlp |grep 3306 
ss -tunlp |grep 4567
# 数据库管理员使用初始密码 登录 并强制修改密码
grep password /var/log/mysqld.log 
mysql -uroot -p'X1fqsw*ZvJ)='
set password='123456';   # 没有策略要求
show databases;
grant all on *.* to sstuser@'%' identified by '123qqq...A'  # 添加配置文件中设置的用户跟密码

# 分别启动72 73主机的数据库服务  服务启动后会自动同步71的所有数据
# 72  要求:配置文件是对的,防火墙和selinux是关闭的
systemctl start mysql  # 注意,没有d   第一次同步是全量同步  所以需要的时间比较久 在按黄pxc软件的时候是内置了同步程序了,是通过配置文件去同步的
ls /var/lib/mysql 
ss -tunlp |grep 3306 
ss -tunlp |grep 4567
mysql -uroot -p123456   # 因为已经同步了,所以用户密码都是一样的
select user from mysql.user ;
# 72 和 73 的操作是一样的


# 测试
# 查看集群信息   
# 在任何一台服务器上面都可以查看集群信息
mysql -uroot -p123456 
show status like "%wsrep%";
# wsrep_incoming_addresses 192.168.4.72:3306,192.168.4.71:3306,192.168.4.73:3306   集群中一共有这么几台机器
#  连接集群中的任意数据库服务器  查询和存储数据
# 73
create database db1;
create table db1.user(id int primary key  auto_increment ,name char(10) ,age int );   # 在PXC存储数据的时候 必须要有主键
grant select ,insert on db1.* to plj@'%' identified by '123456';
# 71 72 
mysql -h192.168.4.71 -uplj -p123456  # 使用添加的用户连接服务器 任意一台都是可以的
insert into db1.user(name,age) values ('to45m',12),('o74o',19);  # 在PXC集群中  主键的自增的步长可能是小于 3+1 任意一个数  ,集群主机数量加1 ;为了避免数据同步的时候 主键相同 
select * from db1.user ; # 发现主键id可能是1,2,3,4


 # 测试宕机主机自动加入集群及自动同步宕机期间的数据
 # 统一把71数据库停止 (模拟宕机) 说明:71首次停止的是原来的服务
 systemctl stop [email protected]   # 首次停止服务是这个命令
ss -tunlp |grep 3306 
ss -tunlp |grep 4567 # 是没有端口的了  这个是判断是否宕机的端口的
 # 在另外两台查看集群信息  存储新数据  (在71宕机期间,存储数据)
 # 72 
 show status like "%wsrep%"; #192.168.4.72:3306,192.168.4.73:3306 
 insert into db1.user(name,age) values ('yy',12),('opp',19);
 # 73 
 select * from db1.user ;
 # 启动71主机数据库  查看集群信息 查看数据
 # 71
systemctl start mysql
ss -tunlp |grep 3306 
ss -tunlp |grep 4567 
mysql -uroot -p123456
show status like "%wsrep%";  # 发现又有三台数据库的IP了
select * from db1.user ;  # 数据也同步了

MySQL存储引擎

概述

  • MySQL存储引擎介绍?
    • 存储引擎MySQL服务功能组件之一,当对数据做查询和存储时候 会根据表使用的存储引擎,对表中的数据处理 不同的存储引擎功能和数据存储方式各不相同
  • mysql服务的体系架构 mysql服务软件由8个功能组建促成 组件各司其职
    • 管理工具:mysql服务软件安装后,提供的管理命令
    • 连接池:数据库服务器接受到客户端的连接后,会调用连接池检查数据库是有空闲的mysqld线程处理客户端的连接请求 会检查用户名和密码 及其访问权限
    • SQL接口:把用户登录后执行的sql命令传递给本机的mysql服务处理
    • 分析器:检查命令的语法 和 是否对数据有访问权限
    • 优化器:通常对执行的select查询命令做用化 ,以最节省硬件资源的方式去执行查询数据的select;
    • 查询缓存: (默认没有启动),占用物理存储空间 存放曾今查找过的数据
      • 就是查询的时候是先去缓存里面查找,没有再去硬盘上面查找,查找了,就会放到缓存中,方便下次查询,
      • show variables like “%cacahes%”;
      • 一般生产环境不会使用到mysql 的缓存的,会有专门的缓存数据库的
    • 存储引擎 : mysql服务的功能分类 对表中的数据做访问时候 , 根据表使用的存储引擎 对访问的数据做处理,每种存储引擎的功能和数据存储方式各不相同
    • 文件系统:指的是存储数据的硬盘

查看存储存储引擎

查看数据库服务支持的存储引擎
show engines ;
CSV                
PERFORMANCE_SCHEMA 
BLACKHOLE          
MyISAM             
InnoDB   # 这个后面是defaults 的说明是建设表时候默认的              
ARCHIVE            
MRG_MYISAM         
FEDERATED          
MEMORY 
# 表头
Comment # 对存储引擎功能的说明  
Transactions # 是否支持事务

# 例子
create database db1;
create table db1.enployees(name char(10),class varchar(100));
show create table db1.enployees \G # 就可以查看到存储引擎了,
show create table mysql.user \G # 查看到user 表是myisam存储引擎
# 修改存储的默认存储引擎
vim /etc/my.cnf
default-storage-engine=myisam  # 设置默认的存储引擎为myisqm
systemctl restart mysqld
show engines ;   # 管理员登录查看结果
create table db1.test (name char(10));
show create table db1.test \G

# 建表时候 ,指定表的存储引擎
create table  db1.user12(age int ,name char(10))engine=memory;
show create table db1.user12 \G

# 表的存储引擎不同  数据存储方式不同
show create table mysql.user \G 
ls /var/lib/mysql/mysql/user*  # 发现是有三个文件的,user.frm  user.MY user.MYD
show create tarena.salary \G  # innodb
ls /var/lib/mysql/tarena/salary  # 发现是有连个文件  salary.frm  salary.idb 
show create db1.user \G # memory
ls /var/lib/mysql/db1/user12*  # 只发现。frm文件

表的存储引擎不同 数据存储方式不同

修改表的存储引擎

  • 要在没有存储数据之前,修改表的存储引擎

  • alter table db1.user engine=innodb ;
    show create table db1.user ;
    ls /var/lib/mysql/db1/user*  # 变成了两个文件,就多了一个文件去存储数据
    

MySQL体系结构

  • 共8个功能组件

MySQL工作过程

  • 查询/存储数据的工作过程

存储引擎介绍

  • 作为可插拔式的组件提供
    • MySQL服务软件自带的功能程序
    • 不同的存储引擎有不同的功能和数据存储方式
    • MySQL 5.0/5.1 MySQL 5.5/5.6(InnoDB)

常用存储引擎的特点

没有好坏之分,看需求

  • myisam存储引擎的特点

    • 不支持事务 和 事务回滚
    • 支持表级锁
    • 每个表对应3个表文件
      • 表明.frm 存放表头信息 : desc
      • 表名.MYI 存放表头的索引信息 show index from …
      • 表名.MYD 存放表的数据 insert into 存放的数据就在这里
  • innodb存储引擎的特点

    • 支持事务 和 事务回滚
    • 支持行级锁
    • 每个表对应2个表文件
      • 表明.frm 存放表头信息 : desc
      • 表名.idb 存放表头的索引信息和表里的数据
  • 专业术语:

    • 事务 : 连接成功 执行sql命令 断开连接
      • 指的是
    • 事务回滚:在事务执行失败的时候,把恢复到出错之前的状态
    • 事务回滚是怎么实现的呢?
      • 数据库服务会使用事务日志文件对innob存储引擎的表执行过的sql操作
      • 事务日志ls /car/lib/mysql/lib_logfile0(原文件) ib_logfile1(备份文件)
    • mysql服务的锁机制 是解决对数据的并发访问冲突问题
      • 例子:
      • 连接1 update tarena.t1 set name=‘a’ where id =1 ;
      • 连接2 update tarena.t1 set name=‘s’ where id =1 ;
      • 这个时候这就是并发访问冲突问题了
    • 表级锁(myisam) 只要是对表中的行做操作,就把正张表锁上 只有表被释放后才运行其他连接对表的数据做访问
    • 行级锁(innodb) 仅对表中备份访问的行分别加锁,没有被访问的行不加锁。不加锁就可以被其他的连接访问
    • 锁粒度(加锁的范围)
      • 读锁:如果执行的是select查询命令 加的是读锁 , 读锁又叫做共享锁,允许同时有多个读访问,但是不允许写访问
      • 写锁 如果执行的是insert update delete访问 ,加的就是写锁 写锁又称为排它锁,既不允许读,也不允许写访问
# 演示
mysqldump  -uroot -p12346 tarena user > /root/user.sql
vim /root/user.sql
LOCK TABLE `user` WRITE  # 这个就是锁表了
UNLOCK  TABLES;  # 解锁 

# 开两个终端
LOCK TABLE `tarena.user`  WRITE;
select * frim tarena.user ; # 在另外个终端的操作  就会卡住了
UNLOCK   TABLES;  # 另外个终端才会执行sql命令  

事务的特性

  • ACID
  • 原子性:一个事务中的所有操作,要么完成,要么全部不完成
  • 一致性:在事务开始之前和事务结束以后,数据库的完整性不会被破坏
  • 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改而互不影响
  • 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
# 什么叫一致性
insert into tarena.user (name ) values ('aa'); 没回车之前,所有人都是看不到数据的,回车后,才可以查看的到
# 当有两个人同时操作表,是互相不知道对方操作什么的,这个就是隔离性

TCL事务控制语言

  • 对事物做管理的命令

    命令 作用
    begin或start transaction 显示开启一个事务
    commit 提交事务
    rollback 回滚事务
    savepoint 名称 在事务里创建保存点(可以创建多个)
    release savepoint 名称 删除保存点
    rollback to 保存点 把事务回滚到保存点
    set transaction 设置事务隔离级别
    set autocommit=0/1 关闭/启动自动提交
    select @@tx_isolation 查看当前事务隔离级别
    show vartables like “autocommit” 查看自动提交状态
  • insert into tarena.user(name) values('AAA'); # 一按下就提交了
    shwo variables like  "autocommit"  # 默认是开启的,就是命令一敲下就直接提交了
    set autocommit=0;  # 关闭自动提交功能  ,所以需要每次都需要提交
    # 事物是对数据生效的
    create table tareana.t33(id int )engine=innodb;
    insert into tarena.t33 values (101);
    select * from tarena.t33;  # 在自己这里是可以查看到的,
    # 打开另外一终端查看是查看不到的,这个就是隔离性了
    commit;  # 这样事务才算是结束  这就是事务的一致性和隔离性的效果
    
    # 演示事务回滚
    delete from tarena.t33;   # 在自己这里看是看到记录是已经删除的,但是在另外终端是还有数据的
    roolback  #事务的回滚    ,数据记录就回来了
    # 如果删除之后,马上commit的话,是不会回滚的
    # 断开连接再登录就已经是还原的了自动提交功能
    

事务隔离解决的问题:

  • 脏读:读到了其他事务未提交的数据,读到的数据并不一定是最终存储到数据库里的数据
  • 可重复读:可重复读的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据都是一致的
  • 不可重复读:一个事务先后读取同一条记录,而事务在两次读取之间该数据被其它事务所修改,则两次
  • 幻读:一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足起查询条件外的数据(就是两次查看数据不一样)

事务隔离级别

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

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

  • 可重复读:对同一字段的多次读取结果都是一致的;除非数据是被本身事务自己所修改;可以阻止脏读和不可重复读,但幻读仍有可能发生

  • 序列化:最高 隔离级别,完全俯冲ACID的隔离级别。所有的事务依次逐个执行,事务之间完全不可能产生干扰。该级别可以防止脏读和不可重复读,及幻读。

  • 级别越高,处理效果越底

  • 从上到下,隔离强度逐渐增强,向能逐渐变差。采用那种隔离级别要根据系统需要权衡决定,其中,可重复读就是MySQL的默认级别

    # 两个终端
    select @@tx_isolation;  # 默认是可重复读的级别
    set auot_commit=0 # 关闭自动提交 1
    set session transaction isolation level read uncommitted # 设置其他人的隔离级别为读未提交   2
    select @@tx_isolation;# 2
    select * from tarena.t33 ; #1
    insert into tarena.t33 values (8888) ; #1
    select * from tarena.t33 ;#2  就会发现是1没提交的数据了,
    rollback ;#1  事务回滚
    select * from tarena.t33 ;#2 就发现没有数据了,这就是脏读了,因为对方是没有提交的
    
    
    # 可重复读
    select * from tarena.t33 ; #1
    insert into tarena.t33 values (8888);#1
    select * from tarena.t33 ;#2 是查看不了的
    
    
    
    

工作建表时候 怎么决定使用那种存储引擎,总结

innodb 使用

  • 写(insert update dalete) 访问多的表 好处是并发访问量大

myisam 适用

  • 读访问多的表 。节省系统的资源(主要节省CPU使用时间)

NoSQL数据库管理

NoSQL概述

数据库类型

数据库服务软件的类型,分为2重

关系型数据库服务管理系统 (RDMS)

非关系型数据库服务管理系统 (NoSQL)

软件有那些?

存储数据的特点是什么?

RDBMS
  • 关系数据库管理系统
    • Relational Database Management System
    • 按照预先设置的组织结构,将数据存储在物理介质上
    • 数据之间可以做关联操作
  • 主流的RDBMS软件
    • MySQL
    • Mariadb
    • Oracle
    • DB2
    • SQL server
    • postgreSQL
NoSQL
  • NoSQL (NoSQL = Not Only SQL)
    • 意思是“不仅仅是SQL”
    • 泛指非关系型数据库
    • 不需要预先定义数据存储结构
    • 每条记录可以有不同的数据类型和字段个数
  • 主流软件
    • Memcached
    • Redis
    • MongoDB
    • CouchDB
    • Neo4j
    • FlockDB

搭建Redis数据库服务器

Redis

  • Remote Dictionary server(远程字典服务器)

  • 是一款高性能的(key/alues)分布式内存数据库

  • 支持数据持久化(定期把内存里数据存储到硬盘)

  • 支持多种数据类型:字符、列表、散列、集合

  • 支持master-salve模式数据备份

# 在50主机上面部署redis
scp -r /linux-soft/4/redis/redis-4.0.8.tar.gz 192.168.4.50:/root
yum -y install gcc
tar xf redis-4.0.8.tar.gz 
cd redis-4.0.8/   # 已经有编译完成了Makefile 
make && make install 
redis-  <tab>两下
# redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli        redis-sentinel   redis-server   

# 初始化配置(确认服务的配置项)
# 说明:初始化配置完成后 会启动redis服务  并设置为开机运行
# 进到源码目录里面[root@localhost redis-4.0.8]#
./utils/install_server.sh  # 确认端口  redis主配置文件  服务的日志位置  redis数据库目录  启动时候启动的命令   @@ 一路回车
Selected config:
Port           : 6379 # 确认端口
Config file    : /etc/redis/6379.conf # redis主配置文件
Log file       : /var/log/redis_6379.log # 服务的日志位置
Data dir       : /var/lib/redis/6379  # redis数据库目录 
Executable     : /usr/local/bin/redis-server # 启动时候启动的命令
Cli Executable : /usr/local/bin/redis-cli  # 命令行连接命令

ss -tunlp | grep 6379  # 查看端口  127.0.0.1:6379  (默认的情况下是回环地址)
# 连接服务  redis-cli  默认连接本机的redis服务
redis-cli  # 登录
ping 
set school tarena
keys * # 查看所有的变量
get school  # 获取school的值
redis服务的停止与启动
/etc/init.d/redis_6379  stop  # 停止服务
/etc/init.d/redis_6379  start # 启动服务
修改redis服务使用的IP地址 服务监听的端口 设置连接密码
# 都是需要修改配置文件来实现的
/etc/init.d/redis_6379  stop  # 把按默认配置先停止服务
vim /etc/redis/6379.conf   # 主配置文件
port 6379  # 93  # 可以将端口更改为6350
bind 192.168.4.50  # 70   将回环地址配置为主机IP地址
requirepass foobared  # 501  foobared是密码  修改为123456
/etc/init.d/redis_6379 start
ss -tunlp | grep 6350  # 检查已经更改的端口

# 指定配置
redis-cli -h 192.168.4.50 -p 6350 -a 123456
set name plj
keys * 
不是按默认配置运行的redis服务,是不能使用脚本停止服务的
/etc/init.d/redis_6379 stop  # 接着上面的,发现停不下来
redis-cli -h 192.168.4.50 -p 6350 -a 123456  shutdown  # 指定使用命令停止了
ss -tunlp | grep 6350  # 查不到端口
/etc/init.d/redis_6379 start  # 启动服务还是可以使用默认配置启用服务

LNP+Redis

实验的诉求:那nginx 网站的数据存储到50主机redis服务器里面

第一步: 部署nginx网站服务器,具体操作如下
# 安装nginx依赖包 
# 安装源码nginx
# 修改nginx配置文件
# 启动nginx 服务
# 安装php相关软件
# 启动php-fpm服务
# 测试配置
 scp -r /linux-soft/4/redis/lnmp/nginx-1.12.2.tar.gz /linux-soft/4/redis/lnmp/php-redis-2.2.4.tar.gz /linux-soft/4/redis/lnmp/linkredis.php 192.168.4.51:/root

yum -y install gcc pcre-devel zlib-devel
tar xf nginx-1.12.2.tar.gz 
cd nginx-1.12.2/
./configure && make && make install 
ls /usr/local/nginx
 cd /usr/local/nginx
vim +65 conf/nginx.conf
sbin/nginx 
ss -tunlp | grep 80
yum -y install php php-fpm php-devel
systemctl start php-fpm
ss -tunlp | grep 9000
vim /usr/local/nginx/html/test.php
<?php
$i=99
echo $i
?>
curl  http://localhost/test.php 

ss -tunlp | grep 6350  #50
/etc/init.d/redis_6379 start  # 如果没有开启的话
 redis-cli -h 192.168.4.50 -p 6350 -a 123456  # 检查昨天的数据是否还在
 KEYS *   # 发现数据是还在的  这个就是说明Redis 的持久性    
 
 ss -tunlp | grep 80   # 51  检查nginx的服务是否起来
ss -tnulp|grep 9000  # 51  检查php-fpm的服务是否起来
curl  http://localhost/test.php    # 51  检查昨天的写的脚本

# LNP + Redis
配置51主机的php支持redis服务 (默认是不支持的)
php -m  # 查看php支持相应的功能模块
 php -m  | grep redis   # 发现是没有的
 # 安装提供redis模块的软件
 # 调用模块  php-redis-2.2.4.tar.gz
tar xf php-redis-2.2.4.tar.gz 
cd phpredis-2.2.4/
phpize   # 生成php配置程序的文件  生成了configure 
ls /usr/bin/php-config 
./configure --with-php-config=/usr/bin/php-config
make && make install # 安装的输出信息要注意一下  
/usr/lib64/php/modules/  # 说明 功能模块是放在这个目录下面的
当前php没有调用的,需要去修改配置文件才能调用
vim +728 /etc/php.ini  # php的进程配置文件
extension_dir = "/usr/lib64/php/modules/"  # 去掉# 后面的路径改为模块所在的路径 
extension= "redis.so" 模块是没有下划线制定dir的
systemctl restart php-fpm
php -m  | grep redis  # 发现是出现有支持redis 模块的了
 # 测试配置  (编写连接redis 服务存储数据的脚本)工作环境中是脚本是程序员写的
 cp linkredis.php /usr/local/nginx/html/test2.php
 vim /usr/local/nginx/html/test2.php
 <?php
$redis = new redis();  # 创建连接名令;也就是调用模块
$redis->connect('192.168.4.50',6350);  # 用模块连接数据库服务器
$redis->auth("123456");     # 指定连接的密码 
$redis->set('redistest','666666');   # 输入数据
echo $redis->get('redistest');   # 获取数据
?>
 # 在客户端访问网站的php脚本
 curl  http://localhost/test2.php
 # 在redis服务器本机查看内存数据
redis-cli -h 192.168.4.50 -p 6350 -a 123456  # 50  登录redis查看数据
KEYS *   # 50  可以查看到数据
GET redistest  # 查看values 


redis服务常用管理命令

常用命令

set  key名   key值       # 存储1个key值
mset   key名列表          # 存储多个key值
get  key名               # 获取key值
mget                     # 获取多个key值
select  数据库编号0-15     # 切换库 
keys   *                 # 显示所有key名
keys  a?                 # 显示指定key名
exists`   key名          # 测试key名是否存在 0/1
ttl   key名              # 查看key生存时间  -1 : 是永久
type  key名              # 查看key类型
move    key名   库型号    # 移动key到指定库
expire  key名   数字      # 设置key有效时间
del   key名              # 删除指定的key
flushall                 # 删除内存里所有的key
flushdb                  # 删除所有库的所有key
save                     # 保存所有key到硬盘
shutdown                 # 停止服务

配置文件解析

配置分类

  • /etc/redis/6379.conf

    名称 说明
    netword 网络
    general 常规
    snapshotting 快照
    replication 复制
    security 安全
    clients 客户端
    memory managenent 内存管理
  • 常用的配置项

    • port 6379 //端口
    • bind 127.0.01 //IP地址
    • deamonize yes //守护进程方式运行
    • databases 16 // 数据库个数
    • logfile /var/log/redis_6379.log //日志文件
    • maxclients 10000 //并发连接数据鲁昂
    • dir /var/lib/redis/6379 //数据库目录位置

内存清楚策略

内存清楚策略:向内存存储数据时候,若存储空间不足删除内存里已有数据的方式

  • 内存空间不足时,删除已存储

  • vim /etc/redis/6379.conf   # 找到MAXMEMORY  POLICY
    # 文件下面就有内存清除策略了5类  564左右
    
策略分类 说明 名称 删除范围
LRU 删除最近最少使用 volatile-lru 针对设置了TTL的key
allkeys-lru 针对所有的key
LFU 删除使用频率最少 volatile-lfu 针对设置了TTL的key
allkeys-lfu 针对所有的key
RANDOM 随机删除 volatile-random 针对设置了TTL的key
allkeys-random 针对所有的key
volatile-ttl 删除快要过期的
noeviction 不删除

优化设置

 vim /etc/redis/6379.conf   # 大概在591行左右   
 maxmemory-policy 策略方式
 
 maxmemory   //最大内存
 maxmemory-policy  //定义使用策略
 maxmemory-samples    //选取key模板个数(针对lru和ttl和lfu策略)

创建集群

准备环境

# 主机上面部署redis
for i in 51 52 53 54 56  ; do scp -r /linux-soft/4/redis/redis-4.0.8.tar.gz 192.168.4.$i:/root &&  ssh 192.168.4.$i && yum -y install gcc && tar xf redis-4.0.8.tar.gz  && cd redis-4.0.8/  && make && make install  ;done
./utils/install_server.sh 
ss -tunlp | grep 6379
/etc/init.d/redis_6379  stop  
vim /etc/redis/6379.conf  
bind 192.168.4.50  # 70   将回环地址配置为主机IP地址
cluster-enabled yes  # 815   启动集群功能
cluster-node-timeout 5000   #829  超时时间毫秒
/etc/init.d/redis_6379 start
ss -tunlp | grep redis-server  # 检查会发现有两个端口
sed -i '70c bind 192\.168\.4\.51' /etc/redis/6379.conf && sed -i '815c cluster-enabled yes' /etc/redis/6379.conf && sed -i '829c cluster-node-timeout 5000' /etc/redis/6379.conf && sed -i '823c cluster-config-file nodes-6379.conf' /etc/redis/6379.conf


创建集群

redis-trib 脚本

命令 描述
create 创建集群
check 检查集群
info 查看集群信息
reshard 重新分片
del-node 删除主机
add-node --salve 添加slave主机
add-node 添加master主机
rebalance 平均分配hash slots
# 创建集群
# 配置管理集群主机192.168.4.57
# 准备ruby脚本运行环境
yum -y install ruby
scp /linux-soft/4/redis/redis-3.2.1.gem  /linux-soft/4/redis/redis-4.0.8.tar.gz  192.168.4.57:/root   # 脚本   和源码包
which gem || yum -y install rubygems
gem install redis-3.2.1.gem  # 当前目录下面的gem包
# 创建ruby脚本
 tar xf redis-4.0.8.tar.gz  
 cd redis-4.0.8/ && ls src/*.rb
mkdir /root/bin   # 创建命令检索目录
cp /root/redis-4.0.8/src/redis-trib.rb  /root/bin   # 创建管理集群脚本
redis-trib.rb help    # 查看命令帮助


# 查看集群状态
redis-cli -h 192.168.4.51 -p 6379  # 51
192.168.4.51:6379> CLUSTER INFO
# cluster_state:fail  # 如果在集群里面的话是ok状态


# 在管理主机创建集群
# 注意:51~57 主机防火墙和selinux必须关闭    
# redis 服务器51~56 内存里不允许有数据
# redis服务器51~56 


#创建集群的命令格式  57主机
redis-trib.rb create --replicas 数字 //从数据库服务器的台数  redis服务器列表
说明
--replicas 数字 //从数据库服务器的台数
默认创建集群时候,默认会把redis服务器列表中前3台数据库配置为master服务器  redis服务器列表中其他服务器做salve服务器
redis-trib.rb create --replicas 1 192.168.4.51:6379 192.168.4.52:6379 192.168.4.53:6379 192.168.4.54:6379 192.168.4.55:6379 192.168.4.56:6379 # 意思就是一共是有三台主服务器和每台数据库服务器只有一个从服务器   服务器一定是3的整数倍
[OK] All 16384 slots covered.  # 意思是 16384个hash槽分配完毕
redis-trib.rb info 192.168.4.51:6379  # 查看集群信息
# 在管理主机查看集群详细信息
redis-trib.rb check 192.168.4.51:6379
# M  主服务器 后面的是id  下面的一行有标名slots 0~5460个槽
# S 从服务器   后面的是id   
 
# 在redis数据库服务器本机查看集群信息  如51主机
192.168.4.51:6379> CLUSTER INFO
cluster_state:ok   查看说明在集群里面的了

# 访问集群验证集群功能
!!!redis集群的功能,如下:
# 数据是分布式存储的
# 能实现服务高可用,主从结构中的主宕机后slave服务器自动升级为master   宕机的服务器恢复后  自动加入集群 并做当前主服务器的slave主机,自动同步宕机期间的数据。
# 数据自动备份
# 访问集群的命令格式  会根据集群算法的计算结果把数据存储在master服务器上
redis-cli -c -h 集群中任意主机的ip  -p 端口号  # -c 连接集群中的redis服务器,会自定调用集群算法存储数据

# 集群存储数据的工作原理 
访问客户端
例子  : 在50主机连接集群存储
redis-cli -c -h 192.168.4.52 -p 6379  # 因为之前50有安装过redis,所有有这个命令
192.168.4.52:6379> INFO replication   # 检查当前主机的集群角色
# Replication
role:master
connected_slaves:1   # 这个代表有一个从

192.168.4.56:6379> INFO replication  #  检查当前主机的集群角色
# Replication
role:slave
master_host:192.168.4.52   # 这个代表是主服务器的IP
192.168.4.53:6379> set name aa  # 53
-> Redirected to slot [5798] located at 192.168.4.52:6379  # 根据集群的计算结果存储到52上面



集群存储数据的存储原理

  • redis集权是如何实现数据的分布式存储的?
    • 存储数据和查询数据时候 调用集群算法 集群算法会计算出1个数字,数字在那个主服务器占用的范围内,就连接对应的主服务器存储数据或查询数据
[root@57 ~]# redis-trib.rb info 192.168.4.51:6379
192.168.4.53:6379 (e5edbde6...) -> 0 keys | 5461 slots | 1 slaves.
192.168.4.55:6379 (ac6b607d...) -> 0 keys | 5461 slots | 1 slaves.
192.168.4.52:6379 (f9820a19...) -> 1 keys | 5462 slots | 1 slaves.

192.168.4.53:6379> set q 0
192.168.4.53:6379> set z 12   # 根据集群计算结果在那个slot槽范围内  就存储在那个数据库上面
-> Redirected to slot [8157] located at 192.168.4.52:6379
192.168.4.52:6379> KEYS * 
1) "z"
192.168.4.52:6379> set v1 101
-> Redirected to slot [1165] located at 192.168.4.55:6379
192.168.4.55:6379> KEYS *
1) "v1"
# 槽越多,能存到该数据库的概率就越大  数据越大,表明存储到这个数据库的机会就越大
# 槽 是可以规定大小的  ,在配置集群的时候可以分配的,如果说,内存很大的话,可以重新分片

测试集群功能

故障切换测试

  • 通知master主机 的redis服务

    • master宕机后对应的slave自动被选举为master
    • 原master 启动后 会自动配置为当前master为slave
  • 检测集群

    • 在管理主机查看信息

      测试高可用
      # 没有停止之前在管理主机查看集群信息
      [root@57 ~]# redis-trib.rb info 192.168.4.51:6379
      192.168.4.51:6379 (0e30fdd2...) -> 0 keys | 5461 slots | 1 slaves.
      192.168.4.52:6379 (f9820a19...) -> 1 keys | 5462 slots | 1 slaves.
      192.168.4.53:6379 (e5edbde6...) -> 0 keys | 5461 slots | 1 slaves.
      
      # 把master角色之际的redis服务停止  
      [root@51 ~]# redis-cli -h 192.168.4.51 -p 6379 shutdown
      [root@51 ~]# ss -tunlp | grep  redis
      
      # 在管理主机查看集群信息  # 发现是少了一台从数据库服务器了
      redis-trib.rb info 192.168.4.52:6379
      192.168.4.52:6379 (f9820a19...) -> 1 keys | 5462 slots | 1 slaves.
      192.168.4.55:6379 (ac6b607d...) -> 0 keys | 5461 slots | 0 slaves.
      192.168.4.53:6379 (e5edbde6...) -> 0 keys | 5461 slots | 1 slaves.
      
      # 启动宕机服务
      /etc/init.d/redis_6379 start  # 将51redis数据库重新启动
       ss -tunlp | grep  redis  # 查询到两个端口
       # 在管理主机查看集群信息
      [root@57 ~]# redis-trib.rb info 192.168.4.52:6379  # 从数据库就会自动加入集群中
      192.168.4.52:6379 (f9820a19...) -> 1 keys | 5462 slots | 1 slaves.
      192.168.4.55:6379 (ac6b607d...) -> 0 keys | 5461 slots | 1 slaves.
      192.168.4.53:6379 (e5edbde6...) -> 0 keys | 5461 slots | 1 slaves.
      

管理集群

向集群里添加新服务器

说明: 什么情况下需要向集群里添加新主机(新添加master角色服务器)

  • 扩大内存空间(添加master角色服务器)
  • 为了保证服务的可靠性(给主服务器添加多个从服务器)

命令格式

redis-trib.rb add-node 新主机Ip:端口 集群中已有主机的ip:端口

添加master服务器

  • 部署一台新redis服务器
    • 运行服务并启用集群配置
  • 添加master主机步骤
    • 添加master主机
    • 分配hash槽
  • 添加master主机
    • 添加时不指定主机角色,默认新主机被选为master
    • 添加的master主机,需手动分配solts(槽)

分配hast slots(master角色的服务器没有hast slots得不到存储的集群

  • 命令格式

    • redis-trib.rb reshard 集群中已有主机的ip:端口
  • 重新分片

    • 移出hash槽个数
    • 接受hash槽主机ID
    • 移出hash槽主机ID
    • 同意配置

添加slave服务器

说明: 从角色服务器的数据是master服务器同步过来的数据

所以slave角色的服务器不需要分配hash slots 只要把主机添加到集群了所slots服务器就可以

命令格式
  • edis-trib.rb add-node --slave 新主机Ip:端口 集群中已有主机的ip:端口

  • 诉求:把redus服务器59添加到58的slvae服务器

  • 会自动做从服务器个数最少的master服务器的从服务器

  • 配置一台新redis服务器

    • 运行服务并启动集群配置
  • 添加slave

添加主机
添加master角色主机到集群里
1. 准备一台启用了集群功能的redis服务器  
创建新虚拟机配置ip地址为192.168.58 安装redis服务软件 初始化配置
停止服务 修改IP地址 启用集群功能  启用redis服务
scp -r /linux-soft/4/redis/redis-4.0.8.tar.gz 192.168.4.58:/root  
yum -y install gcc && tar xf redis-4.0.8.tar.gz  && cd redis-4.0.8/  && make && make install  
./utils/install_server.sh 
ss -tunlp | grep 6379
/etc/init.d/redis_6379  stop  
sed -i '70c bind 192\.168\.4\.51' /etc/redis/6379.conf && sed -i '815c cluster-enabled yes' /etc/redis/6379.conf && sed -i '829c cluster-node-timeout 5000' /etc/redis/6379.conf && sed -i '823c cluster-config-file nodes-6379.conf' /etc/redis/6379.conf
/etc/init.d/redis_6379 start
ss -tunlp | grep redis-server  # 检查会发现有两个端口

2. 在管理主机57把新主机58加到集群里
把58主机添加到集群里面
添加master角色主机的命令格式
redis-trib.rb add-node 新主机IP:端口号  集群中已有主机的IP:端口号
# redis-trib.rb add-node 192.168.4.58:6379 192.168.4.53:6379
# [OK] New node added correctly. 显示添加成功
redis-trib.rb info 192.168.4.53:6379  # 发现是没有hash槽  ,这样子就不会有存储数据的机会 ,还有一个风险就是单点故障,没有从机
  
给58主机分配hash槽
添加到集群里面master分配hash槽
因为没有hash槽得不到存储数据的机会。

想一下分配多少个hash槽给 58 主机使用合理? 16384/4    =   4096         
从当前3台主服务器里  各自拿出一部分hash槽给 58 主机

[root@host57 ~]# redis-trib.rb  reshard  192.168.4.53:6379
How many slots do you want to move (from 1 to 16384)?4096
What is the receiving node ID?  主数据库服务器的ID
Source  Node: ALL   (表示当前所有主服务器一起凑够4096个hash槽 给 新的主服务器)
Do you want to proceed with the proposed reshard plan (yes/no)? yes  同意

移出服务器

  • 移除slave主机
    • 从服务器没有hash槽,直接移除即可
    • 移除时候指定从服务器id值
  • 移出master服务
    • 配置步骤
      • 释放占用的hash槽
      • 移出主机
    • 释放占用的slots
      • 指定移出slots个数
      • 指定接收slots主机ID

命令格式[root@mgm57 ~]# redis-trib.rb del-node 集群中任意主机的Ip:端口 被移除主机的id

说明: slave角色的主机没有hash slots 直接移出就可以 主机被遗嘱集群后 redis服务自动停止

3.2.2  移除master角色的主机

		说明:master角色的服务器会占用hash slots  要先释放hash slots  再执行移除主机的命令
		
			具体操作步骤:
					第一步:释放 hash slots (再次执行reshard命令)
					第二步:移除主机 (执行删除主机的命令)
					
					
					
诉求把master角色 主机 host58移除集群,在管理主机mgm57 做如下操作:
		#释放 hash slots (再次执行reshard命令)
[root@mgm57 ~]# redis-trib.rb  reshard  192.168.4.56:6379
		
第1个问题:释放hash slots 的个数
How many slots do you want to move (from 1 to 16384)? 4096  (host58主机占用hash slots 的个数)

第2个问题:接收4096的个hash slots的主数据库服务器的ID (随便给那个主服务器都可以) 
What is the receiving node ID?0eb3b7aa0493a19189cba35b0c658202cc20884b   (host51主机的id ,就是把释放的4096个hash slots给主数据库服务器host51)

第3个问题:从那台主服务器移除4096个hash slots 
Source node #1:87cc1c128166e08a16cc294758611453bbc71437  (host58主机的id)
Source node #2:done 结束指定
第4个问题:确认配置 yes同意  no 退出		
Do you want to proceed with the proposed reshard plan (yes/no)? yes  同意


				查看集群信息(发现host51 主服务器hash slots变多了 )
[root@mgm57 ~]# redis-trib.rb  info  192.168.4.56:6379
192.168.4.53:6379 (f2c1bdb7...) -> 1 keys | 4096 slots | 1 slaves.
192.168.4.51:6379 (0eb3b7aa...) -> 3 keys | 8192 slots | 1 slaves. 槽多了 
192.168.4.52:6379 (a9cb8ccd...) -> 2 keys | 4096 slots | 1 slaves.
192.168.4.58:6379 (87cc1c12...) -> 0 keys | 0 slots | 0 slaves. 一个槽也没有了 
[OK] 6 keys in 4 masters. 
0.00 keys per slot on average.
[root@mgm57 ~]#				

				查看host58主机的id 然后删除主机 Host58
				
[root@mgm57 ~]# redis-trib.rb  check  192.168.4.56:6379 | grep  192.168.4.58
M: 87cc1c128166e08a16cc294758611453bbc71437 192.168.4.58:6379
[root@mgm57 ~]# 
[root@mgm57 ~]# redis-trib.rb  del-node   192.168.4.56:6379  87cc1c128166e08a16cc294758611453bbc71437				
>>> Removing node 87cc1c128166e08a16cc294758611453bbc71437 from cluster 192.168.4.56:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@mgm57 ~]# 
					再次查看集群信息 (没有host58 主机了 )
[root@mgm57 ~]# redis-trib.rb  info  192.168.4.56:6379
192.168.4.53:6379 (f2c1bdb7...) -> 1 keys | 4096 slots | 1 slaves.
192.168.4.51:6379 (0eb3b7aa...) -> 3 keys | 8192 slots | 1 slaves.
192.168.4.52:6379 (a9cb8ccd...) -> 2 keys | 4096 slots | 1 slaves.
[OK] 6 keys in 3 masters.
0.00 keys per slot on average.
[root@mgm57 ~]# 					

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~扩展知识
		
	   1) 平均分配当前所有主服务器的hash slots 
[root@mgm57 ~]# redis-trib.rb  info  192.168.4.56:6379  槽不平均
192.168.4.53:6379 (f2c1bdb7...) -> 1 keys | 4096 slots | 1 slaves.
192.168.4.51:6379 (0eb3b7aa...) -> 3 keys | 8192 slots | 1 slaves.
192.168.4.52:6379 (a9cb8ccd...) -> 2 keys | 4096 slots | 1 slaves.
[OK] 6 keys in 3 masters.
0.00 keys per slot on average.
[root@mgm57 ~]# 
	   
	   平均分配hash slots
[root@mgm57 ~]# redis-trib.rb	rebalance 192.168.4.56:6379
		
		再次查看平均了
	[root@mgm57 ~]# redis-trib.rb info 192.168.4.56:6379
192.168.4.53:6379 (f2c1bdb7...) -> 2 keys | 5462 slots | 1 slaves.
192.168.4.51:6379 (0eb3b7aa...) -> 2 keys | 5461 slots | 1 slaves.
192.168.4.52:6379 (a9cb8ccd...) -> 2 keys | 5461 slots | 1 slaves.
[OK] 6 keys in 3 masters.
0.00 keys per slot on average.

把移出集群的主机再次添加到集群里的步骤:

首先 启动redis服务 清楚前世记忆 然后才能添加到集群

比如把移出的58主机再添加到集群里面

# 首先58
/etc/init.d/redis_6379  start
ss -tunlp | grep 6379

redis-trib.rb add-node 192.168.4.58:6379  192.168.4.52:6379
会说明连接不上redis服务,因为上面是有数据的


redis -cli  -h 192.168.4.58 -p6379
cluster  info  # 发现还是ok 的  
cluster  reset  # 回复原来没有加入集群的状态
keys *  # 查看是否有数局
flushall  # 清楚所有的数据

# 就可以再次添加到集群里面了  
redis-trib.rb add-node 192.168.4.58:6379  192.168.4.52:6379  # 做主
redis-trib.rb rehard 


	2) 把移除的主机再次添加到集群里的步骤
				第一步: 启动Redis服务并清除前世记忆(在Redis服务器本机操作)
				第二步: 清空内存里的数据(在Redis服务器本机操作)
				第三步: 在管理主机执行执行添加命令(在管理主机执行)
				第四步: 查看是否添加成功(在管理主机执行)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~把移除host58再添加到集群里做master服务器
            #58主机启动服务并清除前世记录
[root@host58 ~]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@host58 ~]# netstat  -utnlp  | grep  -i redis-server
tcp        0      0 192.168.4.58:6379       0.0.0.0:*               LISTEN      4480/redis-server 1 
tcp        0      0 192.168.4.58:16379      0.0.0.0:*               LISTEN      4480/redis-server 1 
[root@host58 ~]#
[root@host58 ~]# redis-cli  -h 192.168.4.58 -p 6379
192.168.4.58:6379> cluster reset
OK
192.168.4.58:6379>				
192.168.4.58:6379> keys *
(empty list or set)
192.168.4.58:6379> 	
        #管理主机58 添加到集群里
[root@mgm57 ~]# redis-trib.rb add-node 192.168.4.58:6379  192.168.4.51:6351

        #查看集群信息 
[root@mgm57 ~]# redis-trib.rb info  192.168.4.51:6351  发现多了主服务器58


~~~~~~~~~~~~~~~~~~~~~~~~~~~~把 移除的59 再次添加到集群 做53主机的slave数据库服务器

命令格式
redis-trib.rb add-node --slave --master-id 主服务器的id   新服务器的ip:端口 集群中已有机器的Ip:端口  

                #启动53主机的redis服务并清除前世记录
]# /etc/init.d/redis_6379 start
]# redis-cli  -h 192.168.4.59 -p 6379
> cluster  reset
> exit

				#在管理主机查看host53主机的id
[root@mgm57 ~]# redis-trib.rb check   192.168.4.51:6351 | grep 192.168.4.53
M: d9c9ef29c07ad740a05fa7aaa4d96ce25fa089b5 192.168.4.53:6353
[root@mgm57 ~]# 
                #添加59主机做主服务器53的 slave服务器
[root@mgm57 ~]# redis-trib.rb add-node --slave --master-id d9c9ef29c07ad740a05fa7aaa4d96ce25fa089b5 192.168.4.59:6379 192.168.4.51:6351

				
				#查看集群信息
				
[root@mgm57 ~]# redis-trib.rb info  192.168.4.51:6351
192.168.4.51:6351 (4cf556bc...) -> 1 keys | 5461 slots | 1 slaves.
192.168.4.52:6352 (94cbe47c...) -> 3 keys | 5462 slots | 1 slaves.
192.168.4.53:6353 (d9c9ef29...) -> 2 keys | 5461 slots | 2 slaves.  53 有2台从服务器
[OK] 6 keys in 3 masters.
0.00 keys per slot on average.
[root@mgm57 ~]# 

把集群中的主机恢复为独立的数据库服务器

在是数据库服务器本机执行如下操作
#停止redis服务
				#注释掉配置文件中的集群功能
				#清空数据库目录
				#启动服务
				#连接服务查看不到集群信息 也没有数据

以数据库服务器host51为例演示:
[root@mgm57 ~]# redis-trib.rb info 192.168.4.56:6379
192.168.4.53:6379 (f2c1bdb7...) -> 2 keys | 5462 slots | 1 slaves.
192.168.4.51:6379 (0eb3b7aa...) -> 2 keys | 5461 slots | 2 slaves.
192.168.4.52:6379 (a9cb8ccd...) -> 2 keys | 5461 slots | 1 slaves.
[OK] 6 keys in 3 masters.
0.00 keys per slot on average.
[root@mgm57 ~]# 
				
[root@host51 ~]# redis-cli  -h 192.168.4.51 shutdown
[root@host51 ~]# vim  /etc/redis/6379.conf 
#cluster-enabled yes
#cluster-config-file nodes-6379.conf
#cluster-node-timeout 5000
[root@host51 ~]# 
[root@host51 ~]# rm -rf /var/lib/redis/6379/*
[root@host51 ~]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@host51 ~]# 
[root@host51 ~]# netstat -utnalp  |grep -i redis-server
tcp        0      0 192.168.4.51:6379       0.0.0.0:*               LISTEN      9082/redis-server 1 
[root@host51 ~]# 

[root@host51 ~]# redis-cli  -h 192.168.4.51 -p 6379
192.168.4.51:6379> keys *
(empty list or set)
192.168.4.51:6379> cluster info
ERR This instance has cluster support disabled  没有启用集群功能
192.168.4.51:6379> 
			#在管理主机查看集群信息看不到host51主机了 
[root@mgm57 ~]# redis-trib.rb info 192.168.4.56:6379
192.168.4.54:6379 (bdba7786...) -> 2 keys | 5462 slots | 1 slaves.
192.168.4.52:6379 (a9cb8ccd...) -> 2 keys | 5461 slots | 1 slaves.
192.168.4.58:6379 (87cc1c12...) -> 2 keys | 5461 slots | 0 slaves.
[OK] 6 keys in 3 masters.
0.00 keys per slot on average.
[root@mgm57 ~]#	



redis-cli  -h `ifconfig eth0 | awk 'NR==2{print $2}'` shutdown sed -i '815c # cluster-enabled yes' /etc/redis/6379.conf && sed -i '829c # cluster-node-timeout 5000' /etc/redis/6379.conf && sed -i '823c # cluster-config-file nodes-6379.conf' /etc/redis/6379.conf && rm -rf /var/lib/redis/6379/* && /etc/init.d/redis_6379 start && netstat -utnalp  |grep -i redis-server

创建redis集群的快速脚本

for i in 51 52 53 54 55 56 58 59;do  scp -r /linux-soft/4/redis/redis-4.0.8.tar.gz 192.168.4.$i:/root  ; done
yum -y install gcc && tar xf redis-4.0.8.tar.gz  && cd redis-4.0.8/  && make && make install  
./utils/install_server.sh 
ss -tunlp | grep 6379 && /etc/init.d/redis_6379  stop  
sed -i '70c bind `ifconfig eth0 | awk 'NR==2{print $2}'`' /etc/redis/6379.conf && sed -i '815c cluster-enabled yes' /etc/redis/6379.conf && sed -i '829c cluster-node-timeout 5000' /etc/redis/6379.conf && sed -i '823c cluster-config-file nodes-6379.conf' /etc/redis/6379.conf 
/etc/init.d/redis_6379 start && ss -tunlp | grep redis-server
# 集群控制器57
yum -y install ruby
scp /linux-soft/4/redis/redis-3.2.1.gem  /linux-soft/4/redis/redis-4.0.8.tar.gz  192.168.4.57:/root   # 脚本   和源码包
which gem || yum -y install rubygems
gem install redis-3.2.1.gem  && tar xf redis-4.0.8.tar.gz  && cd redis-4.0.8/ && ls src/*.rb && mkdir /root/bin   && cp /root/redis-4.0.8/src/redis-trib.rb  /root/bin  
redis-trib.rb create --replicas 1 192.168.4.51:6379 192.168.4.52:6379 192.168.4.53:6379 192.168.4.54:6379 192.168.4.55:6379 192.168.4.56:6379



# 添加master主机58
redis-trib.rb add-node 192.168.4.58:6379 192.168.4.53:6379
redis-trib.rb reshard 192.168.4.53:6379  # 重新分配 hash槽

for i in  58 59;do scp -r /linux-soft/4/redis/redis-4.0.8.tar.gz  192.168.4.$i:/root  && ssh 192.168.4.$i << EOF
yum -y install gcc
tar xf redis-4.0.8.tar.gz && cd redis-4.0.8/ && make && make install 
./utils/install_server.sh << EOF




EOF
exit
EOF
done




redis主从复制

与mysql主从同步功能都是一样的 都是实现数据自动备份的存储结构

redis主从复制 也分为主数据库服务器 和从数据库服务器2种角色

使用redis 主从副为至结构存储数据数据时候 ,也来连接主数据库服务器

redis主从辅助 结构分为“一主一从 一主多从 主从从

说明 默认redis服务运行后 就是master角色

主从复制结构 相关命令: 命令行制定主服务器信息 slaceof 主服务器IP 端口号

把配置保存到配置文件 config rewrite (永久生效)

查看复制信息命令 info replication

反客为主 (临时还原为主数据库服务器 slaveof no one

用来做服务器的机子是51 52 53
keys *
cluster  info 
info replication  

一主一从
例子 把52配置为51的从数据库服务器
因为redis服务器运行后默认就是master角色数据库服务器 所以做主数据库服务器不需要做任何配置
配置数据库52
[root@localhost ~]# redis-cli -h 192.168.4.52
192.168.4.52:6379> SLAVEOF 192.168.4.51 6379 
192.168.4.52:6379> CONFIG REWRITE
[root@localhost ~]# tail -1 /etc/redis/6379.conf 
slaveof 192.168.4.51 6379
 info replication    就可以查看是51的从数据库了
 info replication   # 51 上面就可以查看到冲服务器的资料
 
# 基于第一个实验  把数据库服务器53也配置为51的slave服务器  
[root@localhost ~]# redis-cli -h 192.168.4.53 -p 6379
192.168.4.53:6379> info replication
192.168.4.53:6379> SLAVEOF 192.168.4.51 6379 
192.168.4.53:6379> CONFIG REWRITE
[root@localhost ~]# tail -1 /etc/redis/6379.conf 
slaveof 192.168.4.51 6379
192.168.4.53:6379> info replication
192.168.4.53:6379> slaveof on one # 变回master

此刻在主数据库服务器51 查看  就有2个从数据库的信息拉
192.168.4.51:6379>  info replication

# 打开配置文件 找到slaveop  这一行         # 这是另外一种方法
slaveof 192.168.51 6379 
# 然后重启服务  


# 思考把主从结构中的从服务器永久恢复为独立的数据库服务器
基于上个实验一主多从 结构中的53永久回复独立的数据库服务器
主从从
要求 给一主一从机构中的52也配置为服务器,
192.168.4.53:6379> slaveof   no  one  # 身份虽然是更换了,但是数据还是在的 
192.168.4.53:6379> CONFIG REWRITE  或者   vim /etc/redis/6379.conf  将最后一行改为注释  但是需要重启服务才能实行
192.168.4.53:6379> SLAVEOF 192.168.4.52 6379 
192.168.4.53:6379> CONFIG REWRITE
192.168.4.53:6379> info replication


# 主从结构中的 从服务器不允许执行写操作命令  只能查看
# 带验证的主从结构的配置  就是主数据库服务器的redis服务设置了连接密码   配置从服务器必须指定主服务器的连接密码  才能连接成功同步数据   
练习
给 主从从结构中的主数据库服务器51设置redis的连接密码123456
config get requirepass  # 查询配置文件中账号是否有密码
config set  requirepass 123456  # 给账号输入密码
auth 123456  # 接下来需要输入密码才能够进行操作
config rewrite   # 将配置输入配置文件 进行永久化

然后在从数据库服务器52主机  指定51主服务器的连接密码
没指定之前是同步了数据的
config set masterauth 123456  # 设置主服务器的密码
config rewrite    # 写入配置文件
info replication # 能够连接上了说明是可以的了

redis主从+哨兵服务 51 52 53 56

实现redis集群的功能

redis的结构可以是一主多从 ,一主一从 主从从

使用主从从+哨兵服务 实现redis 集群的功能

要么全配置密码 ,要么全部都不配置连接密码

哨兵服务的工作过程: 服务运行过程中监视主从结构中的主数据库服务器 主坏掉后会把对应的从服务器升级为主服务器,坏调的主机回复后 会自动做当前主服务器的从主机

说明:如果主从结构中的主服务器上的redis服务设置的连接密码 ,那么其他的服务器都要设置连接密码 并且连接密码需要一样

其次 当坏掉的主服务器加入集群时候需要人为设置连接当前主服务器的密码

# 由于上面实验51是设置了连接密码的,所以下面都redis都是需要设置密码的
# 给52的主机redis服务设置连接密码
config set  requirepass 123456
auth 123456  # 设置了密码 的时候从是连接不上的,因为刚设置了密码,需要在从数据库服务器上面设置主的服务器密码,
config rewrite
# 配置53主机  指定连接主服务器的连接密码  给自己redis服务设置连接密码
config set masterauth  123456 # 指定主的服务器的连接密码
config set  requirepass 123456
auth 123456
config rewrite

# 配置哨兵服务器56  需要有redis的安装软件包
rm -rf redis-4.0.8  # 删除以前解压的源码
#安装redis软件(不需要做初始化配置)因为不需要使用到redis的存储功能
yum -y install gcc && tar xf redis-4.0.8.tar.gz  && cd redis-4.0.8/  && make && make install
# 创建并编辑哨兵服务的主配置文件
vim /etc/sentinel.conf
bind 192.168.4.56  # 哨兵的IP
port 26379  # 端口
sentinel monitor  redis_server 192.168.4.51 6379    1   
sentinel auth-pass  redis-server 123456

-- redis_server 给redis 起的别名 
-- 192.168.4.51 6379  redis的主IP和端口   
-- 1 哨兵的台数 
-- sentinel monitor 监视的主机
-- sentinel auth-pass  监视主机的服务器连接密码

# 哨兵启动的时候 就去监视主从结构当前的主,如果发现主宕机了,会把从升级为主服务器
# 启动哨兵服务
redis-sentinel /etc/sentinel.conf  # 会有启动信息输出,会占用终端显示
nohup redis-sentinel /etc/sentinel.conf &  # 可以将它放到后台运行
# 测试配置
# 没有停止51的redis服务之前,查看52主机的复制信息  52是slave角色  
redis-cli -h 192.168.4.52 -p 6379 -P 123456
192.168.4.52:6379> INfo replication  # 查看是slave角色
192.168.4.51:6379> info replication  # 查看是master角色
#停止51的服务查看52的角色
redis-cli -h 192.168.4.51 -p 6379 -P 123456 shutdown
192.168.4.52:6379> info replication
grep -i "sentinel monitor" /etc/sentinel.conf  # 查看56 上面的配置文件
# sentinel monitor redis_server 192.168.4.52 6379 1
cat  /etc/sentinel.conf # 就会发现是里面的内容已经是变多了的
# 启动51 的redis服务查看复制信息  会成为52的从服务器 ,但连接状态是down 需要指定连接密码
/etc/init.d/redis_6379 start
ss -tunlp | grep redis
192.168.4.51:6379> info replication  # 发现是down 状态 原因是没有连接主服务器的密码
192.168.4.51:6379> config set masterauth  123456
192.168.4.51:6379> auth 123456
192.168.4.51:6379> config rewrite
192.168.4.51:6379> info replication  # 再次查看就会发现是up状态了,这样就是已经是实现了哨兵模式了的

总结:

持久化

redis服务是先把客户端的数据保存在内存里面的

服务正常停止的情况下 会自动把内存里的数据复制到硬盘里

在服务运行过程中会把每一段时间 自动把内存里的数据复制到硬盘里面

实现的方法有两种

RDB:(默认使用的方法) 指的就是数据库目录下面的/demp.rdb 文件里面

按照配置文件设置的存盘频率 把内存里的数据 复制到硬盘里用demp.rdb 保存

AOF(默认没有启用) 类似于mysql数据库服务的binlog日志文件

以追加的方式记录用户在redis服务器上执行的写操作命令

RDB有个致命的弱点:意外宕机贵丢失某次的存盘频率的所有数据

AOF记录命令的方式

appendfsync always 703 实时记录 影响CPU的性能

appendfsync everysec 704 每秒记录一次

appendfsync no 705 只是把命令记录到aof文件里面不把命令产生

修复有问题的aof文件 当aof文件会导致服务不能启动

ls /var/lib/redis/6379/  # 可以通过备份dump.rdb此文件以达到数据备份的效果
redis-cli -h 192.168.4.53 -p 6379
192.168.4.53:6379> SAVE  # 将数据存盘
exit
cp /var/lib/redis/6379/dump.rdb  /opt/  # 备份数据
192.168.4.53:6379> FLUSHALL  # 删除数据
redis-cli -h 192.168.4.53 -p 6379 shutdown  # 停止服务
ls /var/lib/redis/6379/ #但是文件还是有的,但是没有数据
rm -rf /var/lib/redis/6379/dump.rdb  # 删除原有的目录
cp /opt/dump.rdb /var/lib/redis/6379/  # 将备份文件拷贝回来
 /etc/init.d/redis_6379 start 
redis-cli -h 192.168.4.53 -p 6379 # 登录上去还是可以查看数据的
验证存盘频率
# 验证RDB方式的存盘频率
第一个是  查看默认
 vim /etc/redis/6379.conf 
save 900 1    # 219行
save 120 10  # 修改为2分钟内存10个变量 就会触发存盘
save 60 10000
redis-cli -h 192.168.4.53 -p 6379 shutdown
/etc/init.d/redis_6379 start 
rm -rf /var/lib/redis/6379/dump.rdb # 为了实现到了存盘频率并且就可以创建文件
redis-cli -h 192.168.4.53 -p 6379  # 在里面创建十个以上变量并且到达指定时间就可以自动存盘了

启用AOF文件
vim /etc/redis/6379.conf
appendonly yes  # 674行 

192.168.4.53:6379> CONFIG SET appendonly yes  # 设置为yes
192.168.4.53:6379> CONFIG REWRITE  # 永久生效
ls /var/lib/redis/6379/appendonly.aof  # 就会发现有这个文件了,
通过备份AOF文件来实现数据的恢复
192.168.4.53:6379> MSET name bob age 10 add ddd  # 再存储点数据
cp /var/lib/redis/6379/appendonly.aof  /opt/
redis-cli -h 192.168.4.53 -p 6379 shutdown
rm -rf /var/lib/redis/6379/*
cp /opt/appendonly.aof  /var/lib/redis/6379/
/etc/init.d/redis_6379 start 
redis-cli -h 192.168.4.53 -p 6379 
192.168.4.53:6379> KEYS *
修复有问题的aof文件 当aof文件会导致服务不能启动
# 先查看服务的日志文件 找报错信息
grep -i 'logfile' /etc/redis/6379.conf
tarl 1 /var/log/redis_6379.log
redis-check-aof --fix /var/lib/redis/6379/appendonly.aof     

数据类型

可以在任何一台redis数据库服务器上面做都可以

注意;主从结构中的从是默认不支持写操作的

字符类型的相关管理命令
# 53
 slaveof   no  one
 CONFIG REWRITE
# /etc/redis/6379.conf  最后一样的配置改为注释  redis-cli -h 192.168.4.53 -p 6379 shutdown  /etc/init.d/redis_6379 start 如果哨兵模式没有关闭的话,会一直会成为从服务器
 set age  19 ex 20 # 设置变量并设置时间
 ttl age  # 查看变量还剩多少的存活时间
 set name bob px 20  # 这个是设置毫秒
 set x 201 xx  # 覆盖存储
 set x 301 nx  # 不覆盖存储
 get x  # 值还是201


 set zfc ABCDEF
 GETRANGE zfc 0 2  # 获取变量的指定范围值  从0开始
 GETRANGE zfc -2 -1  

 STRLEN zfc  # 统计变量字符串的个数

 APPEND zfc "HIJK"  # 给字符串最加HIJK  返回当前字符串的长度  当没有该变量的时候会创建该变量并且赋值

 set i 1
 DECR i  # 自减1  本来是字符串类型,但是如果是数值的字符串,会自转换为数值类型,再减1
 get i
 DECRBY i 2  # 定义自减的长度  
 INCR i  # 自加1 
 INCRBY i 2  # 定义自增的长度  但是不能加小数的
 INCRBYFLOAT i 2.5  # 可以加小数的指定命令

setbit  使用二进制数给变量赋值  目的是节省内存存储空间  计算机的进制
setbit 变量名  第几位  二进制数
二进制数 只能是0或1
计算机的进制单位 :G M K byts 位 
1G = 1024M ;1M = 1024k ; 1k = 1024byts 1byts = 8# 把1k换算成 二进制是多少位    1024×8
使用变量login 存储1年的游戏账号登录状态 
列表类型的相关管理命令

就是当前学过的数组

数组就是让一个变量存储多个值 多个值之间使用下标区分

后进先出 先出后进

 lpush teacher nb wk zzg nfx plj lx dmy  # 最后添加的在最前面
 LRANGE teacher 0 -1  
 KEYS *
 TYPE teacher  #是列表类型
 LLEN teacher  # 统计多少个值
 LINDEX teacher 2  # 将下标为2的值输出来
 lset teacher 3 panglijing  # 修改对用相应的值
 lpop teacher   # 将列表中的第一个元素弹出
 RPUSH teacher  A B C # 向已有的的列表最加元素,末尾
 RPOP teacher   # 弹出列表中最后的一个元素
 LREM teacher 1 nb # 移出元素
散列类型

也叫做hash类型

{name :”plj”,age : 19 } 类似与python里面的字典

一个变量可以存储多列 每列对应一个值

 HSET xng shell 60  # 创建hash类型 ,并
 KEYS *  
 type xng # 查看是hash类型
 HGETALL xng  # 把hash类型里面的值都显示出来
 hmset lzm addr bj
 HMSET lzm mail [email protected] tel 101 age 58  # 一次存储多个变量
 hget lzm tel  # 只要变量中的某一项元素的值
 HDEL xng shell db1 db2  # 一次删除多个元素
 HKEYS xng  # 查看hash类型中的键
 ZRANGE plj 0 -1 withscores  # 将对应的值也显示出来

集合数据类型分为2中

有序集合

 ZADD plj 10 game    # 值是可以重复的,但是变量名是不可重复的
 type plj  # 查看出来是zset有序集合类型
 ZRANGE plj 0 -1  # 显示所有变量名
 ZSCORE plj game   # 显示变量名对应的值
 ZRANGEBYSCORE plj 10 30  # 显示对应10到30之间的变量名
 ZCARD plj  # 查看有多少中变量名
 ZREM plj it cd  # 删除集合对应的变量名

set无序集合 : 没有下标的列表类型 但值是唯一的

# 使用一个变量存储爱好
 SADD plj sleep eat mony game
 type plj # 查看是set类型
 SMEMBERS plj # 查看所有值,是没有顺序的
 SREM plj mony  # 删除集合里面mony的值
 SADD xng sleep game it
 SINTER plj xng  # 两个集合的交集
 SUNION plj xng  # 两个集合的 ,重复的只显示一边
 SDIFF plj xng # 比较两个集合的不同之处
 SCARD plj  # 统计集合里面的元素
 SRANDMEMBER plj 1  # 随即输出一个爱好

回顾昨天学习的知识

1。 编写mysql多实例的配置文件 有2部分要自己编写 管理多实例服务的运行参数配置[mysqld_multi] 多实例的配置[mysqld1 ]…就是只要服务器硬件好就可以运行很多个数据库进程 启动实例的 启动 停止 连接

  1. mysql数据分布式存储 部署mycat服务实现数据的分布式存储 配置步骤如下 :首先安装软件 修改配置mycat服务的配置文件 server.xml (用来定义用户 密码 和 虚拟库名) schema.xml(定义那些表使用的分片规则 及存储数据的服务器的IP地址)
  2. 配置数据库服务器:创建存储数据的库 和 mycat连接用户(pljadmin)
  3. 启动mycat服务
  4. 分片规则的使用 sharding-by-intfile mod-long 求模
  5. 添加新库新表 首先添加新库是在server.xml 里面添加的 新表是在schena.xml里面添加的

昨天的只是点回顾 mysql高可用集群

使用mha软件+mysql主从同步 部署mysql高可用集群

具体配置过程: 主从同步必须配置 免密登录配置 所有数据库服务器都必须 启用binlog日志 用户授权 启用半同步复制功能 禁止自动删除中继日志文件 配置管理主机 安装软件 创建主配置文件并编辑 创建故障切换脚本 配置数据库服务器 : 创建监控用户 把故障切换脚本中制定的vip地址部署在当前主从结构中的主数据库服务器上 安装mha_node软件 测试配置: 测试ssh免密配置 测试主从同步配置 启动管理 注意: 要让管理服务 继续监视新下主数据库服务器 要认为的启动管理服务 测试配置 把宕机的数据库服务器得人为添加到集群里面 并要人为完成宕机期间的数据同步

回顾昨天的只是

PXC集群 pxc软件介绍 部署PXC 安装PXC软件 修改配置文件 mysqld。cnf wsreo.cnf 初始化集权 启动另外两台服务器的mysqld服务 查看集群信息 测试集群 MySQL存储引擎 什么是存储引擎 mysql服务的体系结构 存储引擎的管理 查看修改数据库服务使用的存储引擎 查看修改表使用的存储引擎 建表时候指定表使用的存储引擎管理 常用存储引擎的特点 myisam innodb 专业术语 什么是事务 什么是是事务回滚 表级锁 行级锁 读锁 写锁 晚自习完成的学习任务:数据库服务软件的类型RDBMS NoSQL 对应的服务软件有那些 关系型数据库有哪些 非关系型数据库有那些 他们之间的各自特点是什么 这个查看工作中需要那些数据库 Redis软件介绍 部署Redis服务器 192.168.4.50 网站服务器 192.168.4.51 LNP 今天要完成的任务是LNP+Redis 和部署Redis集群 (实现的需求 是把网站的数据存储在50主机的内存)

项目

核心思想

是第一阶段到第四阶段所学的知识

LVM NFS tomcat 格式化 挂载

数据迁移

数据服务的负载均衡+高可用集群

部署缓存服务实现网站(把网站的数据存放到内存里)

PXC keepalived haproxy redis集群

最终使用要完成的效果

给公司万站部署2太数据存储集群机构:

1套是硬盘存储集群架构 ,并要使用服务到高可用,数据的自动备份和服务的负载均衡

1套是内存存储集群架构,也要实现服务的高可用,数据的自动备份和服务的负载均衡

内存存储架构用来存储网站热点数据 和 可再生的数据 ,

day1

要完成的实验结果:

一 把网站的数据存储在mysql数据读写分离结构里面

1.1 把数据服务器额外添加两块LV 用来存储数据服务器的数据 (存储空间可以动态扩展)

1.2 把mysql服务的数据存储在逻辑卷里面

1.3 配置mysql主从同步

1.3.1 配置主数据库服务器mysql11

1.3.2 配置从数据库服务器mysql22

1.3.3

二 把网站的网页文件存储在NFS共享服务器里面

三 配置网站服务器

四 测试配置

4.1 测试tomcat

4.2 测试nfs配置

#在30编写连接mysqld服务存储数据的脚本

4.3

案例1:配置逻辑卷
          (把数据库服务器的数据存储到逻辑卷(LV)里,目的是可以动态扩展数据库服务器
             硬盘的存储空间)
			 具体步骤如下:
						1) 给2台数据库服务器mysql11 和  mysql22  分别添加2块5G的硬盘
						2) 划分物理分区 (/dev/vdb1   /dev/vdc1)
						3) 创建物理卷
						4)    创建卷组vg0
						5)    创建逻辑卷lv0
						6)    格式化lv0 (文件系统类型是xfs)
操作命令如下:
    4  systemctl  stop mysqld
    5  yum -y install lvm2
    6  lsblk 
    7  pvcreate  /dev/vdb /dev/vdc
    8  vgcreate vg0 /dev/vdb /dev/vdc
    9  vgs
   10  lvcreate  -n lv0  -L 5.99g vg0
   11  lvscan 
   12  mkfs.xfs /dev/vg0/lv0
   13  blkid  /dev/vg0/lv0

案例2:配置数据库服务器
			具体步骤如下:(2台数据库服务器主机分别做如下操作)
						1) 安装 mysql服务软件
						2)开机挂载逻辑卷lv0 到数据库目录下
						3)启动mysql服务并设置开机启动
						4)  查看初始密码并使用初始密码登录
						5) 修改数据库管理员密码 并断开连接
						6) 使用修改后的密码登录
]# rm -rf /var/lib/mysql/*
]# vim /etc/fstab 
/dev/vg0/lv0    /var/lib/mysql   xfs defaults        0 0
:wq

]# mount -a
]# mount  | grep  "/var/lib/mysql"
]# systemctl start mysqld
]# grep password /var/log/mysqld.log  | tail -1
]# mysqladmin  -uroot -p'Tih:Zehtr57s' password "123qqq...A"
]# mysql -uroot -p123qqq...A


案例3:配置主从同步:(读写分离存储数据时 能让用户存储的数据和查看的是一致)
						1) 配置主数据库服务器 mysql11(192.168.4.11)
							具体操作如下:
												1) 启用binlog日志文件
												2)    用户授权
												3)  查看正在使用的binlog日志名和偏移量 (准备从服务器使用)

mysql11]#  vim /etc/my.cnf
[mysqld]
server_id=11
log_bin=master11
:wq
mysql11]# systemctl  restart  mysqld
mysql11]# mysql  -uroot  -p123qqq...A
mysql> grant   replication  slave  on  *.*  to  repluser@"%" identified by "123qqq...A";
mysql> 
mysql> show master status;
+-----------------+----------+--------------+------------------+-------------------+
| File            | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-----------------+----------+--------------+------------------+-------------------+
| master11.000001 |     1026 |              |                  |                   |
+-----------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)



						2) 配置从数据库服务器 mysql11(192.168.4.22)
							具体操作如下:
												1)指定server_id    (修改配置设置server_id 所以要重启服务)
												2)管理员登录数据库服务,指定主服务器信息,指定的信息
														包括(ip    用户    密码    日志名  偏移量)
												3)启动slave进程
												4)查看IO线程和SQL线程的状态(都是Yes 就配置对了)
												

mysql22]#  vim /etc/my.cnf
[mysqld]
server_id=22
:wq
mysql11]# systemctl  restart  mysqld
mysql11]# mysql  -uroot  -p123qqq...A
mysql> change master to  master_host="192.168.4.11" , master_user="repluser" , master_password="123qqq...A",
master_log_file="master11.000001" ,  master_log_pos=441;

mysql> start slave;

mysql> show slave status \G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes


案例4:配置读写分离服务: (ip 地址 是 192.168.4.77   主机名maxscal77)
           (把客户端连接自己后的查询请求给slave 数据库服务器, 把写请求master数据库服务器)
			具体配置步骤如下:
				1)安装软件   yum -y install maxscale-2.1.2-1.rhel.7.x86_64.rpm
				2)修改配置文件

vim /etc/maxscale.cnf

[maxscale]
threads=auto


[server1]
type=server
address=192.168.4.11
port=3306
protocol=MySQLBackend

[server2]
type=server
address=192.168.4.22
port=3306
protocol=MySQLBackend


[MySQL Monitor]
type=monitor
module=mysqlmon
servers=server1,server2
user=mysqla
passwd=123qqq...A
monitor_interval=10000

#[Read-Only Service]
#type=service
#router=readconnroute
#servers=server1
#user=myuser
#passwd=mypwd
#router_options=slave


[Read-Write Service]
type=service
router=readwritesplit
servers=server1,server2
user=mysqlb
passwd=123qqq...A
max_slave_connections=100%

[MaxAdmin Service]
type=service
router=cli


#[Read-Only Listener]
#type=listener
#service=Read-Only Service
#protocol=MySQLClient
#port=4008


[Read-Write Listener]
type=listener
service=Read-Write Service
protocol=MySQLClient
port=4006

[MaxAdmin Listener]
type=listener
service=MaxAdmin Service
protocol=maxscaled
socket=default
port=4016
:wq

				3)配置数据库服务器 (只需要在主数据库服务器mysql11 用户 从服务器会自动同步用户)
						replication slave,  查看主从角色 
						replication client  查看mysql数据库服务运行状态
[root@mysql11 ~]# mysql -uroot -p123qqq...A
mysql> grant  replication slave , replication client on  *.*  to  mysqla@"%"  identified by "123qqq...A";   监控用户
mysql> grant  select  on  *.*  to  mysqlb@"%"  identified by "123qqq...A";  路由用户



				        在从数据库服务器查看是否同步授权用户名

[root@mysql22 ~]# mysql -uroot -p123qqq...A				        
mysql> select  user from mysql.user where  user="mysqla";
mysql> select  user from mysql.user where  user="mysqlb";
				
				4)  启动maxscale服务 (在maxscale77 主机启动服务) 
						[root@maxscale77 ~]# maxscale   /etc/maxscale.cnf
				5) 查看maxscale服务状态
[root@maxscale77 ~]# netstat -utnlp  | grep 4016
tcp6       0      0 :::4016                 :::*                    LISTEN      1125/maxscale       
[root@maxscale77 ~]# netstat -utnlp  | grep 4006
tcp6       0      0 :::4006                 :::*                    LISTEN      1125/maxscale       
[root@maxscale77 ~]# 
						
				6)查看监控信息(在maxscale77 访问自己的管理服务,查看监控信息)
[root@maxscale77 ~]# maxadmin  -uadmin  -pmariadb -P4016
MaxScale> list servers
Servers.
-------------------+-----------------+-------+-------------+--------------------
Server             | Address         | Port  | Connections | Status              
-------------------+-----------------+-------+-------------+--------------------
server1            | 192.168.4.11    |  3306 |           0 | Master, Running
server2            | 192.168.4.22    |  3306 |           0 | Slave, Running
-------------------+-----------------+-------+-------------+--------------------
MaxScale> exit
[root@maxscale77 ~]#



案例5:准备NFS服务存储磁盘 (IP 192.168.4.30主机提供nfs服务 ,存储网站web33的网页文件)
		步骤一 : 
			1)添加1块3G 磁盘
			2)  磁盘分区 (分一个区  /dev/vdb1)
			3)  格式化
[root@NFS30 ~]# lsblk  分区前查看
[root@NFS30 ~]# fdisk /dev/vdb -> n -> p -> 三个回车-> w 
[root@NFS30 ~]# lsblk  分区后查看
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda    253:0    0  30G  0 disk 
└─vda1 253:1    0  30G  0 part /
vdb    253:16   0   3G  0 disk 
└─vdb1 253:17   0   3G  0 part
[root@NFS30 ~]# mkfs.xfs  /dev/vdb1 

			
		步骤二:挂载磁盘
[root@NFS30 ~]# mkdir /sitedir
[root@NFS30 ~]# vim /etc/fstab 
/dev/vdb1       /sitedir        xfs     defaults        0 0
:wq

[root@NFS30 ~]# mount -a

[root@NFS30 ~]# mount | grep  -i  "/sitedir"
/dev/vdb1 on /sitedir type xfs (rw,relatime,attr2,inode64,noquota)
[root@NFS30 ~]#
						
案例6:配置NFS服务 (192.168.4.30 把目录共享给客户端 )
			 1)安装软件
			 2)修改配置文件
			3) 启动服务 (先启动rpcbind服务 再启动nfs服务)
			4)查看共享信息
[root@NFS30 ~]#  yum -y install nfs-utils rpcbind
[root@NFS30 ~]# vim /etc/exports
/sitedir  *(rw)
:wq
[root@NFS30 ~]# chmod o+w /sitedir/

[root@NFS30 ~]# systemctl  restart rpcbind
[root@NFS30 ~]# systemctl  enable rpcbind
[root@NFS30 ~]# systemctl  restart nfs
[root@NFS30 ~]# systemctl  enable nfs
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
[root@NFS30 ~]# showmount  -e localhost
Export list for localhost:
/sitedir *
[root@NFS30 ~]# 



案例7:配置网站服务192.168.4.33 主机名web33
				1)安装软件apache-tomcat-8.0.30.tar.gz  (使用tomcatr软件提高的网站服务)
				2)挂载nfs服务的共享目录(把网站的网页存放的nfs30主机里)
				3)查看挂载
				4) 启动tomcat服务
				5) 查看tomcat服务运行信息

yum -y install java-1.8.0-openjdk
tar -xf apache-tomcat-8.0.30.tar.gz 
mv apache-tomcat-8.0.30 /usr/local/tomcat
rm -rf  /usr/local/tomcat/webapps/ROOT/*
which showmount ||  yum -y install nfs-utils

[root@web33 ~]# showmount  -e 192.168.4.30
Export list for 192.168.4.30:
/sitedir *
[root@web33 ~]#

[root@web33 ~]# vim  /etc/fstab 
192.168.4.30:/sitedir   /usr/local/tomcat/webapps/ROOT nfs defaults        0 0
:wq

[root@web33 ~]# mount -a
[root@web33 ~]# df -h
文件系统               容量  已用  可用 已用% 挂载点
/dev/vda1               30G  1.4G   29G    5% /
devtmpfs               697M     0  697M    0% /dev
tmpfs                  707M     0  707M    0% /dev/shm
tmpfs                  707M  8.5M  699M    2% /run
tmpfs                  707M     0  707M    0% /sys/fs/cgroup
tmpfs                  142M     0  142M    0% /run/user/0
192.168.4.30:/sitedir  3.0G   32M  3.0G    2% /usr/local/tomcat/webapps/ROOT    已经挂载
[root@web33 ~]# 

[root@web33 ~]# /usr/local/tomcat/bin/startup.sh  ^C
[root@web33 ~]# 
[root@web33 ~]# netstat  -utnlp  | grep :8080
tcp6       0      0 :::8080                 :::*                    LISTEN      1371/java           
[root@web33 ~]# 


案例8:测试配置
			一 、测试NFS服务
						1)在nfs服务器创建网页 test.html
						[root@NFS30 ~]# vim /sitedir/test.html
						web test page
						:wq
						
						2)在客户端访问网站服务(在任意一台主机上访问web33 网页)
					]# curl  http://192.168.4.33:8080/test.html
					             web test page
					


二、测试MySQL服务
2.1、 在主数据库服务器mysql11 做如下配置

         [root@mysql11 ~]# mysql -uroot -p123qqq...A
         create database gamedb;
         create  table  gamedb.user ( name  char(10) , password char(6));
         grant  select, insert  on  gamedb.*  to  yaya@"%" identified by "123qqq...A";

        
2.2、在从服务器 检查是否同步库表 和  授权用户 
[root@mysql22 ~]# mysql -uroot -p123qqq...A -e 'desc gamedb.user'

[root@mysql22 ~]# mysql -uroot -p123qqq...A -e 'select user from mysql.user where  user="yaya"'

2.3 在网站服务器命令行 连接 maxscale77
web33]# yum  -y  install mariadb 
web33]# mysql  -h192.168.4.77 -P4006  -uyaya  -p123qqq...A
mysql>exit ;

三、测试Tomcat连接MySQL服务(在网页目录下编写网站脚本文件 访问数据库服务)
1)在网站服务器做如下配置
[root@web33 ~]# yum -y install mysql-connector-java
[root@web33 ~]# cp /usr/share/java/mysql-connector-java.jar /usr/local/tomcat/lib/
[root@web33 ~]# /usr/local/tomcat/bin/shutdown.sh
[root@web33 ~]# /usr/local/tomcat/bin/startup.sh

1)编写网站脚本(在nfs服务共享目录编写网页文件)
[root@nfs30 ~]# vim /sitedir/linkdb.jsp
<%@ page language="java" import="java.util.*" pageEncoding="gbk"%>
<%@ page import="java.naming.*" %>
<%@ page import="java.sql.*" %>
          <%
Class.forName("com.mysql.jdbc.Driver");
Connection con=DriverManager.getConnection("jdbc:mysql://192.168.4.77:4006","yaya","123qqq...A");
Statement state=con.createStatement();
String sql="insert into gamedb.user values('bbb','654321')";
state.executeUpdate(sql);
           %>
data save ok

2)在浏览器地址栏里输入网站访问 或 命令行连接访问 都可以 
[root@NFS30 ~]# curl  http://192.168.4.33:8080/linkdb.jsp
       
data save ok

3)在据库服务器查看数据 (可以查看到linkdb.jsp 脚本里 Insert into 命令添加的记录 )
[root@mysql11 ~]# mysql -uroot -p123qqq...A -e 'select  * from gamedb.user'
[root@mysql22 ~]# mysql -uroot -p123qqq...A -e 'select  * from gamedb.user'

day02

  1. 改变网站运行平台LNP(nginx) + MySQL

  2. 把存储在读写分离存储结构里的数据辅助到mysql高可用集群里面(在线复制)

  3. 部署内存存储服务器,让网站把经常被访问的数据存储在内存里,可以加快网站服务的处理速度

案例1:升级网站运行平台
			步骤一  清除当前配置  (删除web33主机的tomcat服务的配置) 
							1)停止网站服务
							2)卸载共享存储
 [root@web33 ~]# /usr/local/tomcat/bin/shutdown.sh
 [root@web33 ~]# umount /usr/local/tomcat/webapps/ROOT  //卸载当前挂载
 [root@web33 ~]# vim /etc/fstab   //清除开机挂载
 #192.168.4.30:/sitedir    /usr/local/tomcat/webapps/ROOT  nfs  defaults   0   0 
 :wq
   
							
			步骤二:部署LNP
						  	1)安装软件
							2)挂载共享存储(把NFS30的共享目录/sitedir   挂载到nginx的网页目录下)
							3)启动服务
										要先修改配置文件把访问php页面的请求给本机的9000端口处理
										再启动nginx 服务
[root@web33 ~]# yum -y install gcc  zlib-devel  pcre-devel  php   php-devel  php-mysql php-fpm
[root@web33 ~]# tar -xf nginx-1.12.2.tar.gz //解压
[root@web33 ~]# cd nginx-1.12.2  //进源码目录
[root@web33 nginx-1.12.2]# ./configure  //配置
[root@web33 nginx-1.12.2]# make  && make install 
[root@web33 ~]# vim /etc/fstab   //开机挂载
192.168.4.30:/sitedir    /usr/local/nginx/html  nfs  defaults   0   0 
:wq
[root@web33 ~]# mount   -a  //挂载设备
 [root@web33 ~]# vim +65 /usr/local/nginx/conf/nginx.conf  //修改主配置文件
location ~ \.php$ {
            root           html;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            include        fastcgi.conf;
        }
:wq
[root@web33 ~]# /usr/local/nginx/sbin/nginx //启动服务
[root@web33 ~]# systemctl  start  php-fpm


		步骤三:测试配置
							1)编写PHP脚本 (在NFS30的共享目录编写连接MySQL服务的php脚本)
[root@NFS30 ~]# vim /sitedir/linkdb2.php					
<?php
$conn=mysql_connect("192.168.4.11","yaya","123qqq...A");
mysql_select_db("gamedb");
$sql = 'insert into user (name,password) values ("PANGLJ","666888")';
mysql_query($sql);
mysql_close();
echo "save data ok";
?>
:wq
				
							
							2)访问脚本  (在任意1台主机访问web33主机的网站服务 执行linkdb2.php脚本)
							      [root@NFS30 ~]# curl  http://192.168.4.33/linkdb2.php
                                  save data ok
							3)查看数据 (在数据库服务器mysql11 和 mysql22 本机查看数据,
							     能看到php脚本存储的数据就成功里)
[root@mysql22 ~]# mysql -uroot -p123qqq...A -e 'select  * from gamedb.user';							
[root@mysql11~]# mysql -uroot -p123qqq...A -e 'select  * from gamedb.user';


						休息到   16:05 
案例2:部署内存存储服务(部署Redis集群 ,使用内存存储网站的数据)
	步骤一:部署redis服务器(6台都要配置)
					 具体操作步骤: 安装redis软件  、 初始化配置 、停止redis服务、启用集群功能、  启动redis 服务


配置Host51 52 53 54 55 56主机
[root@redisA ~]# rpm -q gcc  ||  yum -y  install gcc  //安装编译工具
[root@redisA ~]# tar -xf redis-4.0.8.tar.gz //解压
[root@redisA ~]# cd redis-4.0.8/   //进源码目录
[root@redisA ~]# make
[root@redisA redis-4.0.8]# make install  //安装软件
[root@redisA redis-4.0.8]# ./utils/install_server.sh //初始化配置 遇到提示敲回车
[root@redisA redis-4.0.8]# /etc/init.d/redis_6379  stop  //停止服务
[root@redisA redis-4.0.8]# vim /etc/redis/6379.conf //修改配置文件,启用集群配置
70 bind 192.168.4.51
93 port 6379
815 cluster-enabled yes
823 cluster-config-file nodes-6379.conf
829 cluster-node-timeout 5000
[root@redisA redis-4.0.8]# /etc/init.d/redis_6379  start  //启动服务
[root@redisA redis-4.0.8]# netstat  -utnlp  | grep  redis-server  //查看端口
tcp        0      0 192.168.4.51:6379       0.0.0.0:*               LISTEN      29720/redis-server   //redis服务端口
tcp        0      0 192.168.4.51:16379      0.0.0.0:*               LISTEN      29720/redis-server  //集群端口
	  
  
   步骤二:创建redis集群
					1)配置管理主机:  安装gem软件    创建ruby脚本
[root@mgm ~]# yum -y  install ruby rubygems  //安装依赖
[root@mgm ~]# gem install redis-3.2.1.gem  //安装依赖软件gem程序
[root@mgm ~]# mkdir /root/bin
[root@mgm ~]# tar -xf redis-4.0.8.tar.gz
[root@mgm ~]# cp  redis-4.0.8/src/redis-trib.rb   /root/bin/  //拷贝脚本
[root@mgm ~]# 
[root@mgm ~]# chmod  +x /root/bin/redis-trib.rb  //确保脚本有执行权限

					
					2)创建集群
					mgm~]#redis-trib.rb  create  --replicas  1   \
192.168.4.51:6379    192.168.4.52:6379    192.168.4.53:6379  \  
192.168.4.54:6379   192.168.4.55:6379    192.168.4.56:6379
......
Can I set the above configuration? (type 'yes' to accept): yes  同意
....
....
>>> Check slots coverage...
[OK] All 16384 slots covered.  集群创建成功的提示信息


					3)查看集群信息
[root@mgm ~]# redis-trib.rb info 192.168.4.51:6379
192.168.4.51:6379 (8221af1a...) -> 0 keys | 5461 slots | 1 slaves.
192.168.4.52:6379 (fc08343f...) -> 0 keys | 5462 slots | 1 slaves.
192.168.4.53:6379 (94213188...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.


步骤三:配置网站服务器 (web33)
             (让网站的php脚本可以连接redis 集群中任意服务器查询和存储数据)
				
				1) 安装连接redis集群的redis.so模块
				2)修改php的配置文件 php.ini 加载模块
				3) 查看支持的模块  
[root@web33 ~ ]# yum -y install php-devel  //安装依赖
[root@web33 ~]# tar -xf redis-cluster-4.3.0.tgz  //解压
[root@web33 ~]# cd redis-4.3.0/  //进入源码目录
[root@web33 redis-4.3.0]# phpize  //创建configure命令及配置信息文件/usr/bin/php-config
Configuring for:
PHP Api Version:         20100412
Zend Module Api No:      20100525
Zend Extension Api No:   220100525
[root@web33 redis-4.3.0]#
[root@web33 redis-4.3.0]# ./configure --with-php-config=/usr/bin/php-config
[root@web33 redis-4.3.0]# make  //编译
[root@web33 redis-4.3.0]# make install  //安装
Installing shared extensions:     /usr/lib64/php/modules/   //提示模块安装目录
[root@web33 redis-4.3.0]# vim /etc/php.ini
728 extension_dir = "/usr/lib64/php/modules/"   //模块目录
730 extension = "redis.so"   //模块名
:wq
[root@web33 redis-4.3.0]# systemctl  restart php-fpm  //重启php-fpm服务
[root@web33 redis-4.3.0]# php -m | grep redis
redis
[root@web33 redis-4.3.0]#
			 	 
步骤四:测试配置
			休息到 17:05
			1)在存储服务器共享目录下,创建连接集群PHP脚本
				  (在脚本连接集群后执行存储数据名和查询数据的命令)
[root@NFS30 ~]# vim    /sitedir/set_data.php   存储数据的PHP脚本
<?php
$redis_list = ['192.168.4.51:6379','192.168.4.52:6379','192.168.4.53:6379','192.168.4.54:6379','192.168.4.55:6379','192.168.4.56:6379'];  //定义redis服务器列表
$client = new RedisCluster(NUll,$redis_list); //定义连接redis服务命令
$client->set("i","tarenaA "); //存储数据 变量名 i
$client->set("j","tarenaB ");  //存储数据 变量名 j
$client->set("k","tarenaC ");  //存储数据 变量名 k 
echo "save ok";
?>
:wq

[root@NFS30 ~]# 
[root@NFS30 ~]# 
[root@NFS30 ~]# vim   /sitedir/get_data.php 查看数据的PHP脚本
<?php
$redis_list = ['192.168.4.51:6379','192.168.4.52:6379','192.168.4.53:6379','192.168.4.54:6379','192.168.4.55:6379','192.168.4.56:6379']; //定义redis服务器列表
$client = new RedisCluster(NUll,$redis_list); //定义连接redis服务命令
echo $client->get("i");  //获取变量i 的数据
echo $client->get("j");  //获取变量j 的数据
echo $client->get("k");  //获取变量k 的数据
echo "get ok";
?>
:wq

[root@NFS30 ~]# 
[root@NFS30 ~]# vim   /sitedir/test3.php  存储+查询的PHP脚本
<?php
$redis_list = ['192.168.4.51:6379','192.168.4.52:6379','192.168.4.53:6379','192.168.4.54:6379','192.168.4.55:6379','192.168.4.56:6379'];
$client = new RedisCluster(NUll,$redis_list);
$client->set("name","panglijing");  //存数据
echo $client->get("name");  //取数据
?>
:wq
[root@NFS30 ~]# 
	

	


            2)访问网站执行脚本(在任意主机访问网站服务器都可以)
[root@NFS30 ~]# curl http://192.168.4.33/set_data.php
save ok[root@NFS30 ~]# 
[root@NFS30 ~]# 
[root@NFS30 ~]# 
[root@NFS30 ~]# curl http://192.168.4.33/get_data.php
tarenaA tarenaB tarenaC get ok
[root@NFS30 ~]# 
[root@NFS30 ~]# curl http://192.168.4.33/test3.php
panglijing[root@NFS30 ~]#

		3)命令行连接任意一台redis服务器查看数据(在任意主机连接redis服务器都可以)
[root@host52 ~]# redis-cli -c -h 192.168.4.51 -p 6379
192.168.4.51:6379> keys *
1) "j"
192.168.4.51:6379> exit

[root@host52 ~]# redis-cli -c -h 192.168.4.52 -p 6379
192.168.4.52:6379> keys *
1) "k"
2) "name"
192.168.4.52:6379> exit
[root@host52 ~]# redis-cli -c -h 192.168.4.53 -p 6379
192.168.4.53:6379> keys *
1) "i"
192.168.4.53:6379>

案例3:数据迁移 (把存储在读写分离结构里的数据 复制到  PXC集群结构里)
			在线迁移数据(在网站业务不停止的情况下复制数据到新的存储结构pxc集群里)
			
步骤一:配置从服务器(把主机192.168.4.66 配置为192.168.4.11的从服务器)			
				1)在192.168.4.66主机安装数据库服务软件并启动mysqld服务(mysql-5.7.17)
			         启动mysql服务 ,  查看初始密码   登陆后 修改密码  退出 使用新密码登陆

[root@pxcnode66 ~]# tar -xf mysql-5.7.17.tar  //解包
[root@pxcnode66 ~]# yum -y  install mysql-community-*.rpm  //安装软件
[root@pxcnode66 ~]# systemctl start  mysqld  //启动服务
[root@pxcnode66 ~]# grep password  /var/log/mysqld.log //查看初始密码
2019-07-05T01:56:51.895852Z 1 [Note] A temporary password is generated for root@localhost: bB0*uCmu:.Kj
[root@pxcnode66 ~]# mysql -uroot -p'bB0*uCmu:.Kj'  //初始密码登录
mysql> 
mysql> alter user root@"localhost" identified by "123qqq...A";//修改登录密码
Query OK, 0 rows affected (0.01 sec)
mysql>
mysql> exit //断开连接
Bye
[root@pxcnode66 ~]# mysql -uroot -p123qqq...A  //新密码登录

				
				2)修改服务主配置文件
[root@pxcnode66 ~]# vim /etc/my.cnf
[mysqld]
server_id=66  //指定server_id
:wq
[root@pxcnode66 ~]# systemctl  restart mysqld  //重启服务


                3)确保数据一致 (pxcnode66主机 使用mysql11主机的完全备份恢复数据确保数据一致 )
								3.1 先在 mysql11主机安装在线热备工具innobackupex 命令
								       把备份文件拷贝给 从服务pxc66主机
[root@mysql11 ~]# yum -y install  libev-4.15-1.el6.rf.x86_64.rpm //安装依赖软件
[root@mysql11 ~]# yum -y  install percona-xtrabackup-24-2.4.7-1.el7.x86_64.rpm //安装在线热备软件
[root@mysql11 ~]# innobackupex  -uroot -p123qqq...A  /allbak --no-timestamp //备份所有数据,并记录备份数据对应的binlog日志名
[root@mysql11 ~]# scp -r /allbak  [email protected]:/root/   //把备份文件发送给pxcnode66主机

									   
								 3.2 从服务pxc66主机 是完全备份文件恢复数据,(也要安装
									   热备工具innobackupex 命令)
[root@pxcnode66 ~]# yum -y install  libev-4.15-1.el6.rf.x86_64.rpm  //安装依赖软件
[root@pxcnode66 ~]# yum -y install  percona-xtrabackup-24-2.4.7-1.el7.x86_64.rpm //安装在线热备软件
[root@pxcnode66 ~]# systemctl  stop  mysqld //停止服务
[root@pxcnode66 ~]# rm  -rf  /var/lib/mysql/*  //清空数据库目录
[root@pxcnode66 ~]# innobackupex --apply-log /root/allbak/  //准备恢复数据
[root@pxcnode66 ~]# innobackupex --copy-back /root/allbak/  //恢复数据
[root@pxcnode66 ~]# chown -R mysql:mysql /var/lib/mysql //修改所有者
[root@pxcnode66 ~]# systemctl start  mysqld  //启动服务

									   
				4)指定主服务器 (把pxc66 配置为 mysql11 的从服务器)
					  在备份文件里查看 完全备份后 对应的日志名和偏移量
					  [root@pxc66 ~]# grep master11 /root/allbak/xtrabackup_info 
binlog_pos = filename 'master11.000001', position '5543'
[root@pxc66 ~]#

[root@pxcnode66 ~]# mysql -uroot -p123qqq...A    //管理员登录指定主服务器信息
mysql> change master to  
master_host="192.168.4.11", //主服务器ip地址
master_user="repluser", //主服务器授权用户
master_password="123qqq...A", //授权密码
master_log_file="master11.000001",    //binlog日志名
master_log_pos=2224; //日志偏移量
Query OK, 0 rows affected, 2 warnings (0.31 sec)
mysql> start slave ; 
				
mysql> exit  //断开连接
Bye
[root@pxcnode66 ~]#
[root@pxcnode66 ~]# mysql -uroot -p123qqq...A -e "show slave status\G" | grep -i 192.168.4.11  //查看主服务器地址
mysql: [Warning] Using a password on the command line interface can be insecure.
                  Master_Host: 192.168.4.11 //主服务器ip地址
[root@pxcnode66 ~]# mysql -uroot -p123qqq...A -e "show slave status\G" | grep -i "yes" //查看状态信息
mysql: [Warning] Using a password on the command line interface can be insecure.
             Slave_IO_Running: Yes  //IO线程正常
            Slave_SQL_Running: Yes  //SQL线程正常
[root@pxcnode66 ~]#	


步骤二:配置第1台PXC服务器(192.168.4.66)

			1)停止mysqld服务、卸载mysqld服务软件				
[root@pxc66 ~]# systemctl  stop  mysqld				
[root@pxc66 ~]# rpm -e --nodeps mysql-community-common mysql-community-devel   \
mysql-community-test mysql-community-minimal-debuginfo  \
mysql-community-libs mysql-community-server mysql-community-embedded \
 mysql-community-embedded-devel mysql-community-embedded-compat  \
 mysql-community-client mysql-community-libs-compat
				
			2)安装PXC软件、修改配置文件、启动mysql服务
[root@pxcnode66 ~]# cd PXC  //进软件目录
[root@pxcnode66 PXC]# yum -y install libev-4.15-1.el6.rf.x86_64.rpm
[root@pxcnode66 PXC]# yum -y install percona-xtrabackup-24-2.4.13-1.el7.x86_64.rpm qpress-1.1-14.11.x86_64.rpm
[root@pxcnode66 PXC]# yum -y install qpress-1.1-14.11.x86_64.rpm  //安装依赖
[root@pxcnode66 PXC]# tar -xf Percona-XtraDB-Cluster-5.7.25-31.35-r463-el7-x86_64-bundle.tar  //解压PXC软件包
[root@pxcnode66 PXC]# yum -y  install Percona-XtraDB-Cluster-*.rpm //安装软件
[root@pxcnode66 PXC]# vim /etc/percona-xtradb-cluster.conf.d/mysqld.cnf //修改数据库服务配置文件
[mysqld]
server-id=66 //指定server_id
:wq

[root@pxcnode66 PXC]# vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf //修改集群服务配置文件
8: wsrep_cluster_address=gcomm://	   不需要写ip地址
25: wsrep_node_address=192.168.4.66   //指定本机Ip地址
27: wsrep_cluster_name=pxc-cluster  //指定集群名称(另外2台的集群名称要于此相同)
30: wsrep_node_name=pxcnode66  //指定本机主机名
39: wsrep_sst_auth="sstuser:123qqq…A" //数据全量同步授权用户及密码
:wq
[root@pxcnode66 PXC]#
[root@pxcnode66 PXC]# systemctl  start mysql  //启动服务
[root@pxcnode66 PXC]# mysql -uroot -p123qqq...A //管理员登录
mysql> grant all on *.* to sstuser@"localhost" identified by "123qqq...A"; //用户授权
mysql> exit;

			
步骤三:配置第2台PXC服务器(192.168.4.10)			
			1)安装PXC软件
			2)  修改配置文件
			3)  启动mysql服务
[root@pxcnode10 ~]# cd PXC  //进软件目录
[root@pxcnode10 PXC]# yum -y install libev-4.15-1.el6.rf.x86_64.rpm
[root@pxcnode10 PXC]# yum -y install percona-xtrabackup-24-2.4.13-1.el7.x86_64.rpm qpress-1.1-14.11.x86_64.rpm
[root@pxcnode10 PXC]# yum -y install qpress-1.1-14.11.x86_64.rpm  //安装依赖
[root@pxcnode10 PXC]# tar -xf Percona-XtraDB-Cluster-5.7.25-31.35-r463-el7-x86_64-bundle.tar  //解压PXC软件包
[root@pxcnode10 PXC]# yum -y  install Percona-XtraDB-Cluster-*.rpm //安装软件
[root@pxcnode10 PXC]# vim /etc/percona-xtradb-cluster.conf.d/mysqld.cnf //修改数据库服务配置文件
[mysqld]
server-id=10 //指定server_id
:wq

[root@pxcnode10 PXC]# vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf //修改集群服务配置文件
8: wsrep_cluster_address=gcomm://192.168.4.66	   
25: wsrep_node_address=192.168.4.10   //指定本机Ip地址
27: wsrep_cluster_name=pxc-cluster  //指定集群名称(另外2台的集群名称要于此相同)
30: wsrep_node_name=pxcnode10  //指定本机主机名
39: wsrep_sst_auth="sstuser:123qqq…A" //数据全量同步授权用户及密码
:wq
[root@pxcnode10 PXC]# systemctl  start mysql  //启动服务
[root@pxcnode10 PXC]# mysql -uroot -p123qqq...A //管理员登录



步骤三:配置第3台PXC服务器(192.168.4.88)			
			1)安装PXC软件
			2)  修改配置文件
			3)  启动mysql服务
[root@pxcnode88 ~]# cd PXC  //进软件目录
[root@pxcnode88 PXC]# yum -y install libev-4.15-1.el6.rf.x86_64.rpm
[root@pxcnode88 PXC]# yum -y install percona-xtrabackup-24-2.4.13-1.el7.x86_64.rpm qpress-1.1-14.11.x86_64.rpm
[root@pxcnode88 PXC]# yum -y install qpress-1.1-14.11.x86_64.rpm  //安装依赖
[root@pxcnode88 PXC]# tar -xf Percona-XtraDB-Cluster-5.7.25-31.35-r463-el7-x86_64-bundle.tar  //解压PXC软件包
[root@pxcnode88 PXC]# yum -y  install Percona-XtraDB-Cluster-*.rpm //安装软件
[root@pxcnode88 PXC]# vim /etc/percona-xtradb-cluster.conf.d/mysqld.cnf //修改数据库服务配置文件
[mysqld]
server-id=88 //指定server_id
:wq

[root@pxcnode88 PXC]# vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf //修改集群服务配置文件
8: wsrep_cluster_address=gcomm://192.168.4.66	   
25: wsrep_node_address=192.168.4.88   //指定本机Ip地址
27: wsrep_cluster_name=pxc-cluster  //指定集群名称(另外2台的集群名称要于此相同)
30: wsrep_node_name=pxcnode88  //指定本机主机名
39: wsrep_sst_auth="sstuser:123qqq…A" //数据全量同步授权用户及密码
:wq
[root@pxcnode88 PXC]# systemctl  start mysql  //启动服务
[root@pxcnode88 PXC]# mysql -uroot -p123qqq...A //管理员登录

    	
步骤五:公共配置(192.168.4.88、192.168.4.10、192.168.4.66)
pxcnode66~]# vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf  
wsrep_cluster_address=gcomm://192.168.4.66,192.168.4.10,192.168.4.88 //指定集群成员列表
:wq

pxcnode10~]# vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf  
wsrep_cluster_address=gcomm://192.168.4.66,192.168.4.10,192.168.4.88 //指定集群成员列表
:wq

pxcnode88~]# vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf  
wsrep_cluster_address=gcomm://192.168.4.66,192.168.4.10,192.168.4.88 //指定集群成员列表
:wq

测试配置
[root@mysql11 ~]# mysql -uroot -p123qqq...A
#访问pxc集群存储数据需要表中有主键字段
mysql> alter table gamedb.user add  id int primary key auto_increment first; 
mysql> exit;

[root@web33 ~]# mysql  -h192.168.4.66  -uyaya  -p123qqq...A  gamedb
Mysql> insert  into  gamedb.user(name) values ("pljA");
Mysql> exit ;
[root@web33 ~]# mysql  -h192.168.4.10  -uyaya  -p123qqq...A  gamedb
Mysql> insert  into  gamedb.user(name) values ("pljB");
Mysql> exit ;
[root@web33 ~]# mysql  -h192.168.4.88  -uyaya  -p123qqq...A  gamedb
Mysql> insert  into  gamedb.user(name) values ("pljC");
Mysql> exit ;

#网站服务33 连接集群中的任意一台服务器都可以查看到 插入的 所有数据
[root@web33 ~]# mysql -h192.168.4.66 -uyaya -p123qqq...A  -e 'select  * from gamedb.user'
[root@web33 ~]# mysql -h192.168.4.10 -uyaya -p123qqq...A  -e 'select  * from gamedb.user'
[root@web33 ~]# mysql -h192.168.4.88 -uyaya -p123qqq...A  -e 'select  * from gamedb.user'

案例4:部署LB集群
	步骤一:安装软件: 在haproxy99主机上安装haproxy软件
    步骤二:修改配置文件
	步骤三:启动服务
    步骤四:测试配置:在网站服务器连接haproxy99主机访问数据

[root@haproxy99 ~]# yum -y install haproxy
[root@haproxy99 ~]# vim  /etc/haproxy/haproxy.cfg
#文件末尾添加如下行
listen mysql_3306 *:3306 //定义haproxy服务名称与端口号
    mode    tcp        //mysql服务 得使用 tcp 协议
    option  tcpka      //使用长连接
    balance roundrobin //调度算法
    server  mysql_01 192.168.4.66:3306 check  //第1台数据库服务器
    server  mysql_02 192.168.4.10:3306 check  //第2台数据库服务器
    server  mysql_03 192.168.4.88:3306 check  //第3台数据库服务器
:wq
[root@haproxy99 haproxy]#
[root@haproxy99 ~]# systemctl  start haproxy //启动服务
[root@haproxy99 ~]# netstat -utnlp  | grep  :3306  //查看端口
tcp6       0      0 :::3306                 :::*                    LISTEN      29768/haproxy     

测试配置
[root@web33 ~]# mysql -h192.168.4.99 -uyaya -p123qqq...A -e  ‘select @@hostname’
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| pxcnode66  |   //第1次连接
+------------+
[root@web33 ~]#

[root@web33 ~]# mysql -h192.168.4.99 -uyaya -p123qqq…A -e  ‘select @@hostname’
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| pxcnode10  |   //第2次连接
+------------+
[root@web33 ~]#

[root@web33 ~]# mysql -h192.168.4.99 -uyaya -p123qqq…A -e  ‘select @@hostname’
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| pxcnode88  |   //第3次连接
+------------+
[root@web33 ~]#



案例5:部署HA集群
	步骤一:准备备用调度器主机192.168.4.98
    环境准备: 创建新的虚拟机 并配置ip地址 192.168.4.98
    1) 安装haproxy 软件 
[root@haproxy98 ~]#yum -y install haproxy
    2)修改haproxy98主机haproxy.conf文件
    说明要和99主机的配置一样,所以直接拷贝haproxy99主机的配置文件也可以
[root@haproxy98 ~]#scp /etc/haproxy/haproxy.cfg 192.168.4.98:/etc/haproxy/
    3)启动haproxy服务
[root@haproxy98 ~]# systemctl  start haproxy
[root@haproxy98 ~]# netstat  -utnalp  | grep 3306
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      918/haproxy         
[root@haproxy98 ~]# 

  步骤二:安装软件keepalived软件
	1)在haproxy99主机安装keepalived软件
[root@haproxy99 ~]# yum -y install keepalived.x86_64

    2)在haproxy98主机安装keepalived软件
[root@haproxy98 ~]# yum -y install keepalived.x86_64    

步骤三:修改配置文件

     1)修改haproxy99主机的配置文件,说明99主机做主调度器 优先级要比98高
     #删除文件中不相关的配置
[root@haproxy99 ~]# sed -i  '36,$d' /etc/keepalived/keepalived.conf
[root@haproxy99 ~]# vim /etc/keepalived/keepalived.conf
.....
......
vrrp_iptables
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 150
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.4.100
    }
}
:wq

	 2)修改haproxy98主机的配置文件,说明98主机做备用调度器 优先级要比99低	
[root@haproxy98 ~]# scp [email protected]:/etc/keepalived/keepalived.conf /etc/keepalived/
[root@haproxy98 ~]# vim /etc/keepalived/keepalived.conf	
....
state BACKUP
....
priority 100
:wq

步骤四:启动服务

     1)在haproxy99主机启动keepalived服务	
[root@haproxy99 ~]# systemctl  start keepalived     

     2)在haproxy98主机启动keepalived服务
[root@haproxy98 ~]# systemctl  start keepalived

步骤五:测试配置

    1)客户端连接vip地址,访问数据库服务
[root@web33 ~]# mysql -h192.168.4.100 -uyaya -p123qqq...A -e 'select @@hostname'
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| pxc10      |
+------------+
[root@web33 ~]# mysql -h192.168.4.100 -uyaya -p123qqq...A -e 'select @@hostname'
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| pxc88      |
+------------+
[root@web33 ~]# mysql -h192.168.4.100 -uyaya -p123qqq...A -e 'select @@hostname'
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |

	2)测试高可用	
        #把99主机的keepalived 服务停止模拟 服务宕机里 
[root@haproxy99 ~]# systemctl  stop  keepalived   

        #在98 主机可以查看到vip地址  192.168.4.100
[root@haproxy98 ~]# ip addr show | grep  192
    inet 192.168.4.98/24 brd 192.168.4.255 scope global noprefixroute eth0
    inet 192.168.4.100/32 scope global eth0
[root@haproxy98 ~]# 

       #客户端一直连接vip地址访问数据库服务
[root@web33 ~]# mysql -h192.168.4.100 -uyaya -p123qqq...A -e 'select @@hostname'
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| pxc66      |
+------------+
[root@web33 ~]# mysql -h192.168.4.100 -uyaya -p123qqq...A -e 'select @@hostname'
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |
+------------+
| pxc10      |
+------------+
[root@web33 ~]# mysql -h192.168.4.100 -uyaya -p123qqq...A -e 'select @@hostname'
mysql: [Warning] Using a password on the command line interface can be insecure.
+------------+
| @@hostname |


ip地址 角色 主机名 安装软件 启动服务 备注
day01 192.168.4.33(clone-vm7) 网站服务器 web33 tomcat
192.168.4.11(clone-mysql) MySQL数据库服务器 mysql11 mysql-5.7.17 添加2块3G磁盘
192.168.4.22(clone-mysql) MySQL数据库服务器 mysql22 mysql-5.7.17 添加2块3G磁盘
192.168.4.77(clone-vm7) 数据读写分离服务器 maxscale77 maxscale
192.168.4.30(clone-vm7) NFS服务器 nfs30 nfs-utlis rpcbind 添加1块3G磁盘(如果硬件配置低,可以在77主机配置)
day02 192.168.4.51 redis服务器 redisA redis 启用集群功能 不需要设置连接密码 使用6379端口
192.168.4.52 redis服务器 redisB redis 启用集群功能 不需要设置连接密码 使用6379端口
192.168.4.53 redis服务器 redisC redis 启用集群功能 不需要设置连接密码 使用6379端口
192.168.4.54 redis服务器 redisD redis 启用集群功能 不需要设置连接密码 使用6379端口
192.168.4.55 redis服务器 redisE redis 启用集群功能 不需要设置连接密码 使用6379端口
192.168.4.56 redis服务器 redisF redis 启用集群功能 不需要设置连接密码 使用6379端口
192.168.4.57 redis集群管理主机 MGM57 创建redis-trib.rb脚本(也可用77主机做管理主机)
192.168.4.66 pxc集群主机 host66 mysql-5.7.17
192.168.4.10 pxc集群主机 pxc10 PXC集群软件
192.168.4.88 pxc集群主机 pxc88 PXC集群软件
192.168.4.99 LB集群调度器 haproxy99 haproxy软件 如果硬件配置低,可以在77主机配置
192.168.4.98 LB集群备用调度器 haproxy98 haproxy软件 如果硬件配置低,可以在30主机配置

你可能感兴趣的:(数据库,数据库)