精华内容
下载资源
问答
  • 学习MySQL这一篇就够了

    万次阅读 多人点赞 2020-07-28 17:21:34
    DBS:数据库管理系统,又称为数据库软件或者数据库产品,用于创建和管理DB,常见的有MySQL、Oracle、DB2、SQL Server SQL:结构化查询语言,用于和数据库通信的语言,不是某个数据库软件特有的,而是几乎所有的主流...

    目录


    配套资料,免费下载
    链接:https://pan.baidu.com/s/1WmxBogBdP2yyCSe6YPm6Hg
    提取码:y287
    复制这段内容后打开百度网盘手机App,操作更方便哦

    第一章 数据库概述

    1.1、数据库的好处

    1. 将数据持久化到本地
    2. 提供结构化查询功能

    1.2、数据库的常见概念

    1. DB:数据库,存储数据的仓库
    2. DBMS:数据库管理系统,又称为数据库软件或者数据库产品,用于创建和管理数据库,常见的有MySQL、Oracle、SQL Server
    3. DBS:数据库系统,数据库系统是一个通称,包括数据库、数据库管理系统、数据库管理人员等,是最大的范畴
    4. SQL:结构化查询语言,用于和数据库通信的语言,不是某个数据库软件特有的,而是几乎所有的主流数据库软件通用的语言

    1.3、数据库的存储特点

    1. 数据存放到表中,然后表再放到库中
    2. 一个库中可以有多张表,每张表具有唯一的表名用来标识自己
    3. 表中有一个或多个列,列又称为“字段”,相当于Java中“属性”
    4. 表中的每一行数据,相当于Java中“对象”

    1.4、数据库的常见分类

    1. 关系型数据库:MySQL、Oracle、DB2、SQL Server
    2. 非关系型数据库:
      • 键值存储数据库:Redis、Memcached、MemcacheDB
      • 列存储数据库:HBase、Cassandra
      • 面向文档的数据库:MongDB、CouchDB
      • 图形数据库:Neo4J

    1.5、SQL语言的分类

    1. DQL:数据查询语言:select、from、where
    2. DML:数据操作语言:insert、update、delete
    3. DDL:数据定义语言:create、alter、drop、truncate
    4. DCL:数据控制语言:grant、revoke
    5. TCL:事务控制语言:commit、rollback

    第二章 MySQL概述

    2.1、MySQL的背景

    MySQL的前身是属于MySQL AB,08年被SUN公司收购,09年SUN公司又被Oracle公司收购

    2.2、MySQL的优点

    1. 成本低、开源免费
    2. 性能高、移植性好
    3. 体积小、便于安装

    2.3、MySQL的安装

    01

    02

    03

    04

    05

    06

    07

    08

    09

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    2.4、MySQL的启动

    net start MySQL
    

    2.5、MySQL的停止

    net stop MySQL
    

    2.6、MySQL的登录

    mysql -h主机名 -P端口号 -u用户名 -p密码
    

    2.7、MySQL的退出

    exit
    

    第三章 DQL语言

    3.1、基础查询

    一、语法

    SELECT 查询列表 FROM 表名;
    

    二、特点

    1. 查询列表可以是字段、常量、函数、表达式
    2. 查询结果是一个虚拟表

    三、示例

    1、查询单个字段

    SELECT 字段名 FROM 表名;
    

    2、查询多个字段

    SELECT 字段名,字段名 FROM 表名;
    

    3、查询所有字段

    SELECT * FROM 表名;
    

    4、查询常量

    SELECT 常量值;
    

    注意:字符型和日期型的常量值必须用单引号引起来,数值型不需要

    5、查询函数

    SELECT 函数名(实参列表);
    

    6、查询表达式

    SELECT 100/25;
    

    7、起别名

    1SELECT 字段名 AS "别名" FROM 表名;
    

    注意:别名可以使用单引号、双引号引起来,当只有一个单词时,可以省略引号,当有多个单词且有空格或特殊符号时,不能省略,AS可以省略

    8、去重复

    SELECT DISTINCT 字段名 FROM 表名;
    

    9、做加法

    1SELECT 数值+数值; 直接运算
    2SELECT 字符+数值; 首先先将字符转换为整数,如果转换成功,则继续运算,如果转换失败,则默认为0,然后继续运算
    3SELECT NULL+数值; NULL和任何数值参与运算结果都是NULL
    

    10、【补充】ifnull函数

    功能:判断某字段或表达式是否为null,如果为null,返回指定的值,否则返回原本的值

    SELECT IFNULL(字段名, 指定值) FROM 表名;
    

    11、【补充】isnull函数

    功能:判断某字段或表达式是否为null,如果是null,则返回1,否则返回0

    SELECT ISNULL(字段名) FROM 表名;
    

    3.2、条件查询

    一、语法

    SELECT 查询列表 FROM 表名 WHERE 筛选条件;
    

    二、分类

    1. 条件运算符:>、>=、<、<=、=、<=>、!=、<>
    2. 逻辑运算符:and、or、not
    3. 模糊运算符:
      • like:%任意多个字符、_任意单个字符,如果有特殊字符,需要使用escape转义
      • between and
      • not between and
      • in
      • is null
      • is not null

    三、演示

    1、查询工资>12000的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE salary > 12000 ;
    

    2、查询工资>=14000的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE salary >= 14000 ;
    

    3、查询工资<12000的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE salary < 12000 ;
    

    4、查询工资<=14000的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE salary <= 14000 ;
    

    5、查询员工编号=100的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE employee_id = 100 ;
    

    6、查询员工编号<=>100的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE employee_id <=> 100 ;
    

    注意:=只能判断普通类型的数值,而<=>不仅可以判断普通类型的数值还可以判断NULL

    7、查询员工编号!=100的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE employee_id != 100 ;
    

    8、查询员工编号<>100的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE employee_id <> 100 ;
    

    注意:!=和<>都是判断不等于的意思,但是MySQL推荐使用<>

    9、查询工资>12000&&工资<18000的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE salary > 12000 AND salary < 18000 ;
    

    10、查询工资<=12000||工资>=18000的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE salary <= 12000 OR salary >= 18000 ;
    

    11、查询工资<=12000||工资>=18000的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE NOT (salary > 12000 AND salary < 18000) ;
    

    12、查询员工名中第一个字符为B、第四个字符为d的员工信息

    SELECT 
      *
    FROM
      employees 
    WHERE last_name LIKE 'B__d%' ;
    

    13、查询员工编号在100到120之间的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE employee_id BETWEEN 100 AND 120 ;
    

    14、查询员工编号不在100到120之间的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE employee_id NOT BETWEEN 100 AND 120 ;
    

    15、查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号

    SELECT 
      last_name,
      job_id 
    FROM
      employees 
    WHERE job_id IN ('IT_PROT', 'AD_VP', 'AD_PRES') ;
    

    注意:in列表的值类型必须一致或兼容,in列表中不支持通配符%和_

    16、查询没有奖金的员工名和奖金率

    SELECT 
      last_name,
      commission_pct 
    FROM
      employees 
    WHERE commission_pct IS NULL ;
    

    17、查询有奖金的员工名和奖金率

    SELECT 
      last_name,
      commission_pct 
    FROM
      employees 
    WHERE commission_pct IS NOT NULL ;
    

    注意:=、!=不能用来判断NULL、而<=>、is null 、 is not null可以用来判断NULL,但注意<=>也可以判断普通类型的数值

    3.3、排序查询

    一、语法

    SELECT 
      查询列表 
    FROM
      表 
    【WHERE 筛选条件】
    ORDER BY 排序列表 【asc | desc;
    

    二、注意

    1. 排序列表可以是单个字段、多个字段、别名、函数、表达式
    2. asc代表升序,desc代表降序,如果不写,默认是asc
    3. order by的位置一般放在查询语句的最后(除limit语句之外)

    三、示例

    1、按单个字段排序:查询员工信息,要求按工资降序

    SELECT 
      * 
    FROM
      employees 
    ORDER BY salary DESC ;
    

    2、按多个字段查询:查询员工信息,要求先按工资降序,再按员工编号升序

    SELECT 
      * 
    FROM
      employees 
    ORDER BY salary DESC, employee_id ASC ;
    

    3、按别名排序查询:查询员工信息,要求按员工年薪升序

    SELECT 
      *,
      salary * 12 * (1+ IFNULL(commission_pct, 0)) 年薪 
    FROM
      employees 
    ORDER BY 年薪 ASC ;
    

    4、按函数排序查询:查询员工信息,要求按员工名字的长度降序

    SELECT 
      LENGTH(last_name),
      last_name 
    FROM
      employees 
    ORDER BY LENGTH(last_name) DESC ;
    

    5、按表达式排序:查询员工信息,要求按员工年薪升序

    SELECT 
      *,
      salary * 12 * (1+ IFNULL(commission_pct, 0)) 
    FROM
      employees 
    ORDER BY salary * 12 * (1+ IFNULL(commission_pct, 0)) ASC ;
    

    3.4、单行函数

    一、语法

    SELECT 函数名(实参列表)FROM 表】;
    

    二、分类

    1. 字符函数

      • concat:连接字符
      • substr:截取子串
      • replace:替换字符
      • upper:变大写
      • lower:变小写
      • lpad:左填充
      • rpad:右填充
      • length:获取字节长度
      • trim:去除前后空格
      • instr:获取子串第一次出现的索引
      1、注意MySQL中的索引是从1开始的
      
    2. 数学函数

      • round:四舍五入
      • ceil:向上取整
      • floor:向下取整
      • mod:取模运算(a-a/b*b)
      • truncate:保留小数的位数,不进行四舍五入
      • rand:获取随机数,返回0-1之间的小数
    3. 日期函数

      • now:返回当前日期+时间
      • curdate:返回当前日期
      • curtime:返回当前时间
      • year:返回年
      • month:返回月
      • day:返回日
      • hour:小时
      • minute:分钟
      • second:秒
      • monthname:以英文形式返回月
      • datediff:返回两个日期相差的天数
      • date_format:将日期转换成字符
      • str_to_date:将字符转换成日期
      格式符:
      %Y:四位的年份
      %y:二位的年份
      %m:二位的月份(0102...12%c:一位的月份(12...12%d:日(0102...31%H:小时(24小时制)
      %h:小时(12小时制)
      %i:分钟(000102...59%s:秒(000102...59
    4. 控制函数

      • if:判断函数
      • case:分支函数
      1IF(条件表达式,表达式1,表达式2):如果条件表达式成立,返回表达式1,否则返回表达式2
      
      2case的格式一:
          CASE 变量或字段或表达式 
            WHEN 常量1 THEN1 
            WHEN 常量2 THEN2
            ...
            ELSE 值n 
          END ;
          
      3case的格式二:
          CASE
            WHEN 条件1 THEN1 
            WHEN 条件2 THEN2
            ...
            ELSE 值n 
          END
      
    5. 其它函数

      • version:当前数据库的版本
      • database:当前打开的数据库
      • user:当前登录的用户
      • password(‘字符’):返回该字符的密码形式
      • md5(‘字符’):返回该字符的md5加密形式

    三、演示

    1、concat

    SELECT CONCAT('Hello',' ','World') AS out_put;
    

    2、substr

    #截取从指定索引处后面所有字符
    SELECT SUBSTR('李莫愁爱上了陆展元',7)  AS out_put;
    
    #截取从指定索引处指定字符长度的字符
    SELECT SUBSTR('李莫愁爱上了陆展元',1,3) AS out_put;
    

    3、replace

    SELECT REPLACE('张无忌爱上了周芷若','周芷若','赵敏') AS out_put;
    

    4、upper

    SELECT UPPER('john') AS out_put;
    

    5、lower

    SELECT LOWER('john') AS out_put;
    

    6、lpad

    SELECT LPAD('殷素素',10,'*') AS out_put;
    

    7、rpad

    SELECT RPAD('殷素素',10,'*') AS out_put;
    

    8、length

    SELECT LENGTH('john') AS out_put;
    

    9、trim

    #删除指定字符的左右空格
    SELECT LENGTH(TRIM('    张翠山    ')) AS out_put;
    
    #删除指定字符的指定字符
    SELECT TRIM('aaa' FROM 'aaaaaaaaa张翠山aaaaaaaaa')  AS out_put;
    

    10、instr

    SELECT INSTR('杨不悔爱上了殷六侠','殷六侠') AS out_put;
    

    注意:返回子串第一次出现的索引,如果找不到返回0

    11、round

    #默认四舍五入
    SELECT ROUND(-1.55) AS out_put;
    
    #指定小数位数
    SELECT ROUND(1.567,2) AS out_put;
    

    注意:四舍五入和符号无关

    12、ceil

    SELECT CEIL(-1.02) AS out_put;
    

    注意:向上取整,返回>=该参数的最小整数

    13、floor

    SELECT FLOOR(-9.99) AS out_put;
    

    注意:向下取整,返回<=该参数的最大整数

    14、mod

    SELECT MOD(10,3) AS out_put;
    

    15、truncate

    SELECT TRUNCATE(1.69999,1) AS out_put;
    

    16、rand

    SELECT RAND() AS out_put;
    

    17、now

    SELECT NOW() AS out_put;
    

    18、curdate

    SELECT CURDATE() AS out_put;
    

    19、curtime

    SELECT CURTIME() AS out_put;
    

    20、year

    SELECT YEAR(NOW());
    

    21、month

    SELECT MONTH(NOW());
    

    22、day

    SELECT DAY(NOW());
    

    23、hour

    SELECT HOUR(NOW());
    

    24、minute

    SELECT MINUTE(NOW());
    

    25、second

    SELECT SECOND(NOW());
    

    26、monthname

    SELECT MONTHNAME(NOW()) 月名;
    

    27、datediff

    SELECT DATEDIFF('1995-2-7','1995-2-6') AS out_put;
    

    28、date_format

    SELECT DATE_FORMAT(NOW(),'%Y年%m月%d日') AS out_put;
    

    29、str_to_date

    SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d') AS out_put;
    

    30、if

    SELECT IF(10 < 5, '大', '小') AS out_put;
    

    31、case的格式一

    /*
    案例:查询员工的工资,要求
    	部门号=30,显示的工资为1.1倍
    	部门号=40,显示的工资为1.2倍
    	部门号=50,显示的工资为1.3倍
    	其它部门,显示的工资为原工资
    */
    
    SELECT 
      salary 原始工资,
      department_id,
      CASE
        department_id 
        WHEN 30 THEN salary * 1.1 
        WHEN 40 THEN salary * 1.2 
        WHEN 50 THEN salary * 1.3 
        ELSE salary 
      END AS 新工资 
    FROM
      employees ;
    

    32、case的格式二

    /*
    案例:查询员工的工资情况
        如果工资>20000,显示A级别
        如果工资>15000,显示B级别
        如果工资>10000,显示C级别
        否则,显示D级别
    */
    
    SELECT 
      salary,
      CASE
        WHEN salary > 20000 THEN 'A' 
        WHEN salary > 15000 THEN 'B' 
        WHEN salary > 10000 THEN 'C' 
        ELSE 'D' 
      END AS 工资级别 
    FROM
      employees ;
    

    33、version

    SELECT VERSION();
    

    34、database

    SELECT DATABASE();
    

    35、user

    SELECT USER();
    

    36、password(‘字符’)

    SELECT PASSWORD('123456');
    

    37、md5(‘字符’)

    SELECT MD5('123456');
    

    3.5、分组函数

    一、语法

    SELECT 函数名(实参列表)FROM 表】;
    

    二、分类

    1. sum:求和

    2. avg:平均值

    3. max:最大值

    4. min:最小值

    5. count:计算个数

    1、sum、avg一般用于处理数值型,max、min、count可以处理任何类型
    
    2、以上分组函数都忽略null3、可以和distinct搭配实现去重的运算:select sum(distinct 字段) from;
    
    4、一般使用count(*)用作统计行数
    
    5、和分组函数一同查询的字段要求是group by后的字段
    

    三、演示

    1、sum

    SELECT SUM(salary) FROM employees;
    

    2、avg

    SELECT AVG(salary) FROM employees;
    

    3、max

    SELECT MAX(salary) FROM employees;
    

    4、min

    SELECT MIN(salary) FROM employees;
    

    5、count

    SELECT COUNT(salary) FROM employees;
    

    3.6、分组查询

    一、语法

    SELECT 
      查询列表 
    FROM
      表 
    【where 筛选条件】 
    GROUP BY 分组的字段 
    【having 分组后的筛选】
    【order BY 排序的字段】 ;
    

    二、特点

    1、和分组函数一同查询的字段必须是group by后出现的字段
    
    2、筛选分为两类:分组前筛选和分组后筛选
                	针对的表				 语句位置			   连接的关键字
    	分组前筛选	 分组前的原始表			group bywhere
    	分组后筛选	 分组后的结果集			group byhaving
    	
    3、分组可以按单个字段也可以按多个字段
    
    4、分组可以搭配着排序使用
    

    三、演示

    1、查询每个工种的员工平均工资

    SELECT 
      AVG(salary),
      job_id 
    FROM
      employees 
    GROUP BY job_id ;
    

    2、查询每个位置的员工部门个数

    SELECT 
      COUNT(*),
      location_id 
    FROM
      departments 
    GROUP BY location_id ;
    

    3、查询有奖金的每个领导手下员工的平均工资

    SELECT 
      AVG(salary),
      manager_id 
    FROM
      employees 
    WHERE commission_pct IS NOT NULL 
    GROUP BY manager_id ;
    

    4、查询哪个部门的员工个数>5

    SELECT 
      COUNT(*),
      department_id 
    FROM
      employees 
    GROUP BY department_id 
    HAVING COUNT(*) > 5 ;
    

    5、查询每个工种有奖金的员工的最高工资>6000的最高工资和公众编号,按最高工资升序

    SELECT 
      MAX(salary) m,
      job_id
    FROM
      employees 
    WHERE commission_pct IS NOT NULL 
    GROUP BY job_id 
    HAVING m > 6000 
    ORDER BY m ;
    

    6、查询每个工种每个部门的最低工资并按最低工资降序

    SELECT 
      MIN(salary),
      job_id,
      department_id 
    FROM
      employees 
    GROUP BY job_id, department_id
    ORDER BY MIN(salary) DESC ;
    

    3.7、连接查询

    一、含义

    连接查询又称多表查询,当查询的字段来自于多个表时,就会用到连接查询

    二、注意

    笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行
    
    发生原因:没有有效的连接条件
    如何避免:添加有效的连接条件
    

    三、分类

    1. 按年代分类
      • sql92标准:支持内连接
      • sql99标准:支持内连接、部分外连接(左外、右外)、交叉连接
    2. 按功能分类
      • 内连接
        • 等值连接
        • 非等值连接
        • 自连接
      • 外连接
        • 左外连接
        • 右外连接
        • 全外连接
      • 交叉连接

    四、sql92标准演示

    1、sql92标准:等值连接

    #查询员工名和对应的部门名
    
    SELECT 
      last_name,
      department_name 
    FROM
      employees,
      departments 
    WHERE employees.`department_id` = departments.`department_id` ;
    

    2、sql92标准:非等值连接

    #查询员工的工资和工资级别
    
    SELECT 
      salary,
      grade_level 
    FROM
      employees e,
      job_grades g 
    WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal` ;
    

    3、sql92标准:自连接

    #查询员工名和它对应上级的名称
    
    SELECT 
      e.employee_id,
      e.last_name,
      m.employee_id,
      m.last_name 
    FROM
      employees e,
      employees m 
    WHERE e.`manager_id` = m.`employee_id` ;
    

    3.8、sql99标准

    一、语法

    SELECT 
      查询列表 
    FROM1 别名1 
    【连接类型】 JOIN2 别名2 ON 连接条件 
    【where 分组前筛选条件】
    【group BY 分组列表】
    【having 分组后筛选条件】
    【order BY 排序列表】 ;
    

    二、连接类型

    1. 内连接:inner
    2. 外连接
      • 左外连接:left 【outer】(左边的是主表)
      • 右外连接:right 【outer】(右边的是主表)
      • 全外连接:full 【outer】(两边都是主表,但是MySQL不支持全外连接、Oracle支持)
    3. 交叉连接:cross(交叉连接其实是用sql99语法实现笛卡尔乘积)

    三、演示

    1、内连接:等值连接

    #查询员工名和对应的部门名
    
    SELECT 
      last_name,
      department_name 
    FROM
      departments d 
    INNER JOIN employees e ON e.`department_id` = d.`department_id` ;
    

    2、内连接:非等值连接

    #查询员工的工资和工资级别
    
    SELECT 
      salary,
      grade_level 
    FROM
      employees e 
    INNER JOIN job_grades g ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal` ;
    

    3、内连接:自连接

    #查询员工名和它对应上级的名称
    
    SELECT 
      e.last_name,
      m.last_name 
    FROM
      employees e 
    INNER JOIN employees m ON e.`manager_id` = m.`employee_id` ;
    

    4、外连接:左外连接

    #查询哪个部门没有员工
    
    SELECT 
      d.`department_name`
    FROM
      departments d 
    LEFT OUTER JOIN employees e ON d.`department_id` = e.`department_id` 
    WHERE e.`employee_id` IS NULL ;
    

    5、外连接:右外连接

    #查询哪个部门没有员工
    
    SELECT 
      d.`department_name`
    FROM
      employees e 
    RIGHT OUTER JOIN departments d ON d.`department_id` = e.`department_id` 
    WHERE e.`employee_id` IS NULL ;
    

    6、交叉连接

    #使用交叉连接进行笛卡尔乘积查询
    
    SELECT 
      b.*,
      bo.* 
    FROM beauty b 
    CROSS JOIN boys bo ;
    

    3.9、子查询

    一、含义

    嵌套在其它语句内部的select语句称为子查询或内查询,外面的语句可以是insert、delete、update、select等,一般select作为外面语句较多,外面如果为select语句,则此语句称为外查询或主查询

    二、分类

    1. 按出现的位置划分
      • select后面:标量子查询
      • from后面:表子查询
      • where或having后面
        • 标量子查询
        • 列子查询
        • 行子查询
      • exists后面
        • 标量子查询
        • 列子查询
        • 行子查询
        • 表子查询
    2. 按结果集行列数划分
      • 标量子查询(单行子查询):结果集为一行一列
      • 列子查询(多行子查询):结果集为多行一列
      • 行子查询:结果集为多行多列
      • 表子查询:结果集为多行多列

    三、特点

    1. 子查询放在小括号内
    2. 子查询一般放在条件的右侧
    3. 子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果
    4. 标量子查询,一般搭配着单行操作符使用:>、>=、<、<=、!=、<>、=、<=>
    5. 列子查询,一般搭配着多行操作符使用:in、not in、any、some、all、exits

    四、演示

    1、select后面

    #查询每个部门的员工个数
    
    SELECT 
      d.*, (
      SELECT 
        COUNT(*) 
      FROM
        employees e 
      WHERE e.department_id = d.`department_id`
    ) 个数 
    FROM
      departments d ;
    

    2、from后面

    #查询每个部门平均工资的工资等级
    
    SELECT 
      ag_dep.*,
      g.`grade_level` 
    FROM (
      SELECT 
        AVG(salary) ag,
        department_id 
      FROM
        employees 
      GROUP BY department_id
    ) ag_dep 
    INNER JOIN job_grades g ON ag_dep.ag BETWEEN lowest_sal AND highest_sal ;
    

    3、where或having后面

    标量子查询:查询最低工资的员工姓名和工资

    SELECT 
      last_name,
      salary 
    FROM
      employees 
    WHERE salary = (
    	SELECT MIN(salary) FROM employees
    ) ;
    

    列子查询:

    #查询所有是领导的员工姓名
    
    SELECT 
      last_name 
    FROM
      employees 
    WHERE employee_id IN (
    	SELECT DISTINCT manager_id FROM employees
    ) ;
    
    #返回其它工种中比job_id为‘IT_PROG’工种任一工资低的员工的员工号、姓名、job_id以及salary
    
    SELECT 
      employee_id,
      last_name,
      job_id,
      salary 
    FROM
      employees 
    WHERE salary < ANY (
      SELECT DISTINCT salary FROM employees WHERE job_id = 'IT_PROG'
    ) AND job_id <> 'IT_PROG' ;
    
    #返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工的员工号、姓名、job_id以及salary
    
    SELECT 
      employee_id,
      last_name,
      job_id,
      salary 
    FROM
      employees 
    WHERE salary < ALL (
      SELECT DISTINCT salary FROM employees WHERE job_id = 'IT_PROG'
    ) AND job_id <> 'IT_PROG' ;
    

    行子查询:查询员工编号最小并且工资最高的员工信息

    SELECT 
      * 
    FROM
      employees 
    WHERE (employee_id, salary) = (
    	SELECT MIN(employee_id), MAX(salary) FROM employees
    ) ;
    

    4、exists后面

    #查询有员工的部门名
    
    SELECT 
      department_name 
    FROM
      departments d 
    WHERE EXISTS (
    	SELECT * FROM employees e
    	WHERE e.`department_id` = d.`department_id`
    ) ;
    

    3.10、分页查询

    一、语法

    SELECT 
      查询列表 
    FROM1 别名1
    【连接类型】 JOIN2 别名2 ON 连接条件 
    【WHERE 分组前的筛选】
    【GROUP BY 分组字段】 
    【HAVING 分组后的筛选 】
    【ORDER BY 排序字段 ASC|DESCLIMIToffset, 】size ;
    

    二、特点

    1. limit语句放在查询语句的最后
    2. offset代表起始索引,起始索引从0开始,size代表条目个数
    3. 分页语句:select 查询列表 from 表 limit (page-1)*size,size;

    三、演示

    #查询前五条员工信息
    
    SELECT * FROM  employees LIMIT 0,5;
    

    3.11、联合查询

    一、语法

    查询语句1
    unionall】
    查询语句2
    unionall...
    

    二、特点

    1. 要查询的结果来自于多个表且多个表没有直接的连接关系,但查询的信息一致时,可以使用联合查询
    2. 要求多条查询语句的查询列数是一致的
    3. 要求多条查询语句的查询的每一列的类型和顺序最好一致
    4. union关键字默认去重,如果使用union all可以包含重复项

    三、演示

    #查询中国用户中男性的信息以及外国用户中年男性的用户信息
    
    SELECT id,cname FROM t_ca WHERE csex='男'
    UNION ALL
    SELECT t_id,tname FROM t_ua WHERE tGender='male';
    

    第四章 DML语言

    4.1、插入语句

    一、语法

    #方式一:
    INSERT INTO 表名(字段名,...) VALUES(,...);
    
    #方式二:
    INSERT INTO 表名 SET 字段名=,字段名=,...;
    

    二、特点

    1. 要求值的类型和字段的类型要一致或兼容
    2. 字段的个数和顺序不一定与原始表中的字段个数和顺序一致,但必须保证值和字段一一对应
    3. 假如表中有可以为null的字段,注意可以通过以下两种方式插入null值:①字段和值都省略、②字段写上,值使用null
    4. 字段和值的个数必须一致
    5. 字段名可以省略,默认所有列
    6. 方式一支持一次插入多行,语法如下:INSERT INTO 表名【(字段名,…)】 VALUES(值,…),(值,…),…;
    7. 方式一支持子查询,语法如下:INSERT INTO 表名 查询语句;

    三、演示

    1、方式一:插入数据

    INSERT INTO beauty(id,name,sex,borndate,phone,photo,boyfriend_id) 
    			VALUES(15,'唐艺昕','女','1997-12-05','15633029014',NULL,2);
    

    2、方式二:插入数据

    INSERT INTO beauty SET 
        id = 19,name = '张倩倩',
        sex = '女',
        borndate = '1997-12-05',
        phone = '15633029014',
        photo = NULL,
        boyfriend_id = 3 ;
    

    4.2、修改语句

    一、语法

    1、单表更新
    UPDATE 表名 SET=,... WHERE 查询条件;
    
    2、多表更新
    #sql92语法: 
    UPDATE1 别名,2 别名 
    SET=,
      ...
    WHERE 连接条件 AND 筛选条件 ;
    
    #sql99语法: 
    UPDATE1 别名 
    INNER | LEFT | RIGHT JOIN2 别名 ON 连接条件
      SET=,
      ...
    WHERE 筛选条件 ;
    

    二、演示

    1、单表更新

    #修改beauty表中姓唐的女神的电话为13899888899
    
    UPDATE beauty SET phone = '13899888899' WHERE NAME LIKE '唐%';
    

    2、多表更新

    #修改张无忌的女朋友的手机号为13899888899,魅力值为1000
    sql92语法:
    UPDATE 
      boys bo,
      beauty b 
      SET b.`phone` = '13899888899',
          bo.`userCP` = 1000 
    WHERE bo.`id` = b.`boyfriend_id` AND bo.`boyName` = '张无忌' ;
    
    #修改张无忌的女朋友的手机号为13899888899,魅力值为1000
    sql99语法:
    UPDATE 
      boys bo 
    INNER JOIN beauty b ON bo.`id` = b.`boyfriend_id`
      SET b.`phone` = '13899888899',
          bo.`userCP` = 1000 
    WHERE bo.`boyName` = '张无忌' ;
    

    4.3、删除语句

    一、语法

    1、单表删除 
    DELETE FROM 表名 【WHERE 筛选条件 】;
    
    2、多表删除(级联删除)
    sql92语法: 
    DELETE1的别名,2的别名 
    FROM1 别名,2 别名 
    WHERE 连接条件 AND 筛选条件 ;
    
    sql99语法: 
    DELETE1的别名,2的别名 
    FROM1 别名 
    INNER | LEFT | RIGHT JOIN2 别名 ON 连接条件 
    WHERE 筛选条件 ;
    

    二、演示

    1、单表删除

    #删除手机号以9结尾的女神信息
    
    DELETE FROM beauty WHERE phone LIKE '%9';
    

    2、多表删除

    #删除黄晓明的信息以及他女朋友的信息
    #sql92语法:
    DELETE
      b,
      bo
    FROM
      beauty b,
      boys bo
    WHERE b.`boyfriend_id` = bo.`id` AND bo.`boyName` = '黄晓明' ; 
    
    #删除黄晓明的信息以及他女朋友的信息
    #sql99语法:
    DELETE 
      b,
      bo 
    FROM
      beauty b 
    INNER JOIN boys bo ON b.`boyfriend_id` = bo.`id` 
    WHERE bo.`boyName` = '黄晓明' ;
    

    第五章 DDL语言

    5.1、库的管理

    5.1.1、库的创建

    CREATE DATABASEIF NOT EXISTS】 库名 【 CHARACTER SET 字符集名】;
    

    5.1.2、库的修改

    #它已经被废弃
    RENAME DATABASE 旧库名 TO 新库名;
    
    #修改库字符集
    ALTER DATABASE 库名 CHARACTER SET 字符集名;
    

    5.1.3、库的删除

    DROP DATABASEIF EXISTS】 库名;
    

    5.2、表的管理

    5.2.1、表的创建

    CREATE TABLEIF NOT EXISTS】 表名 (
      字段名 字段类型 【约束】,
      字段名 字段类型 【约束】,
      ...
      字段名 字段类型 【约束】
    ) ;
    

    5.2.2、表的修改

    1、添加列
    ALTER TABLE 表名 ADD COLUMN 列名 类型 【FIRST|AFTER 字段名】;
    
    2、修改列的类型或约束
    ALTER TABLE 表名 MODIFY COLUMN 列名 新类型 【新约束】;
    
    3、修改列名
    ALTER TABLE 表名 CHANGE COLUMN 旧列名 新列名 类型;
    
    4、删除列
    ALTER TABLE 表名 DROP COLUMN 列名;
    
    5、修改表名
    ALTER TABLE 表名 RENAMETO】 新表名;
    

    5.2.3、表的删除

    方式一:DROP TABLEIF EXISTS】 表名;
    
    方式二:TRUNCATE TABLEIF EXISTS】 表名;
    

    5.2.4、表的复制

    1、复制表的结构
    CREATE TABLE 表名 LIKE 旧表;
    
    2、复制表的某些字段
    CREATE TABLE 表名 
    SELECT 字段1,字段2,... FROM 旧表 WHERE 0;
    
    3、复制表的结构+数据
    CREATE TABLE 表名 
    SELECT 查询列表 FROM 旧表 【WHERE 筛选条件】;
    
    4、复制表的某些字段+数据
    CREATE TABLE 表名 
    SELECT 字段1,字段2,... FROM 旧表 【WHERE 筛选条件】;
    

    5.3、数据类型

    5.3.1、数值型

    一、类型

    类型 TINYINT SMALLINT MEDIUMINT INT/INTEGER BIGINT
    字节 1 2 3 4 8

    二、特点

    1. 都可以设置无符号和有符号,默认有符号,通过unsigned设置无符号
    2. 如果超出了范围,会报out or range异常,插入临界值(该类型的最大值或最小值即为临界值)
    3. 长度可以不指定,默认会有一个长度,长度代表显示的最大宽度,如果不够则左边用0填充,但需要搭配zerofill,并且默认变为无符号整型
    4. 如果对数据没有特殊要求,则优先考虑使用INT/INTEGER

    5.3.2、浮点型

    一、类型

    1. 定点数
      • DEC(M,D) :M+2字节
      • DECIMAL(M,D):M+2字节
    2. 浮点数
      • FLOAT(M,D) :4字节
      • DOUBLE(M,D):8字节

    二、特点

    1. M代表整数部位+小数部位的个数,D代表小数部位
    2. 如果超出范围,则报out or range异常,并且插入临界值(该类型的最大值或最小值即为临界值)
    3. M和D都可以省略,但对于定点数,M默认为10,D默认为0
    4. 如果精度要求较高,则优先考虑使用定点数

    5.3.3、字符型

    一、类型

    类型 CHAR VARCHAR BINARY VARBINARY ENUM SET TEXT BLOB
    描述 固定长度字符 可变长度字符 二进制字符串 二进制字符串 枚举 集合 文本 二进制大型对象

    二、特点

    1. char:固定长度的字符,写法为char(M),最大长度不能超过M,其中M可以省略,默认为1
    2. varchar:可变长度的字符,写法为varchar(M),最大长度不能超过M,其中M不可以省略
    3. 如果对数据没有特殊要求,则优先考虑使用VARCHAR

    5.3.4、日期型

    一、类型

    类型 YEAR DATE TIME DATETIME TIMESTAMP
    描述 年份 日期 时间 日期+时间 日期+时间

    二、特点

    1. TIMESTAMP比较容易受时区、语法模式、版本的影响,更能反映当前时区的真实时间,而DATETIME则只能反映出插入时的当地时区
    2. TIMESTAMP支持的时间范围较小,DATETIME的取值范围:1000-1-1 — 9999-12-31
    3. TIMESTAMP的属性受Mysql版本和SQLMode的影响很大
    4. 如果对数据没有特殊要求,则优先考虑使用DATETIME

    5.4、常见约束

    一、含义

    约束是一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性

    二、分类

    1. NOT NULL:非空,该字段的值必填
    2. UNIQUE:唯一,该字段的值不可重复
    3. DEFAULT:默认,该字段的值不用手动插入有默认值
    4. CHECK:检查,MySQL不支持
    5. PRIMARY KEY:主键,该字段的值不可重复并且非空 unique+not null
    6. FOREIGN KEY:外键,该字段的值引用了另外的表的字段

    三、特点

    主键和唯一

    #不同点:
    1、一个表至多有一个主键,但可以有多个唯一
    2、主键不允许为空,唯一可以为空
    
    #相同点:
    1、都具有唯一性
    2、都支持组合键,但不推荐
    

    外键

    1、用于限制两个表的关系,从表的字段值引用了主表的某字段值
    2、外键列和主表的被引用列要求类型一致,意义一样,名称无要求
    3、主表的被引用列要求是一个key(一般就是主键)
    4、插入数据,先插入主表;删除数据,先删除从表
    
    
    可以通过以下两种方式来删除主表的记录
    #方式一:级联删除
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE CASCADE;
    
    #方式二:级联置空
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE SET NULL;
    

    四、演示

    1、创建表时添加约束

    CREATE TABLE 表名(
    	字段名 字段类型 NOT NULL,#非空
        字段名 字段类型 DEFAULT,#默认
    	字段名 字段类型 PRIMARY KEY,#主键
    	字段名 字段类型 UNIQUE,#唯一
    	CONSTRAINT 约束名 FOREIGN KEY(字段名) REFERENCES 主表(被引用列)
    ) ;
    

    注意:

    1. 列级约束支持:非空、默认、主键、唯一,不可以起约束名
    2. 表级约束支持:主键、唯一、外键,可以起约束名,但是在MySQL中对主键无效
    3. 列级约束可以在一个字段上追加多个,中间用空格隔开,没有顺序要求

    2、修改表时添加或删除约束

    1、非空
    添加非空(列级约束)
    ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 NOT NULL;
    删除非空
    ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型;
    
    2、默认
    添加默认(列级约束)
    ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 DEFAULT;
    删除默认
    ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型;
    
    3、主键
    添加主键(列级约束)
    ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 PRIMARY KEY;
    添加主键(表级约束)
    ALTER TABLE 表名 addCONSTRAINT 约束名】 PRIMARY KEY(字段名);
    删除主键
    ALTER TABLE 表名 DROP PRIMARY KEY;
    
    4、唯一
    添加唯一(列级约束)
    ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 UNIQUE;
    添加唯一(表级约束)
    ALTER TABLE 表名 addCONSTRAINT 约束名】 UNIQUE(字段名);
    删除唯一
    ALTER TABLE 表名 DROP INDEX 索引名;
    
    5、外键
    添加外键(表级约束)
    ALTER TABLE 表名 addCONSTRAINT 约束名】 FOREIGN KEY(字段名) REFERENCES 主表(被引用列);
    删除外键
    ALTER TABLE 表名 DROP FOREIGN KEY 约束名;
    

    5.5、自增长列

    一、含义

    自增长列又称为标识列,它可以不用手动的插入值,系统提供默认的序列值

    二、特点

    1. 不用手动插入值,可以自动提供序列值,默认从1开始,步长为1,如果要更改起始值,第一次手动插入值,后续使用NULL,如果要更改步长,修改更改系统变量:SET auto_increment_increment = 值;
    2. 一个表至多有一个自增长列
    3. 自增长列只能支持数值型
    4. 自增长列必须为一个key

    三、演示

    1、创建表时添加自增长列

    CREATE TABLE 表名 (
      字段名 字段类型 约束 AUTO_INCREMENT
    ) ;
    

    2、修改表时添加或删除自增长列

    添加自增长列
    ALTER TABLEMODIFY COLUMN 字段名 字段类型 约束 AUTO_INCREMENT;
    
    删除自增长列
    ALTER TABLEMODIFY COLUMN 字段名 字段类型 约束;
    

    第六章 DCL语言

    关于授权的权限列表:

    image-20200809204539412

    6.1、创建用户

    CREATE USER 用户名@'IP地址' IDENTIFIED BY '密码';
    注意:'IP地址'可以设置为localhost(代表本机)或者'%'(代表允许所有IP地址登录)
    

    6.2、删除用户

    DROP USER 用户名@'IP地址';
    注意:'IP地址'可以设置为localhost(代表本机)或者'%'(代表允许所有IP地址登录)
    

    6.3、用户授权

    GRANT 权限1,权限2,...... ON 数据库名.* TO 用户名@'IP地址' IDENTIFIED BY '密码';
    注意:所有的数据库就用*.*,所有的权限就用all或者all privileges
    

    6.4、撤销授权

    REVOKE 权限1,权限2,...... ON 数据库名.* FROM 用户名@'IP地址' IDENTIFIED BY '密码';
    注意:所有的数据库就用*.*,所有的权限就用all或者all privileges
    

    6.5、刷新授权

    FLUSH PRIVILEGES;
    

    6.6、查看授权

    SHOW GRANTS FOR 用户名@'IP地址';
    注意:'IP地址'可以设置为localhost(代表本机)或者'%'(代表允许所有IP地址登录)
    

    6.7、修改密码

    #修改密码
    SET PASSWORD = PASSWORD('123456');
    #登录授权
    GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456';
    #刷新授权
    FLUSH PRIVILEGES;
    

    6.8、忘记密码

    1、可以在配置文件里加上 skip-grant-tables ,注意写到[mysqld]参数组下,表示跳过授权
    2、重启MySQL再登录就不需要密码,进去改密码,改完后,直接 FLUSH PRIVILEGES; 就可以使用新密码来登录了
    (例:UPDATE mysql.user SET PASSWORD=PASSWORD("123456") WHERE USER="root" AND HOST="localhost";)
    3、改完后记得去掉配置文件例的 skip-grant-tables,重新启动MySQL服务
    4、再使用新的密码登录就可以了
    

    第七章 TCL语言

    7.1、事务

    一、含义

    一条或多条sql语句组成一个执行单位,一组sql语句要么都执行要么都不执行

    二、特点(ACID)

    1. 原子性:一个事务是不可再分割的整体,要么都执行要么都不执行
    2. 一致性:一个事务的执行不能破坏数据库数据的完整性和一致性
    3. 隔离性:一个事务不受其它事务的干扰,多个事务是互相隔离的
    4. 持久性:一个事务一旦提交了,则永久的持久化到本地

    三、分类

    1. 隐式事务:没有明显的开启和结束,本身就是一条事务可以自动提交,比如insert、update、delete
    2. 显式事务:具有明显的开启和结束,例如以下格式:
    1、开启事务
    set autocommit=0;#关闭自动提交
    start transaction;#开启事务机制
    
    2、编写一组逻辑sql语句
    注意:sql语句支持的是insertupdatedelete
    
    【设置回滚点,可选项】
    savepoint 回滚点名;
    
    3、结束事务
    提交:commit;
    回滚:rollback;
    回滚到指定的地方: rollback to 回滚点名;
    

    7.2、事务并发(读问题)

    一、事物的并发问题如何发生?

    多个事务同时操作同一个数据库的相同数据时

    二、事务的并发问题都有哪些?

    1. 脏读:一个事务读到了另一个事务还未提交的update数据,导致多次查询的结果不一样
    2. 不可重复读:一个事务读到了另一个事务已经提交的update数据,导致多次查询结果不一致
    3. 幻读:一个事务读到了另一个事务已经提交的insert数据,导致多次查询的结果不一样

    三、事物的并发问题如何解决?

    通过设置隔离级别来解决并发问题

    四、隔离级别

    隔离级别 隔离描述 脏读 不可重复读 幻读
    READ UNCOMMITTED 读未提交 × × ×
    READ COMMITTED 读已提交 × ×
    REPEATABLE READ 可重复读 ×
    SERIALIZABLE 串行化

    五、注意问题

    1. mysql 中默认第三个隔离级别 REPEATABLE READ
      oracle中默认第二个隔离级别 READ COMMITTED
      
    2. 查看隔离级别 SELECT @@tx_isolation;
      设置隔离级别 SET SESSION|GLOBAL TRANSACTION ISOLATION LEVEL 隔离级别;
      

    7.3、丢失更新(写问题)

    一、定义

    在事务的隔离级别内容中,能够了解到两个不同的事务在并发的时候可能会发生数据的影响。细心的话可以发现事务隔离级别章节中,脏读、不可重复读、幻读三个问题都是由事务A对数据进行修改、增加,事务B总是在做读操作。如果两事务都在对数据进行修改则会导致另外的问题:丢失更新。

    二、解决

    1. 悲观锁:认为两个事务更新操作一定会发生丢失更新
      • 解决:通过在语句后边添加for update来实现行级上锁,所以又称为“行级锁”,例如:select * from t_account t wheret.id=‘1’ for update;
    2. 乐观锁:认为事务不一定会产生丢失更新,让事务进行并发修改,不对事务进行锁定
      • 解决:由程序员自己解决,可以通过给数据表添加自增的version字段或时间戳timestamp,进行数据修改时,数据库会检测version字段或者时间戳是否与原来的一致,若不一致,抛出异常或者重新查询

    三、注意

    对于账户交易建议直接使用悲观锁,数据库的性能很高,并发度不是很高的场景两者性能没有太大差别。如果是交易减库存的操作可以考虑乐观锁,保证并发度。

    第八章 高级部分

    8.1、索引

    一、含义

    索引(index)是帮助MySQL高效获取数据的一种有序的数据结构

    二、特点

    1. 优势:
      • 类似于书籍的目录索引,提高数据检索的效率,降低数据库的IO成本
      • 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗
    2. 劣势:
      • 实际上索引也是一张表,该表中保存了主键与索引字段,并指向实体类的记录,所以索引列也是要占用空间的
      • 虽然索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE。因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息

    三、语法

    1、创建

    CREATEUNIQUE|FULLTEXT|SPATIAL 】 INDEX 索引名称 ON 表名(字段列表);
    

    2、修改

    先删除,在创建
    

    3、删除

    DROP INDEX 索引名称 ON 表名;
    

    4、查看

    SHOW INDEX FROM 表名;
    

    5、alter命令

    #该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL
    ALTER TABLE 表名 ADD PRIMARY KEY(字段列表); 
    	
    #这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)
    ALTER TABLE 表名 ADD UNIQUE 索引名称(字段列表);
    	
    #添加普通索引,索引值可以出现多次。
    ALTER TABLE 表名 ADD INDEX 索引名称(字段列表);
    	
    #该语句指定了索引为FULLTEXT,用于全文索引	
    ALTER TABLE 表名 ADD FULLTEXT 索引名称(字段列表);
    

    四、注意

    索引的设计可以遵循一些已有的原则,创建索引的时候请尽量考虑符合这些原则,便于提升索引的使用效率,更高效的使用索引:

    1. 索引字段的选择,最佳候选列应当从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合
    2. 索引可以有效的提升查询数据的效率,但索引数量不是多多益善,索引越多,维护索引的代价自然也就水涨船高。对于插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引入相当高的维护代价,降低DML操作的效率,增加相应操作的时间消耗。另外索引过多的话,MySQL也会犯选择困难病,虽然最终仍然会找到一个可用的索引,但无疑提高了选择的代价
    3. 对查询频次较高,且数据量比较大的表建立索引
    4. 使用唯一索引,区分度越高,使用索引的效率越高
    5. 使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。假如构成索引的字段总长度比较短,那么在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MySQL访问索引的I/O效率
    6. 使用组合索引,如果查询时where子句中使用了组成该索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询效率。例如:CREATE INDEX idx_name_email_status ON tb_seller(name,email,status); 就相当于对name 创建索引;对name , email 创建了索引;对name , email, status 创建了索引

    8.2、视图

    一、含义

    MySQL在5.1以后推出了视图(VIEW),本身是一个虚拟表,它的数据来自于表,通过执行时动态生成

    二、特点

    1. 简化sql语句
    2. 提高了sql的重用性
    3. 保护基表的数据,提高了安全性

    三、语法

    1、创建

    CREATE VIEW 视图名
    AS
    查询语句;
    

    2、修改

    #方式一:
    CREATE OR REPLACE VIEW 视图名
    AS
    查询语句;
    
    #方式二:
    ALTER VIEW 视图名
    AS
    查询语句;
    

    3、删除

    DROP VIEW 视图1,视图2,...;
    

    4、查看

    #方式一:
    DESC 视图名;
    
    #方式二:
    SHOW CREATE VIEW 视图名;
    

    四、注意

    视图一般用于查询的,而不是更新的,所以具备以下特点的视图都不允许更新:

    1. 包含分组函数、group by、distinct、having、union、join
    2. 常量视图
    3. where后的子查询用到了from中的表
    4. 用到了不可更新的视图

    8.3、存储过程

    8.3.1、语法

    一、含义

    存储过程,类似于Java中的方法,它是一组预先编译好的SQL语句的集合,理解成批处理语句

    二、特点

    1. 简化sql语句
    2. 提高了sql的重用性
    3. 减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率

    三、语法

    1、创建

    #标准格式如下:
    DELIMITER $
    CREATE PROCEDURE 存储过程名(参数模式 参数名 参数类型,...)
    BEGIN
    	存储过程体(一组合法的SQL语句)
    END $
    DELIMITER ;
    
    #参数模式in:参数类型是输入的
    #参数模式out:参数类型是输出的
    #参数模式inout:参数类型既可以输入也可以输出
    
    #调用in模式的参数: CALL sp1('Hello,World');
    #调用out模式的参数: SET @name; CALL sp1(@name); SELECT @name;
    #调用inout模式的参数: SET @name=值; CALL sp1(@name); SELECT @name;
    

    2、修改

    先删除,在创建
    

    3、删除

    DROP PROCEDURE 存储过程名;
    

    4、查看

    SHOW CREATE PROCEDURE 存储过程名;
    

    8.3.2、变量

    一、分类

    1. 系统变量
      • 全局变量
      • 会话变量
    2. 自定义变量
      • 用户变量
      • 局部变量

    二、语法

    1、全局变量

    描述:服务器层面上的,必须拥有super权限才能为系统变量赋值,作用域为整个服务器,也就是针对于所有连接(会话)有效,但不能跨重启

    1、查看所有系统变量
    SHOW GLOBAL VARIABLES;
    
    2、查看满足条件的部分系统变量
    SHOW GLOBAL VARIABLES LIKE '%char%';
    
    3、查看指定的系统变量的值
    SELECT @@global 系统变量名;
    
    4、为某个系统变量赋值
    方式一: SET GLOBAL 系统变量名=;
    方式二: SET @@global 系统变量名=;
    

    2、会话变量

    描述:服务器为每一个连接的客户端都提供了系统变量,作用域为当前的连接(会话)

    1、查看所有系统变量
    SHOWSESSION 】 VARIABLES;
    
    2、查看满足条件的部分系统变量
    SHOWSESSION 】 VARIABLES LIKE '%char%';
    
    3、查看指定的系统变量的值
    SELECTSESSION 】系统变量名;
    
    4、为某个系统变量赋值
    SETSESSION 】系统变量名=;
    

    3、用户变量

    描述:针对于当前连接(会话)生效

    位置:可以在begin end里面,也可以放在外面

    1、声明并赋值
    SET @变量名=;SET @变量名:=;SELECT @变量名:=;
    
    2、更新值
    方式一:
    	SET @变量名=;SET @变量名:=;SELECT @变量名:=;
    方式二:
    	SELECT xxx INTO @变量名 FROM;
    	
    3、查看值
    SELECT @变量名;
    

    4、局部变量

    描述:作用域:仅仅在定义它的begin end中有效
    位置:只能放在begin end中,而且只能放在第一句

    1、声明并赋值
    DECLARE 变量名 类型 【 DEFAULT 值 】;
    
    2、更新值
    方式一:
    	SET 变量名=;SET 变量名:=;SELECT @变量名:=;
    方式二:
    	SELECT xxx INTO 变量名 FROM;
    	
    3、查看值
    SELECT 变量名;
    

    8.3.3、分支结构

    8.3.3.1、if结构

    一、语法

    注意:只能应用在begin end中

    IF 条件1 THEN 语句1;
    ELSEIF 条件2 THEN 语句2;
    ELSEIF 条件3 THEN 语句3;
    ....ELSE 语句n;END IF;
    

    二、演示

    #创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
    DELIMITER $
    CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR
    BEGIN
    	DECLARE ch CHAR DEFAULT 'A';
    	IF score>90 THEN SET ch='A';
    	ELSEIF score>80 THEN SET ch='B';
    	ELSEIF score>60 THEN SET ch='C';
    	ELSE SET ch='D';
    	END IF;
    	RETURN ch;
    END $
    DELIMITER ;
    
    #函数调用
    SELECT test_if(87)$
    
    8.3.3.2、case结构

    一、语法

    注意:只能应用在begin end中

    语法1CASE 表达式或字段
    WHEN1 THEN 语句1;
    WHEN2 THEN 语句2;
    ...ELSE 语句n;ENDCASE;
    
    语法2CASE 
    WHEN 条件1 THEN 语句1;
    WHEN 条件2 THEN 语句2;
    ...ELSE 语句n;ENDCASE;
    

    二、演示

    #创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D
    DELIMITER $
    CREATE FUNCTION test_case (score FLOAT) RETURNS CHAR 
    BEGIN
    	DECLARE ch CHAR DEFAULT 'A' ;
    	
    	CASE 
    	WHEN score>90 THEN SET ch='A';
    	WHEN score>80 THEN SET ch='B';
    	WHEN score>60 THEN SET ch='C';
    	ELSE SET ch='D';
    	END CASE;
    	
    	RETURN ch;
    END $
    DELIMITER ;
    
    #函数调用
    SELECT test_case(56);
    

    8.3.4、循环结构

    一、分类

    image-20200728162123754

    二、演示

    8.3.4.1、while结构
    #批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
    #删除过程
    DROP PROCEDURE IF EXISTS test_while;
    
    #定义过程
    DELIMITER $
    CREATE PROCEDURE test_while(IN insertCount INT)
    BEGIN
    	DECLARE i INT DEFAULT 1;
    	a:WHILE i<=insertCount DO
    		#LEAVE代表Java中的break关键字;ITERATE代表Java中的continue关键字
    		IF i>20 THEN LEAVE a;
    		END IF;
    		INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
    		SET i=i+1;
    	END WHILE a;
    END $
    DELIMITER ;
    
    #调用过程
    CALL test_while(100);
    
    8.3.4.2、repeat结构
    #批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
    #删除过程
    DROP PROCEDURE IF EXISTS test_repeat;
    
    #定义过程
    DELIMITER $
    CREATE PROCEDURE test_repeat(IN insertCount INT)
    BEGIN
    	DECLARE i INT DEFAULT 1;
    	a:REPEAT 
    		INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
    		SET i=i+1;
    	UNTIL i>20		
    	END REPEAT a;
    END $
    DELIMITER ;
    
    #调用过程
    CALL test_repeat(100);
    
    8.3.4.3、loop结构
    #批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止
    #删除过程
    DROP PROCEDURE IF EXISTS test_loop;
    
    #定义过程
    DELIMITER $
    CREATE PROCEDURE test_loop(IN insertCount INT)
    BEGIN
    	DECLARE i INT DEFAULT 1;
    	a:LOOP 
    		#LEAVE代表Java中的break关键字;ITERATE代表Java中的continue关键字
    		IF i>20 THEN LEAVE a;
    		END IF;
    		INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000');
    		SET i=i+1;
    	END LOOP a;
    END $
    DELIMITER ;
    
    #调用过程
    CALL test_loop(100);
    

    8.3.5、游标

    一、含义

    游标是用来存储查询结果集的数据类型 , 在存储过程和函数中可以使用光标对结果集进行循环的处理

    二、语法

    1、声明游标

    DECLARE 游标名称 CURSOR FOR select结果集;
    

    2、打开游标

    OPEN 游标名称;
    

    3、获取游标

    FETCH 游标名称 INTO 变量列表(需要跟select结果集的字段对应);
    

    4、关闭游标

    CLOSE 游标名称;
    

    三、演示

    建数据表以用来演示

    CREATE TABLE emp (
      id INT (11) NOT NULL AUTO_INCREMENT,
      NAME VARCHAR (50) NOT NULL COMMENT '姓名',
      age INT (11) COMMENT '年龄',
      salary INT (11) COMMENT '薪水',
      PRIMARY KEY (`id`)
    ) ENGINE = INNODB DEFAULT CHARSET = utf8 ;
    
    INSERT INTO emp(id,NAME,age,salary) 
    VALUES
    (NULL,'金毛狮王',55,3800),
    (NULL,'白眉鹰王',60,4000),
    (NULL,'青翼蝠王',38,2800),
    (NULL,'紫衫龙王',42,1800);
    

    循环获取该表的内容

    DELIMITER $
    CREATE PROCEDURE getAllRowsForEmpTable()
    BEGIN
      DECLARE e_id INT(11);
      DECLARE e_name VARCHAR(50);
      DECLARE e_age INT(11);
      DECLARE e_salary INT(11);
      DECLARE has_data INT DEFAULT 1;
      
      DECLARE emp_result CURSOR FOR SELECT * FROM emp;
      DECLARE EXIT HANDLER FOR NOT FOUND SET has_data=0;
      
      OPEN emp_result;
      
      REPEAT
        FETCH emp_result INTO e_id,e_name,e_age,e_salary;
        SELECT CONCAT('id=',e_id , ', name=',e_name, ', age=', e_age, ', salary=',e_salary) as emp_info;
        UNTIL has_data = 0
      END REPEAT;
      
      CLOSE emp_result;
    END$
    DELIMITER ; 
    

    打开命令行调用查看

    CALL getAllRowsForEmpTable();
    

    8.4、函数

    一、含义

    其实函数就是一个有返回值的过程

    二、语法

    1、创建

    DELIMITER $
    CREATE FUNCTION 函数名(参数名 参数类型) 
    RETURNS 返回类型
    BEGIN
    	函数过程体(一组合法的SQL语句)
    END $
    DELIMITER ;
    

    2、修改

    先删除,在创建
    

    3、删除

    DROP FUNCTION 函数名;
    

    4、查看

    SHOW CREATE FUNCTION 函数名;
    

    5、调用

    SELECT 函数名(实参列表);
    

    三、注意

    1. 函数体中肯定需要有return语句
    2. 存储过程和函数的区别在于函数必须有返回值,而存储过程没有

    8.5、触发器

    一、含义

    MySQL在5.0以后推出了触发器(TRIGGER),触发器是与表有关的数据库对象,指在 insert/update/delete 之前或之后,触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性、日志记录 、数据校验等操作。使用别名 OLD 和 NEW 来引用触发器中发生变化的记录内容,这与其他的数据库是相似的。现在MySQL触发器还只支持行级触发,不支持语句级触发

    二、分类

    触发器类型 NEW 和 OLD的使用
    INSERT 型触发器 NEW 表示将要或者已经新增的数据
    UPDATE 型触发器 OLD 表示修改之前的数据 , NEW 表示将要或已经修改后的数据
    DELETE 型触发器 OLD 表示将要或者已经删除的数据

    三、语法

    1、创建

    DELIMITER $
    CREATE TRIGGER 触发器名称 
    BEFORE/AFTER INSERT/UPDATE/DELETE
    ON 表名称 
    【 FOR EACH ROW--行级触发器
    BEGIN
    	触发器过程体(一组合法的SQL语句)
    END $
    DELIMITER ;
    

    2、更新

    先删除,在创建
    

    3、删除

    DROP TRIGGER 触发器名称;
    

    4、查看

    SHOW TRIGGERS;
    

    四、演示

    创建数据表以用来演示

    CREATE TABLE emp (
      id INT (11) NOT NULL AUTO_INCREMENT,
      NAME VARCHAR (50) NOT NULL COMMENT '姓名',
      age INT (11) COMMENT '年龄',
      salary INT (11) COMMENT '薪水',
      PRIMARY KEY (`id`)
    ) ENGINE = INNODB DEFAULT CHARSET = utf8 ;
    INSERT INTO emp(id,NAME,age,salary) 
    VALUES
    (NULL,'金毛狮王',55,3800),
    (NULL,'白眉鹰王',60,4000),
    (NULL,'青翼蝠王',38,2800),
    (NULL,'紫衫龙王',42,1800);
    
    CREATE TABLE emp_logs (
      id INT (11) NOT NULL AUTO_INCREMENT,
      operation VARCHAR (20) NOT NULL COMMENT '操作类型, insert/update/delete',
      operate_time DATETIME NOT NULL COMMENT '操作时间',
      operate_id INT (11) NOT NULL COMMENT '操作表的ID',
      operate_params VARCHAR (500) COMMENT '操作参数',
      PRIMARY KEY (`id`)
    ) ENGINE = INNODB DEFAULT CHARSET = utf8 ;
    

    编写触发器进行测试

    创建 insert 型触发器,完成插入数据时的日志记录:

    DELIMITER $
    CREATE TRIGGER emp_logs_insert_trigger
    AFTER INSERT 
    ON emp 
    FOR EACH ROW 
    BEGIN
      INSERT INTO emp_logs (id,operation,operate_time,operate_id,operate_params) VALUES(NULL,'insert',NOW(),new.id,CONCAT('插入后(id:',new.id,', name:',new.name,', age:',new.age,', salary:',new.salary,')'));	
    END $
    DELIMITER ;
    

    创建 update 型触发器,完成更新数据时的日志记录:

    DELIMITER $
    CREATE TRIGGER emp_logs_update_trigger
    AFTER UPDATE 
    ON emp 
    FOR EACH ROW 
    BEGIN
      INSERT INTO emp_logs (id,operation,operate_time,operate_id,operate_params) VALUES(NULL,'update',NOW(),new.id,CONCAT('修改前(id:',old.id,', name:',old.name,', age:',old.age,', salary:',old.salary,') , 修改后(id',new.id, 'name:',new.name,', age:',new.age,', salary:',new.salary,')'));                                                                      
    END $
    DELIMITER ;
    

    创建delete 行的触发器 , 完成删除数据时的日志记录:

    DELIMITER $
    CREATE TRIGGER emp_logs_delete_trigger
    AFTER DELETE 
    ON emp 
    FOR EACH ROW 
    BEGIN
      INSERT INTO emp_logs (id,operation,operate_time,operate_id,operate_params) VALUES(NULL,'delete',NOW(),old.id,CONCAT('删除前(id:',old.id,', name:',old.name,', age:',old.age,', salary:',old.salary,')'));                                                                      
    END $
    DELIMITER ;
    

    依次调用以下的语句,查看emp_logs是否有触发器保存的日志记录

    INSERT INTO emp(id,NAME,age,salary) VALUES(NULL, '光明左使',30,3500);
    
    UPDATE emp SET age = 39 WHERE id = 3;
    
    DELETE FROM emp WHERE id = 5;
    

    8.6、事件

    一、含义

    MySQL在5.1以后推出了事件调度器(Event Scheduler),与triggers的事件触发不同,event类似与linux crontab计划任务,用于时间触发

    二、特点

    1. 事件是一组SQL集合,简单说就是mysql中的定时器,时间到了就执行
    2. 事件由一个特定的线程来管理的,也就是所谓的事件调度器,但是事件不能直接调用,通过单独或调用存储过程使用,在某一特定的时间点,触发相关的SQL语句或存储过程

    三、语法

    1、创建

    MySQL事件调度器event_scheduler负责调用事件,它默认是关闭的。这个调度器不断地监视一个事件是否要调用, 要创建事件,必须打开调度器。

    #开启事件调度器(任意一个都可以)
    SET GLOBAL event_scheduler = ON; 
    SET @@global.event_scheduler = ON; 
    SET GLOBAL event_scheduler = 1; 
    SET @@global.event_scheduler = 1; 
    
    #关闭事件调度器(任意一个都可以)
    SET GLOBAL event_scheduler = OFF; 
    SET @@global.event_scheduler = OFF; 
    SET GLOBAL event_scheduler = 0; 
    SET @@global.event_scheduler = 0;
    
    DELIMITER $
    CREATE EVENT 事件名称
    ON SCHEDULE 执行时间和频率
    -- 执行时间和频率有两种形式AT和EVERY
    -- 	使用 AT     关键字只会执行一次,格式如下:
    -- 	AT CURRENT_TIMESTAMP 或者 'YYYY-MM-DD HH:MM.SS'
    -- 	使用 EVERY  关键字指定时间间隔,格式如下:
    -- 	EVERY 1 [HOUR|MONTH|WEEK|DAY|MINUTE|...]
    
    -- 可选项,使用 STARTS 关键字指定开始时间,格式如下:
    -- STARTS CURRENT_TIMESTAMP 或者 'YYYY-MM-DD HH:MM.SS'
    -- 可选项,使用 ENDS   关键字指定结束时间,格式如下:
    -- ENDS CURRENT_TIMESTAMP 或者 'YYYY-MM-DD HH:MM.SS'
    
    -- [ON COMPLETION [NOT] PRESERVE] 
    -- 可选项,设定event的生命
    --		ON COMPLETION NOT PRESERVE :即计划任务执行完毕后自动drop该事件(默认)
    --		ON COMPLETION PRESERVE     :即计划任务执行完毕后不会drop该事件
    
    -- [ENABLE | DISABLE] 
    -- 可选项,设定event的状态
    --		ENABLE	:表示系统尝试执行这个事件(默认)
    --		DISABLE	:表示系统尝试关闭这个事件
    
    -- [COMMENT 'comment'] 
    -- 可选项,设定event的备注
    DO
    BEGIN
            /* 在这里写SQL语句或者调用存储过程 */
    END$
    DELIMITER ;
    

    2、修改

    先删除,在创建
    

    3、删除

    DROP EVENT 事件名称;
    

    4、查看

    SHOW EVENTS;
    

    5、调用

    #启用事件
    ALTER EVENT 事件名称 ENABLE;
    
    #禁用事件
    ALTER EVENT 事件名称 DISABLE;
    

    四、注意

    1. 默认创建事件存储在当前库中,也可显示指定事件创建在哪个库中
    2. 通过show events只能查看当前库中创建的事件
    3. 事件执行完即释放,如立即执行事件,执行完后,事件便自动删除,多次调用事件或等待执行事件可以查看到
    4. 如果两个事件需要在同一时刻调用,mysql会确定调用他们的顺序,如果要指定顺序,需要确保一个事件至少在另一个事件1秒后执行
    5. 对于递归调度的事件,结束日期不能在开始日期之前
    6. select可以包含在一个事件中,然而他的结果消失了,就好像没执行过

    第九章 数据备份与恢复

    9.1、数据导出

    1、导出某张数据表

    #格式:mysqldump -u账户 -p密码 数据库名 数据表名 > 文件保存路径
    mysqldump -uroot -p123456 test emp > D:/emp.sql
    

    2、导出整个数据库

    #格式:mysqldump -u账户 -p密码 数据库名 > 文件保存路径
    mysqldump -uroot -p123456 test > D:/test.sql
    

    9.2、数据导入

    1、导入某张数据表

    #格式:mysql -u账户 -p密码
    #     use 数据库名;
    #     source 文件保存路径
    mysql -uroot -p123456
    >use test;
    >source D:/emp.sql
    

    2、导入整个数据库

    #格式:mysql -u账户 -p密码 < 文件保存路径
    mysql -uroot -p123456 < test.sql
    

    第十章 安装MySQL单实例

    10.1、准备虚拟机

    虚拟机配置:全新系统,桌面版

    image-20200824234229205

    虚拟机地址:进入系统,可上网

    image-20200824225209337

    连接的工具:自行百度,在下载

    SecureCRT:7.0.0

    10.2、删除自带库

    [root@caochenlei ~]# rpm -qa | grep mysql
    mysql-libs-5.1.73-8.el6_8.x86_64
    [root@caochenlei ~]# rpm -e mysql-libs-5.1.73-8.el6_8.x86_64 --nodeps
    

    10.3、安装依赖包

    [root@caochenlei ~]# yum -y install numactl perl libaio wget
    

    10.4、下载服务端

    下载:

    [root@caochenlei ~]# wget https://cdn.mysql.com//Downloads/MySQL-5.6/MySQL-server-5.6.49-1.el6.x86_64.rpm
    

    查看:

    [root@caochenlei ~]# ll MySQL-server-5.6.49-1.el6.x86_64.rpm
    -rw-r--r--. 1 root root 65467136 6月   3 13:36 MySQL-server-5.6.49-1.el6.x86_64.rpm
    

    10.5、安装服务端

    [root@caochenlei ~]# rpm -ivh MySQL-server-5.6.49-1.el6.x86_64.rpm
    

    10.6、下载客户端

    下载:

    [root@caochenlei ~]# wget https://cdn.mysql.com//Downloads/MySQL-5.6/MySQL-client-5.6.49-1.el6.x86_64.rpm
    

    查看:

    [root@caochenlei ~]# ll MySQL-client-5.6.49-1.el6.x86_64.rpm
    -rw-r--r--. 1 root root 21584380 6月   3 13:36 MySQL-client-5.6.49-1.el6.x86_64.rpm
    

    10.7、安装客户端

    [root@caochenlei ~]# rpm -ivh MySQL-client-5.6.49-1.el6.x86_64.rpm
    

    10.8、启动数据库服务

    [root@caochenlei ~]# service mysql start
    Starting MySQL.Logging to '/var/lib/mysql/caochenlei.err'.
    ..                                                         [确定]
    

    10.9、查看初始化密码

    [root@caochenlei ~]# cat /root/.mysql_secret
    # The random password set for the root user at Mon Aug 24 23:06:53 2020 (local time): E4qT_4CJ9YNf0daG
    

    10.10、修改初始化密码

    登录:

    [root@caochenlei ~]# mysql -uroot -pE4qT_4CJ9YNf0daG
    

    修改:

    mysql> set password = password('123456');
    Query OK, 0 rows affected (0.01 sec)
    

    10.11、远程的授权

    授权:

    mysql> grant all privileges on *.* to 'root'@'%' identified by '123456';
    Query OK, 0 rows affected (0.00 sec)
    

    刷新:

    mysql> flush privileges;
    Query OK, 0 rows affected (0.00 sec)
    

    退出:

    mysql> exit
    Bye
    

    10.12、开放防火墙

    [root@caochenlei ~]# /sbin/iptables -I INPUT -p tcp --dport 3306 -j ACCEPT
    [root@caochenlei ~]# /etc/rc.d/init.d/iptables save
    iptables:将防火墙规则保存到 /etc/sysconfig/iptables:     [确定]
    

    10.13、添加自启动

    [root@caochenlei ~]# chkconfig --add mysql
    [root@caochenlei ~]# chkconfig mysql on
    

    10.14、测试连接

    image-20200824232120251

    10.15、关闭系统

    [root@caochenlei ~]# poweroff
    
    Broadcast message from root@caochenlei
            (/dev/pts/1) at 23:24 ...
    
    The system is going down for power off NOW!
    

    第十一章 安装MySQL主从复制

    11.1、准备虚拟机

    复制CentOS 6 64 bit-1 > CentOS 6 64 bit-2

    image-20200824233313817

    启动CentOS 6 64 bit-1:

    image-20200824233645840

    启动CentOS 6 64 bit-2:选择“我已复制该虚拟机”

    image-20200824234110546

    11.2、主从复制介绍

    主从复制允许将来自一个MySQL数据库服务器(主服务器)的数据复制到一个或多个MySQL数据库服务器(从服务器)。

    11.3、主从复制架构

    实现目标:一主一从

    image-20200825003631169

    11.4、主节点配置

    编辑:

    注意:192.168.206.128为主节点

    [root@caochenlei ~]# vi /usr/my.cnf
    

    添加:

    注意:在[mysqld]下一行添加以下信息

    #日志名称
    log-bin=mysql-bin
    #日志格式:row、statement、mixed
    binlog-format=row
    #服务器ID标识
    server-id=1
    #刷写事务日志
    innodb_flush_log_at_trx_commit=1
    #执行写入1次同步1次
    sync_binlog=1
    #及时更新master_info
    sync_master_info=1
    

    重启:

    [root@caochenlei ~]# service mysql restart
    Shutting down MySQL...                                     [确定]
    Starting MySQL.....                                        [确定]
    

    连接:

    [root@caochenlei ~]# mysql -uroot -p123456
    

    授权:

    mysql> grant replication slave on *.* to 'root'@'%' identified by '123456';
    Query OK, 0 rows affected (0.03 sec)
    

    刷新:

    mysql> flush privileges;
    Query OK, 0 rows affected (0.01 sec)
    

    查看:

    mysql> show master status\G
    *************************** 1. row ***************************
                 File: mysql-bin.000001
             Position: 397
         Binlog_Do_DB: 
     Binlog_Ignore_DB: 
    Executed_Gtid_Set: 
    1 row in set (0.00 sec)
    

    11.5、从节点配置

    编辑:

    注意:192.168.206.129为从节点

    [root@caochenlei ~]# vi /usr/my.cnf
    

    添加:

    注意:在[mysqld]下一行添加以下信息

    #日志名称
    log-bin=mysql-bin
    #日志格式:row、statement、mixed
    binlog-format=row
    #服务器ID标识
    server-id=2
    #是否只读
    read_only=1
    

    停止:

    [root@caochenlei ~]# service mysql stop
    Shutting down MySQL..                                      [确定]
    

    删除:

    注意:这里不能直接重启mysql是因为它们的auto.cnf中的server-uuid是一样的,在进行接下来的配置的时候会失败,所以要删除从库的server-uuid,让它在启动的时候自动生成一个全新的server-uuid

    [root@caochenlei ~]# rm -f /var/lib/mysql/auto.cnf
    

    启动:

    [root@caochenlei ~]# service mysql start
    Starting MySQL...                                          [确定]
    

    连接:

    [root@caochenlei ~]# mysql -uroot -p123456
    

    执行:

    注意:MASTER_LOG_FILE=show master status的File、MASTER_LOG_POS=show master status的Position

    CHANGE MASTER TO
    MASTER_HOST='192.168.206.128',
    MASTER_PORT=3306,
    MASTER_USER='root',
    MASTER_PASSWORD='123456',
    MASTER_LOG_FILE='mysql-bin.000001',
    MASTER_LOG_POS=397;
    

    开启:

    mysql> start slave;
    Query OK, 0 rows affected (0.03 sec)
    

    查看:

    注意:重点检查Master_Log_File、Read_Master_Log_Pos是否和主节点的信息一致,Slave_IO_Running、Slave_SQL_Running是否为YES

    mysql> show slave status\G
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 192.168.206.128
                      Master_User: root
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000001
              Read_Master_Log_Pos: 397
                   Relay_Log_File: caochenlei-relay-bin.000002
                    Relay_Log_Pos: 283
            Relay_Master_Log_File: mysql-bin.000001
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
                  Replicate_Do_DB: 
              Replicate_Ignore_DB: 
               Replicate_Do_Table: 
           Replicate_Ignore_Table: 
          Replicate_Wild_Do_Table: 
      Replicate_Wild_Ignore_Table: 
                       Last_Errno: 0
                       Last_Error: 
                     Skip_Counter: 0
              Exec_Master_Log_Pos: 397
                  Relay_Log_Space: 461
                  Until_Condition: None
                   Until_Log_File: 
                    Until_Log_Pos: 0
               Master_SSL_Allowed: No
               Master_SSL_CA_File: 
               Master_SSL_CA_Path: 
                  Master_SSL_Cert: 
                Master_SSL_Cipher: 
                   Master_SSL_Key: 
            Seconds_Behind_Master: 0
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 0
                    Last_IO_Error: 
                   Last_SQL_Errno: 0
                   Last_SQL_Error: 
      Replicate_Ignore_Server_Ids: 
                 Master_Server_Id: 1
                      Master_UUID: d7200ffb-e698-11ea-87e0-000c29e99cce
                 Master_Info_File: /var/lib/mysql/master.info
                        SQL_Delay: 0
              SQL_Remaining_Delay: NULL
          Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
               Master_Retry_Count: 86400
                      Master_Bind: 
          Last_IO_Error_Timestamp: 
         Last_SQL_Error_Timestamp: 
                   Master_SSL_Crl: 
               Master_SSL_Crlpath: 
               Retrieved_Gtid_Set: 
                Executed_Gtid_Set: 
                    Auto_Position: 0
    1 row in set (0.02 sec)
    

    11.6、连接测试

    测试连接:192.168.206.128(master)

    image-20200825014102540

    创建数据库:

    CREATE DATABASE `mytest` CHARACTER SET utf8 ;
    

    创建数据表:

    CREATE TABLE `mytest`.`myuser` (
      `id` BIGINT NOT NULL AUTO_INCREMENT,
      `username` VARCHAR (20) NOT NULL,
      `password` VARCHAR (20) NOT NULL,
      PRIMARY KEY (`id`)
    ) ;
    

    添加数据集:

    INSERT INTO `mytest`.`myuser` (`id`, `username`, `password`) VALUES ('1', 'zhangsan', '123456'); 
    INSERT INTO `mytest`.`myuser` (`id`, `username`, `password`) VALUES ('2', 'lisi', '123456'); 
    INSERT INTO `mytest`.`myuser` (`id`, `username`, `password`) VALUES ('3', 'wangwu', '123456'); 
    

    查看数据集:

    use mytest;
    SELECT * FROM myuser;
    

    连接测试:192.168.206.129(slave)

    image-20200825014729798

    查看数据集:

    USE mytest; 
    SELECT * FROM myuser;
    

    最终的结论:

    我们会发现我们只在192.168.206.128(master)创建数据库、创建表、添加数据,而它的从节点会自动的拉取主节点的内容,这就是所谓的主从复制了。

    第十二章 安装MySQL读写分离

    12.1、环境准备

    复制CentOS 6 64 bit-2 > CentOS 6 64 bit-3

    注意:因为CentOS 6 64 bit-2已经是配置好的slave节点了,我们只需要做少量修改就能实现一主两从的架构了,所以我们复制CentOS 6 64 bit-2,当然,你要是时间允许,机器性能允许,您也可以重新按照主从复制的步骤在搭建一台slave,在这里我们就不搭建了,只是进行一下复制修改,复制的时候,注意关机,先关闭slave,再关闭master,再复制,再重命名,先启动master,在启动slave,在启动新复制的那台slave

    image-20200825111116521

    启动CentOS 6 64 bit-3:选择“我已复制该虚拟机”

    image-20200825142527374

    12.2、读写分离介绍

    以上已经完成了主从复制(一主一从)配置,然而这只是一个基本配置,加上一个proxysql实现MySQL读写分离,proxysql支持MySQL协议的的数据库代理,程序访问的不再是具体的数据库,而是proxysql这个代理程序,用户请求发向proxysql,如果是写请求发往主节点,读请求发下从节点组中,以此实现读写分离一定程序上减轻了主数据库的io压力。

    12.3、读写分离架构

    实现目标:一主两从,基于上文中的一主一从,我们重新复制一个从节点,进行少量修改即可

    image-20200825201051126

    12.4、修改从节点二

    注意:主节点:CentOS 6 64 bit-1【128】、从节点一:CentOS 6 64 bit-2【129】、从节点二:CentOS 6 64 bit-3【130】

    停止:

    [root@caochenlei ~]# service mysql stop
    Shutting down MySQL..                                      [确定]
    

    删除:

    [root@caochenlei ~]# rm -f /var/lib/mysql/auto.cnf
    

    修改:

    [root@caochenlei ~]# vi /usr/my.cnf
    
    #服务器ID标识
    server-id=3
    

    启动:

    [root@caochenlei ~]# service mysql start
    Starting MySQL.......                                      [确定]
    

    登录:

    [root@caochenlei ~]# mysql -uroot -p123456
    

    查看:

    USE mytest; 
    SELECT * FROM myuser;
    

    测试:

    第一步:在主节点(192.168.206.128)插入数据

    INSERT INTO `mytest`.`myuser` (`id`, `username`, `password`) VALUES ('9', 'xiaojiu', '123456');
    
    USE mytest; 
    SELECT * FROM myuser;
    

    第二步:在从节点(192.168.206.129)查看数据

    USE mytest; 
    SELECT * FROM myuser;
    

    第三步:在从节点(192.168.206.130)查看数据

    USE mytest; 
    SELECT * FROM myuser;
    

    注意:如果说从节点一或者从节点二有一个不正常工作,也就是不能主从复制,主要是它们的服务器ID标识复制的时候是一样的,开机因为已经添加了自启动,所以肯定会冲突,有一个不能够连接到主节点,只要这个时候重启一下不能正常工作的那台机器的mysql服务就行了,因为从节点二我们已经修改server-id=3了,这样它们两个从节点肯定不会冲突了,到这里,一主两从的模式就搭建好了,接下来就是配置读写分离了。

    12.5、安装proxysql

    设下载源:

    cat << EOF | tee /etc/yum.repos.d/proxysql.repo
    [proxysql_repo]
    name= ProxySQL YUM repository
    baseurl=https://repo.proxysql.com/ProxySQL/proxysql-2.0.x/centos/\$releasever
    gpgcheck=1
    gpgkey=https://repo.proxysql.com/ProxySQL/repo_pub_key
    EOF
    

    安装依赖:

    [root@caochenlei ~]# yum install -y mysql-libs perl-DBI perl-DBD-MySQL
    

    开始安装:

    [root@caochenlei ~]# yum install -y proxysql-2.0.13-1
    

    开放端口:

    [root@caochenlei ~]# /sbin/iptables -I INPUT -p tcp --dport 6032 -j ACCEPT
    [root@caochenlei ~]# /etc/rc.d/init.d/iptables save
    iptables:将防火墙规则保存到 /etc/sysconfig/iptables:[确定]
    
    [root@caochenlei ~]# /sbin/iptables -I INPUT -p tcp --dport 6033 -j ACCEPT
    [root@caochenlei ~]# /etc/rc.d/init.d/iptables save
    iptables:将防火墙规则保存到 /etc/sysconfig/iptables:[确定]
    

    添加自启动:

    [root@caochenlei ~]# chkconfig --add proxysql
    [root@caochenlei ~]# chkconfig proxysql on
    

    删除文件:

    [root@caochenlei ~]# rm -f /etc/proxysql.cnf
    

    新增文件:

    [root@caochenlei ~]# vi /etc/proxysql.cnf
    
    datadir="/var/lib/proxysql"
    errorlog="/var/lib/proxysql/proxysql.log"
    admin_variables=
    {
            #本地登录的账号和密码
            admin_credentials="admin:admin"
            #本地登录的IP和端口号
            mysql_ifaces="0.0.0.0:6032"
    }
    mysql_variables=
    {
            threads=4
            max_connections=2048
            default_query_delay=0
            default_query_timeout=36000000
            have_compress=true
            poll_timeout=2000
            #远程登录的IP和端口号
            interfaces="0.0.0.0:6033"
            default_schema="information_schema"
            stacksize=1048576
            server_version="5.5.30"
            connect_timeout_server=3000
            #监控账号的账号和密码
            monitor_username="monitor"
            monitor_password="monitor"
            monitor_history=600000
            monitor_connect_interval=60000
            monitor_ping_interval=10000
            monitor_read_only_interval=1500
            monitor_read_only_timeout=500
            ping_interval_server_msec=120000
            ping_timeout_server=500
            commands_stats=true
            sessions_sort=true
            connect_retries_on_failure=10
    }
    #以下的配置我们会采用动态语句的形式配置
    mysql_servers =
    (
    )
    mysql_users:
    (
    )
    mysql_query_rules:
    (
    )
    scheduler=
    (
    )
    mysql_replication_hostgroups=
    (
    )
    

    注意:6032是连接proxysq的管理端口,6033是对外提供服务的端口。

    启动服务:

    [root@caochenlei ~]# service proxysql start
    Starting ProxySQL: 2020-08-25 20:30:00 [INFO] Using config file /etc/proxysql.cnf
    2020-08-25 20:30:00 [INFO] Using OpenSSL version: OpenSSL 1.1.1d  10 Sep 2019
    2020-08-25 20:30:00 [INFO] No SSL keys/certificates found in datadir (/var/lib/proxysql). Generating new keys/certificates.
    DONE!
    

    12.6、删除自带库

    [root@caochenlei ~]# rpm -qa | grep mysql
    mysql-libs-5.1.73-8.el6_8.x86_64
    [root@caochenlei ~]# rpm -e mysql-libs-5.1.73-8.el6_8.x86_64 --nodeps
    

    12.7、安装依赖包

    [root@caochenlei ~]# yum -y install numactl perl libaio wget
    

    12.8、下载服务端

    下载:

    [root@caochenlei ~]# wget https://cdn.mysql.com//Downloads/MySQL-5.6/MySQL-server-5.6.49-1.el6.x86_64.rpm
    

    查看:

    [root@caochenlei ~]# ll MySQL-server-5.6.49-1.el6.x86_64.rpm
    -rw-r--r--. 1 root root 65467136 6月   3 13:36 MySQL-server-5.6.49-1.el6.x86_64.rpm
    

    12.9、安装服务端

    [root@caochenlei ~]# rpm -ivh MySQL-server-5.6.49-1.el6.x86_64.rpm
    

    12.10、下载客户端

    下载:

    [root@caochenlei ~]# wget https://cdn.mysql.com//Downloads/MySQL-5.6/MySQL-client-5.6.49-1.el6.x86_64.rpm
    

    查看:

    [root@caochenlei ~]# ll MySQL-client-5.6.49-1.el6.x86_64.rpm
    -rw-r--r--. 1 root root 21584380 6月   3 13:36 MySQL-client-5.6.49-1.el6.x86_64.rpm
    

    12.11、安装客户端

    [root@caochenlei ~]# rpm -ivh MySQL-client-5.6.49-1.el6.x86_64.rpm
    

    12.12、启动数据库服务

    [root@caochenlei ~]# service mysql start
    Starting MySQL.Logging to '/var/lib/mysql/caochenlei.err'.
    ..                                                         [确定]
    

    12.13、查看初始化密码

    [root@caochenlei ~]# cat /root/.mysql_secret
    # The random password set for the root user at Tue Aug 25 20:31:19 2020 (local time): IFIn7pcTznYpoLm1
    

    12.14、修改初始化密码

    登录:

    [root@caochenlei ~]# mysql -uroot -pIFIn7pcTznYpoLm1
    

    修改:

    mysql> set password = password('123456');
    Query OK, 0 rows affected (0.01 sec)
    

    退出:

    mysql> exit
    Bye
    

    12.15、创建两个账号

    这个操作是在master节点进行的,创建完成后,会自动复制到从节点,方便proxysql后来的监控和远程登录的认证连接

    注意:可以使用 select user,host from mysql.user; 查看所有用户

    为proxysql创建监控账号(主要做监控使用):

    create user 'monitor'@'%' identified by 'monitor';
    grant all privileges on *.* to 'monitor'@'%' identified by 'monitor';
    flush privileges;
    

    为proxysql创建远程账号(主要是远程登录):

    create user 'proxysql'@'%' identified by 'proxysql';
    grant all privileges on *.* to 'proxysql'@'%' identified by 'proxysql';
    flush privileges;
    

    退出:

    mysql> exit
    Bye
    

    12.16、配置proxysql

    这个操作是在安装proxysql的这台机器上的操作,6032端口的默认账号密码为admin,如果想要修改请在第12.5步修改,然后重启。

    [root@caochenlei ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032 --prompt 'admin>'
    

    分别执行以下语句

    # 配置主从复制的信息
    insert into mysql_servers(hostgroup_id,hostname,port,weight,max_connections,max_replication_lag,comment) values(10,'192.168.206.128',3306,1,1000,10,'write mysql');
    insert into mysql_servers(hostgroup_id,hostname,port,weight,max_connections,max_replication_lag,comment) values(20,'192.168.206.129',3306,1,10000,10,'read mysql');
    insert into mysql_servers(hostgroup_id,hostname,port,weight,max_connections,max_replication_lag,comment) values(20,'192.168.206.130',3306,1,10000,10,'read mysql');
    
    # 本地主机登录的账号:默认就是admin:admin不用再配置
    
    # 配置远程登录的账号:之前在master主节点中已经创建了
    insert into mysql_users(username,password,active,default_hostgroup,transaction_persistent) values('proxysql','proxysql',1,20,1);
    
    # 设置转发规则
    INSERT INTO mysql_query_rules(active,match_pattern,destination_hostgroup,apply) VALUES(1,'^SELECT.*FOR UPDATE$',10,1);
    INSERT INTO mysql_query_rules(active,match_pattern,destination_hostgroup,apply) VALUES(1,'^SELECT',20,1);
    
    # 立刻加载配置
    load mysql servers to runtime;
    load mysql users to runtime;
    load mysql variables to runtime;
    load mysql query rules to runtime;
    
    # 配置写到磁盘
    save mysql servers to disk;
    save mysql users to disk;
    save mysql variables to disk;
    save mysql query rules to disk;
    

    执行完成以后退出

    12.17、连接proxysql

    注意:如果远程连接不上,请把防火墙全部关掉试试,如果不行,请重新启动一下proxysql,还是不行,请重头排查一下问题,或者查看日志tail /var/lib/proxysql/proxysql.log

    第一种:远程命令行连接测试

    主节点、两个从节点随便找一台测试一下:

    ##连接
    [root@caochenlei ~]# mysql -uproxysql -pproxysql -h192.168.206.131 -P6033
    
    ##查看所有数据库
    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | mytest             |
    | performance_schema |
    | test               |
    +--------------------+
    5 rows in set (0.05 sec)
    

    第二种:远程图形化窗口连接

    注意这个端口是6033而不是3306,账号和密码我之前设置的都是proxysql

    image-20200825212223601

    12.18、查询监控数据

    如果想要查看sql语句在哪个数据库执行的,在proxysql机器上请执行以下语句

    [root@caochenlei ~]# mysql -uadmin -padmin -h127.0.0.1 -P6032 --prompt 'admin>'
    admin> select * from stats_mysql_query_digest;
    

    第十三章 安装MySQL分片集群

    13.1、环境准备

    我们使用之前的读写分离时候配置的一主两从这三台服务器,至于那个读写分离的数据库中间件proxysql服务器就用不着了,直接关机就行了,以下三台依次从主节点开始启动即可也就是CentOS 6 64 bit-1、CentOS 6 64 bit-2、CentOS 6 64 bit-3

    image-20200825111116521

    13.2、分片集群介绍

    如今随着互联网的发展,数据的量级也是撑指数的增长,从GB到TB到PB。对数据的各种操作也是愈加的困难,传统的关系性数据库已经无法满足快速查询与插入数据的需求。这个时候NoSQL的出现暂时解决了这一危机。它通过降低数据的安全性,减少对事务的支持,减少对复杂查询的支持,来获取性能上的提升。

    但是,在有些场合NoSQL一些折衷是无法满足使用场景的,就比如有些使用场景是绝对要有事务与安全指标的。这个时候NoSQL肯定是无法满足的,所以还是需要使用关系性数据库。如果使用关系型数据库解决海量存储的问题呢?此时就需要做数据库集群,为了提高查询性能将一个数据库的数据分散到不同的数据库中存储。简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。而这其中,我们需要使用一个数据库中间件来完成,它就是Mycat。

    13.3、分片集群架构

    实现目标:一主两从需要三组,再加上一个数据库中间件服务器,一共需要10台

    image-20200825220142607

    如何演示:但实际上呢,这个分片集群是在主从复制模式上进行的演进,说白了,上边的3组一主两从,随便拿出来一个都是一个主从复制模式,那我们前一章已经完成了一主两从的学习,也就是已经配置好了这三台服务器,我们要是再拷贝出来两组就显得太麻烦了,学习嘛,怎么简单怎么来,现在我们手头只有一组,那我们就在这一组上进行演示,也就是一组上创建三个数据库,我们学习的架构就是下边这样了和上边的效果一模一样,如下图:

    image-20200826093129272

    13.4、Mycat的介绍

    Mycat 背后是阿里曾经开源的知名产品——Cobar。Cobar 的核心功能和优势是 MySQL 数据库分片,此产品曾经广为流传,据说最早的发起者对 MySQL 很精通,后来从阿里跳槽了,阿里随后开源的 Cobar,并维持到 2013 年年初,然后,就没有然后了。

    Cobar 的思路和实现路径的确不错。基于 Java 开发的,实现了 MySQL 公开的二进制传输协议,巧妙地将自己伪装成一个 MySQL Server,目前市面上绝大多数 MySQL 客户端工具和应用都能兼容。比自己实现一个新的数据库协议要明智的多,因为生态环境在哪里摆着。

    Mycat 是基于 cobar 演变而来,对 cobar 的代码进行了彻底的重构,使用 NIO 重构了网络模块,并且优化了 Buffer 内核,增强了聚合,Join 等基本特性,同时兼容绝大多数数据库成为通用的数据库中间件。

    简单的说,MyCAT就是一个新颖的数据库中间件产品,支持mysql集群或者mariadb集群,提供高可用性数据分片集群。你可以像使用mysql一样使用mycat。对于开发人员来说根本感觉不到mycat的存在。

    它支持的数据库产品非常的多如:

    image-20200825215043387

    13.5、Mycat的分片

    分片就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。

    数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。

    (1)一种是按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这种切分可以称之为数据的垂直(纵向)切分

    img

    (2)另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。

    image-20200825215350981

    13.6、Mycat的安装

    官方网址:Mycat

    默认端口:8066

    JDK:要求jdk必须是1.7及以上版本

    MySQL:推荐mysql是5.5及以上版本

    安装JDK8:

    #查看软件
    rpm -qa | grep java
    rpm -qa | grep jdk
    
    #批量卸载
    rpm -qa | grep jdk | xargs rpm -e --nodeps
    rpm -qa | grep java | xargs rpm -e --nodeps
    
    #在线安装
    yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel
    
    #通过yum方式安装默认安装在/usr/lib/jvm文件下,看看你自己安装的具体是哪个版本
    ll /usr/lib/jvm/
    
    #编辑/etc/profile文件,在文件最后写入环境变量,然后保存退出
    vi /etc/profile
    
    # java environment
    export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el6_10.x86_64
    export JRE_HOME=$JAVA_HOME/jre
    export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/jre/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
    export PATH=$JAVA_HOME/bin:$PATH
    
    #使环境变量生效
    source /etc/profile
    
    #查看安装是否成功,这两个都能出来就安装成功了
    [root@caochenlei ~]# java -version
    openjdk version "1.8.0_262"
    OpenJDK Runtime Environment (build 1.8.0_262-b10)
    OpenJDK 64-Bit Server VM (build 25.262-b10, mixed mode)
    [root@caochenlei ~]# javac -version
    javac 1.8.0_262
    

    下载:

    注意:失效的话,请自行百度,然后上传到虚拟机

    [root@caochenlei ~]# wget http://dl.mycat.org.cn/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
    

    解压:

    [root@caochenlei ~]# tar -zxvf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
    

    安装:

    [root@caochenlei ~]# mv mycat /usr/local
    

    添加防火墙:

    注意:mycat数据端口默认为8066,管理端口默认为9066,我们都需要对外开放

    [root@caochenlei ~]# /sbin/iptables -I INPUT -p tcp --dport 8066 -j ACCEPT
    [root@caochenlei ~]# /sbin/iptables -I INPUT -p tcp --dport 9066 -j ACCEPT
    [root@caochenlei ~]# /etc/rc.d/init.d/iptables save
    iptables:将防火墙规则保存到 /etc/sysconfig/iptables:[确定]
    

    添加域名解析:

    [root@caochenlei ~]# vi /etc/hosts
    
    127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
    
    #配置当前主机名称的域名解析
    192.168.206.128 caochenlei
    
    #配置一主两从服务的域名解析
    192.168.206.128 master1
    192.168.206.129 slave1
    192.168.206.130 slave2
    

    常用命令:

    • /usr/local/mycat/bin/mycat start 启动
    • /usr/local/mycat/bin/mycat stop 停止
    • /usr/local/mycat/bin/mycat console 前台运行,可以显示日志,新手建议使用
    • /usr/local/mycat/bin/mycat restart 重启服务
    • /usr/local/mycat/bin/mycat pause 暂停
    • /usr/local/mycat/bin/mycat status 查看启动状态

    13.7、Mycat的配置

    第一步:登录主节点创建三个数据库分别是db1、db2、db3

    CREATE DATABASE `db1`CHARACTER SET utf8; 
    CREATE DATABASE `db2`CHARACTER SET utf8; 
    CREATE DATABASE `db3`CHARACTER SET utf8; 
    

    第二步:修改schema.xml文件

    删除原有配置

    [root@caochenlei ~]# rm -f /usr/local/mycat/conf/schema.xml
    

    新增我们配置

    [root@caochenlei ~]# vi /usr/local/mycat/conf/schema.xml
    
    <?xml version="1.0"?>
    <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
    <mycat:schema xmlns:mycat="http://io.mycat/">
    	<schema name="STOREDB" checkSQLschema="false" sqlMaxLimit="100">
    		<!-- rule采用按主键范围分片,主键名为id(默认) -->
    		<table name="TB_USERS" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
    		<!-- rule采用按哈希一致分片,主键名为order_id(自己修改) -->
    		<table name="TB_ORDER" dataNode="dn1,dn2,dn3" rule="sharding-by-murmur-order" />
    	</schema>
    
    	<dataNode name="dn1" dataHost="OneMasterAndTwoSlave" database="db1" />
    	<dataNode name="dn2" dataHost="OneMasterAndTwoSlave" database="db2" />
    	<dataNode name="dn3" dataHost="OneMasterAndTwoSlave" database="db3" />
    
    	<dataHost name="OneMasterAndTwoSlave" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
    		<!-- 心跳语句 -->
    		<heartbeat>select user()</heartbeat>
    		<!-- 一主两从 -->
    		<writeHost host="hostM1" url="master1:3306" user="root" password="123456">
    			<readHost host="hostS1" url="slave1:3306" user="root" password="123456" />
    			<readHost host="hostS2" url="slave2:3306" user="root" password="123456" />
    		</writeHost>
    	</dataHost>
    </mycat:schema>
    

    第三步:修改server.xml文件

    server.xml几乎保存了所有mycat需要的系统配置信息,最常用的是在此配置用户名、密码及权限。

    [root@caochenlei ~]# vi /usr/local/mycat/conf/server.xml
    

    在system中添加UTF-8字符集设置,否则存储中文会出现问号。

    <property name="charset">utf8</property>
    

    修改user的设置 , 我们这里为STOREDB数据库设置了两个用户。把它之前的两个用户删掉,把咱们自己设置的放进去。

    <user name="test">
    	<property name="password">test</property>
    	<property name="schemas">STOREDB</property>
    </user>
    <user name="root">
    	<property name="password">root</property>
    	<property name="schemas">STOREDB</property>
    </user>
    

    第四步:修改auto-sharding-rang-mod.txt文件

    修改主键范围分片大小

    删除:

    [root@caochenlei ~]# rm -f /usr/local/mycat/conf/auto-sharding-rang-mod.txt
    

    新增:

    [root@caochenlei ~]# vi /usr/local/mycat/conf/auto-sharding-rang-mod.txt
    
    0-500M=0
    500M1-1000M=1
    1000M1-1500M=2
    

    注意:以上意思是主键id在0-500M的数据放在分片1中,500M1-1000M的数据放到分片2中,1000M1-1500M的数据放到分片3中,超过1500M1,就报错

    第五步:修改rule.xml文件

    [root@caochenlei ~]# vi /usr/local/mycat/conf/rule.xml
    

    新增哈希订单主键,因为默认主键名都是id,要想是自己定义的,就拷贝一份,重新起个名,然后修改columns成你数据表的那个主键名称就行了

            <tableRule name="sharding-by-murmur-order">
                    <rule>
                            <columns>order_id</columns>
                            <algorithm>murmur</algorithm>
                    </rule>
            </tableRule>
    

    修改分片数量,因为现在有db1、db2、db3个分片,找到<function name="murmur"中的count,修改为3,如以下所示:

            <function name="murmur"
                    class="io.mycat.route.function.PartitionByMurmurHash">
                    <property name="seed">0</property><!-- 默认是0 -->
                    <property name="count">3</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
                    <property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
                    <!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值>也就是节点索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
                    <!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
                            用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不
    指定,就不会输出任何东西 -->
            </function>
    

    13.8、Mycat的启动

    在启动之前,我们需要做一个密码重置的工作,也不知道这是不是个BUG,但是,你要不做密码重置,很可能Mycat它启动不起来,我也是醉了,就这一个问题,搞了我一晚上的心态,操作步骤如下:

    依次在主节点、从节点一、从节点二执行以下四条语句:

    use mysql;
    update user set password = password('123456') where user = 'root';
    flush privileges;
    set password for 'root' = password('123456');
    #如果上句报错使用下边这个,不报错就算了
    set password = password('123456');
    

    然后再启动Mycat

    [root@caochenlei ~]# /usr/local/mycat/bin/mycat start
    Starting Mycat-server...
    

    13.9、Mycat的测试

    注意:在这里我使用图形化界面来操作,先测试是否连通,如果不能连上,请检查虚拟机防火墙是否关闭,那两个用户是否配对,如果Mycat重启不成功,请使用ps -ef | grep mycat查看,然后使用kill强制杀死,再然后重新启动,如果不知道什么问题,请使用前台运行,它会显示出错误信息,然后再解决

    image-20200825235336310

    创建用户表,然后插入数据,直接拷贝以下SQL代码到窗口,然后运行,必须一步一步来并且不要进行窗口操作对连接Mycat的那个连接,因为会报错

    #第一步:删表
    USE `STOREDB`;
    DROP TABLE IF EXISTS `TB_USERS`;
    
    #第二步:建表
    CREATE TABLE `TB_USERS` (
      `id` bigint(20) NOT NULL,
      `username` varchar(20) NOT NULL,
      `password` varchar(20) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    #第三步:插入数据
    insert  into `TB_USERS`(`id`,`username`,`password`) values (1,'zhangsan1','123456');
    insert  into `TB_USERS`(`id`,`username`,`password`) values (2,'zhangsan2','123456');
    insert  into `TB_USERS`(`id`,`username`,`password`) values (3,'zhangsan3','123456');
    insert  into `TB_USERS`(`id`,`username`,`password`) values (5000001,'lisi1','123456');
    insert  into `TB_USERS`(`id`,`username`,`password`) values (5000002,'lisi2','123456');
    insert  into `TB_USERS`(`id`,`username`,`password`) values (5000003,'lisi3','123456');
    insert  into `TB_USERS`(`id`,`username`,`password`) values (10000001,'wangwu1','123456');
    insert  into `TB_USERS`(`id`,`username`,`password`) values (10000002,'wangwu2','123456');
    insert  into `TB_USERS`(`id`,`username`,`password`) values (10000003,'wangwu3','123456');
    

    创建订单表,然后插入数据,直接拷贝以下SQL代码到窗口,然后运行,必须一步一步来并且不要进行窗口操作对连接Mycat的那个连接,因为会报错

    #第一步:删表
    USE `STOREDB`;
    DROP TABLE IF EXISTS `TB_ORDER`;
    
    #第二步:建表
    CREATE TABLE `TB_ORDER` (
      `order_id` varchar(30) NOT NULL,
      `create_time` datetime NOT NULL,
      `pay_time` datetime NOT NULL,
      `total_fee` bigint(20) NOT NULL,
      `user_id` varchar(50) NOT NULL,
      PRIMARY KEY (`order_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    #第三步:插入数据
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('201708261157265358046058','2017-08-26 11:57:26','2017-08-26 12:48:22',1,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('201708261221397410698125','2017-08-26 12:21:39','2017-08-26 12:48:22',1,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('201708261234474784646997','2017-08-26 12:34:47','2017-08-26 12:48:22',1,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('201708261247443132289031','2017-08-26 12:47:44','2017-08-26 12:48:22',3,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('918773291320152064534354','2017-10-13 17:39:57','2017-08-26 12:48:22',5,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('918780410236788736453543','2017-10-13 18:08:14','2017-10-13 18:09:36',1,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('918806410983137280453453','2017-10-13 19:51:33','2017-10-13 19:51:47',1,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('918833486129815552274522','2017-10-13 21:39:08','2017-08-26 12:48:22',1,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('918835712999055360745325','2017-10-13 21:47:59','2017-10-13 21:49:28',1,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('919055625042825216545334','2017-10-14 12:21:50','2017-08-26 12:48:22',1,'lijialong');
    insert  into `TB_ORDER`(`order_id`,`create_time`,`pay_time`,`total_fee`,`user_id`) values ('919059761058607104453433','2017-10-14 12:38:16','2017-10-14 12:38:24',2,'lijialong');
    

    13.10、Mycat的效果

    重开一个窗口,连接主节点,依次查看,db1、db2、db3上的TB_USERS、TB_ORDER,你会发现数据是均匀分布的,这就实现了我们最终的分片集群了,具体效果图如下:

    db1>TB_USERS

    image-20200826020118355

    db2>TB_USERS

    image-20200826020137393

    db3>TB_USERS

    image-20200826020201015

    db1>TB_ORDER

    image-20200826020226630

    db2>TB_ORDER

    image-20200826020245571

    db3>TB_ORDER

    image-20200826020257914

    13.11、Mycat的踩坑

    1. Mycat只是一个数据库中间件,它并不是一个真正的数据库,所以用窗口不能直接操作,需要使用SQL语句
    2. Mycat依赖于JDK1.7+,我建议使用JDK1.8
    3. Mycat只是帮你做了数据分片,真正的主从复制还是靠你自己实现
    4. 当你创建表的时候,Mycat默认会把表名转换为大写,所以你创建的时候就直接把表名大写和数据库名大写,否则可能会找不到表,因为大小写不对应
    5. 当你的主键字段不是id的时候,直接在ruls.xml中拷贝一份相对应类型的tableRule,然后改个规则名称和字段名称就行了,然后再引用自定义的那个
    展开全文
  • MySQL学习心得

    千次阅读 2018-02-25 16:13:48
    以下是个人看书和看Mysql技术内幕的一点学习心得,跟大家分享,有错误请指出,谢谢。 2018/08/07更新:四种连接区别 Mysql 导出数据:select * into outfile '/tmp/bump.txt'fields terminated by ','optionally ...

    以下是个人看书和看Mysql技术内幕的一点学习心得,跟大家分享,有错误请指出,谢谢。

    2018/08/07更新:四种连接区别

    Mysql 导出数据: select  * into  outfile  '/tmp/bump.txt'  fields terminated  by ','  optionally   enclosed  by ' " '             lines   terminated  by '\n'  from  linuxtest.test2 

    Mysql 导入数据: Load data infile  '/tmp/dump.txt'  into  table    linuxtest1.test fields  terminated  by  ','  optionally  enclosed by '  " ' lines   terminated  by '\n' 

    cast 数据类型转化:select cast(number as signed) from tablename  将varchar类型的number字段转换成整数

    substr 字符串截取: select sbustr(number,1,2) from tablename;从字符串第一个位置开始,截取两个字符。字符串的初始位置编码是1

    select *,row_number() over(partition by 字段) from tablename where ....;窗口函数,发现这个函数在聚合的时候比group by更加灵活

    引擎区别

    mysql主要有两大引擎,Myisam和innodb。之前默认是myisam,在5.7版本之后默认为inndb了。两者的主要区别如下

    1、Innodb 支持事务

    2、Innodb支持外键

    3、Innodb是行锁,myisam是表锁。所以innodb适用于高并发,但是高并发不是换个引擎就能解决的

     

    三大范式

    1、数据库字段单元保证最小,不能再分,例如地区:能够准确到上海即上海,而不用中国

    2、字段要与主键有相关性  

    3、字段与主键的相关性要是直接相关(非间接相关)

    Innodb引擎事务

    1、原子性:即整个事务是不可切分的;不能只执行其中某一部分

    2、一致性:事务发生前后,数据库状态变化应该是一致的

    3、隔离性:事务之间是孤立的,不会相互影响

    4、持久性:事务一旦执行完毕,数据库的变化是持久的

    日期比较可以用 select * from tablename where data> #2018-03-21# 利用#号进行日期大小比对,还可以使用内置的datediff 函数,或者year,day;或者强制转换为整数形,进行大数比较

    MySQL分区

    提高查找效率可分为LIST、RANGE等

    show variables like 'symlink';展示MYISAM 是否可以迁移;


    set password for root = password('123');更改数据库密码

    mysqladmin -u USER -p password PASSWORD

    delimiter 定义MYSQL程序终止符

    alter table table_name rename to new_tab_name、rename table old_name to new_name 数据表改名;

    alter table  tab_name disable keys   索引失效

    alter table tab_name enable keys     索引有效

    show  variables like 'have_cache_query'   缓存查询 

    procedure() 表示一个历程

    procedure analyse():语句分析,用于分析SQL运行过程,从而进行一定优化(主要是时间消耗)

    explain  查询分析,用来做相应的SQL优化

    character set utf-8  数据库编码

    truncate table tablename 删除所有数据,但表结构保留     delete  from tablename where 1=1 类似效果,表结构保留数据删除

    drop table tablename 表结构与数据一起删除

    create tigger trgginer_name 创建触发器;

    insert into table values(0)

    update table set sep=LAST_INSERT_ID(seq+1);

    select LAST_INSERT_ID()

    LAST_INSERT_ID()函数     更新整列值

    convert();数据类型转换;

    show create table 表名 查看建表信息

    cast(now() as unsigned) 数据类型转换

    collation()字符串排序;

    \g:每行显示一个结果;


    \c:取消输入,回到初始状态;

    DATE_SUB:减去指定时间间隔;

    CURDATE:返回当前日期;

    INTERVAL:返回True or False;

    NULL:能为空;

    NOT NULL:表示不能为空;

    enum:枚举类型; enum('F','M') NOT NULL;

    default-storage-engine=innodb;更改默认引擎;

    federated:引擎是通过方程数据表检索而来,数据表并不保存在本地。

    show variables like 'version,datadir,engine';查数据库信息

    Load DATA   加载文件数据

    load data local infile 'name.txt' into table member

    source  导入文件.sql语句

    IF()紧随其后的表达式进行求值,返回后面两个参数值;IF(death IS NULL,0,1)

    concat    合并字符串

    _ 只能匹配一个字符,% 匹配字符串

    @变量名:=值;MYSQL赋值方法

    count(列名) 统计一列中非NULL的值

    with rollup  汇总group by统计的数据


    Linux alias:定义指令别名;     unalias删除指令别名; character:定义编码规格;


    collation   显示数据库编码    show collation

    set names 'utf8'   编码修改


    alter table tablename engine = MyISAM  引擎修改

    convert:字符集编码转换;convert(@s1 using latin1)

    zerofull:0填充,满足字符串长度

    left join     以左表为主表,将右表数据对左表进行补充,join失败的字段填充null

    right join  以右表为主,同上

    inner join  内连接  显示两张表相关的共有信息

    full join   全连接  显示两张表所有的信息

    unsigned:无符号数;

    转载注明出处。谢谢!

    展开全文
  • MySQL高级学习

    千次阅读 2019-11-09 11:29:14
    数据库分区、分表、分库、分片;MySQL锁机制;MySQL实战问题

    一、数据库分区、分表、分库、分片

    1.1 单机数据库的瓶颈

    • 单个表数据量越大,读写锁,插入操作重新建立索引效率越低。
    • 单个库数据量太大(一个库数据量到1T - 2T就是极限)
    • 单个数据库服务器压力过大
    • 读写速度遇到瓶颈(并发量几百)

    1.2 分区

    ① 分区技术的介绍

    数据库分区是一种物理数据库的设计技术,它的目的是为了在特定的SQL操作中减少数据读写的总量以缩减响应时间。

    分区并不是生成新的数据库表,而是将表的数据均匀分摊到不同的硬盘,系统或不同服务器存储介子中,实际上还是一张表。另外,分区可以做到将表的数据分摊到不同的地方,提高数据检索的效率,降低数据库频繁IO压力值,分区的优点如下:

    1. 相对于单个文件系统或硬盘,分区可以存储更多的数据。
    2. 数据管理比较方便,如要清理或废弃某年的数据,就可以直接删除该日期的分区数据即可。
    3. 精准定位分区查询数据,不需要全表扫描查询,大大提高检索效率。
    4. 可跨多个分区磁盘查询,来提高查询的吞吐量。
    5. 在涉及聚合函数时,很容易进行数据的合并。

    ② 什么时候考虑使用分区?

    • 一张表的查询速度已经慢到影响使用的时候。
    • sql经过优化
    • 数据量大
    • 表中的数据是分段的
    • 对数据的操作往往只涉及一部分数据,而不是所有的数据

    ③ 水平分区

    这种形式分区是对表的行进行分区,通过这种的方式不同分组里面的物理列分割的数据集得以组合,从而进行个体分体或集体分割。所有在表中定义的列在每个数据集中都能找到,所以表的特性得以保持。

    举例:一个包含十年发票记录的表可以被分区为10个不同的分区,每个分区包含的是其中一年的记录。

    ④ 垂直分区

    这种分区方式一般来说是通过对表的垂直划分来减少目标表的宽度,使某些特定的列被划分到特定的分区,每个分区都包含了其中的列所对应的行。

    举例:一个包含了大textblob列的表,这些textblod列又不经常被访问,这时候就要把这些不经常使用的textblob了划分到另一个分区,在保证它们数据关联性的同时还能提高访问速度。

    ⑤ 分区实现的方式

    mysql5开始支持分区功能

    创建表:

    create table sales(
    	id int auto increment,
    	amount double not null,
    	order_day datetime not null,
    	primary key(id,order_day)
    ) engine=Innodb
    

    设置分区:

    partition by range(year(order_day))(
    	partition p_2010 values less than (2000),
    	partition p_2011 values less than (2011),
    	partition p_2012 values less than (2012),
    	partition p_2012 values less than maxvalue
    );
    

    1.3 分表

    ① 什么时候考虑分表?

    • 一张表的查询速度已经慢到影响使用的时候
    • sql经过优化
    • 数据量大
    • 当频繁插入或者联合查询时,速度变慢

    ② 分表解决的问题

    分表后,单表的并发能力提高了,磁盘的IO性能也提供了,写操作效率也提高了。

    • 查询一次的时间短了
    • 数据分布在不同的文件,磁盘I/O性能提高
    • 读写锁影响的数据量变小
    • 插入数据库需要重新建立索引的数据减少

    ③ 分表实现方式

    要业务系统配合迁移升级,工作量较大。常用分区分表的规则策略:

    • Range(范围)
    • Hash(哈希)
    • 按照时间拆分
    • Hash之后按照分表个数取模
    • 在认证库中保存数据库配置,就是建立一个DB,这个DB单独保存user_idDB的映射关系

    1.4 分库

    ① 什么时候考虑分库?

    • 单台DB的存储空间不够
    • 随着查询量的增加单台数据库服务器已经没办法支撑

    ② 分库解决的问题

    其主要目的是为突破单节点数据库服务器的I/O 能力限制,解决数据库扩展性问题。

    ③ 分库实现的方式

    垂直拆分

    把系统中不存在关联关系或者需要join的表可以放在不同的数据库不同的服务器中。 按照业务垂直拆分。比如:可以按照业务分为资金、会员、订单三个数据库。

    需要解决的问题:跨数据库的事务、join查询等问题。

    水平拆分

    例如,大部分的站点。数据都是和用户有关,那么可以根据用户,将数据按照用户水平拆分。

    按照规则拆分,一般水平库是在垂直分库之后的。比如每天处理的订单数量是海量的,可以按照一定的规则水平划分。

    需要解决的问题:数据路由、组装。

    读写分离

    对于时效性不高的数据,可以通过读写分离缓解数据库压力。

    需要解决的问题:在业务上区分哪些业务是允许一定时间延迟的,以及数据同步问题。

    1.5 分区、分表、分库的对比

    分区 就是把一张表的数据分成N个区块,在逻辑上看最终只是一个表,但底层是由N个物理区块组成的。
    分表 就是把一张表按一定的规则分解成N个具有独立存储空间的实体表。系统读写时需要根据定义好的规则得到对应的字表名,然后操作它。
    分库 一旦分表,一个数据库中的表会越来越多

    优先级:垂直分库–>水平分库–>读写分离

    1.6 拆分后面临的新问题

    • 事务的支持,分库分表,就变成了分布式事务
    • join时跨库,跨表的问题
    • 分库分表,读写分离使用了分布式,分布式为了保证强一致性,必然带来延迟,导致性能降低,系统的负责度降低。

    解决方案:

    ​ 对于不同的方式之间没有严格的界限,特点不同,侧重点不同。需要根据实际情况,结合每种方式的特点来进行处理。选用第三方的数据库中间件(AtlasMycatTDDLDRDS),同时业务系统需要配合数据存储的升级。

    总结:优先考虑分区。当分区不能满足需求时,开始考虑分表,合理的分表对效率的提升会优于分区。

    1.7 京东评论案例

    现状

    • 商品的评论数量:数十亿条
    • 每天的服务调用:数十亿次
    • 每年成倍增长

    整体的数据存储:基础数据存储,文本存储

    京东评论

    基础数据存储

    MySQL:只存储非文本的基础信息。包括:评论状态,用户,时间等基础数据。以及图片,标签,点赞等附加信息。数据组织形式(不同的数据又可选择不同的库表拆分方案):

    • 评论基础数据按用户ID进行拆库并拆表
    • 图片及标签处于同一数据库下,根据商品编号分别进行拆表
    • 其它的扩展信息数据,因数据量不大、访问量不高,处理于同一库下且不做分表即可

    文本存储

    文本存储(评论的内容)使用了mongodbhbase

    • 选择nosql而非mysql。
    • 减轻了mysql存储压力,释放msyql,庞大的存储也有了可靠的保障。
    • nosql的高性能读写大大提升了系统的吞吐量并降低了延迟。

    1.8 数据分片

    ​ 在分布式存储系统中,数据需要分散在多台设备上,数据分片(Sharding)就是用来确定数据在多台存储设备上分布的技术,数据分片要达到三个目的:

    1. 分布均匀,即每台设备上的数据量要尽可能相近
    2. 负载均衡,即每台设备上的请求量要尽可能相近
    3. 扩缩容时产生的数据迁移尽可能少

    数据分片方法

    • 划分号段

    • 取模

    • 检索表

    • 一致性哈希算法(Consistent Hashing是在1997年由MIT提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网的热点(Hot Spot)问题。一致性哈希的算法简单而巧妙,很容易做到数据均分布,其单调性也保证了扩缩容的数据迁移是比较少的。

    虚拟服务器

    为了让系统有更好的扩展性,这里提出存储层VServer(虚拟服务器)的概念,一个VServer是一个逻辑上的存储服务器,是分布式存储系统的一个存储单元,一台物理设备上可以部署多个VServer,一个VServer支持一个写进程和多个读进程。

    物理设备

    通过VServer的方式,会有下面一些好处:

    1. 提高单机性能。为了不引入复杂的锁机制,采用了单写进程的设计,如果单机只有一个写进程,写并发能力会受到限制,通过VServer方式把单机上的存储资源(内存、硬盘)划分为多个存储单元,这样就支持多个写进程同时工作,大大提升单机写并发能力。
    2. 部署扩展性更好。VServer的方式在部署上非常灵活,可以根据单机的资源情况来确定VServer的数量,针对不同的机型配置不同的VServer数量,这样不同的机型都能充分利用机器上的资源,即使在一个系统中使用多种机型,也能做到机器的负载比较均衡。

    二、MySQL锁机制

    2.1 锁的分类

    • 从对数据操作的类型(读/写)分

      • 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响。
      • 写锁(排它锁):当前写操作没有完成前,它会阻断其他写锁和读锁。
    • 对数据操作的粒度分

    为了尽可能数据库的并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很耗资源的事情(涉及获取,检查,释放锁等操作),因此数据库系统需要在高并发响应和系统性能两方面进行平衡,这样就产生了“锁粒度(Lock granularity)”的概率。

    一种提高共享资源并发性的方式是让锁定对象更有选择性。尽量只锁定需要修改的部分数据,而不是所有的资源。更理想的方式是,只对会修改的数据片进行精确的锁定。任何时候,在给定的资源上,锁定的数据量越少,则系统的并发度越高,只要相互之间不发生冲突即可。

    • 表锁
    • 行锁

    2.2 表锁

    特点:偏向MyISAM存储引擎,开销小,加锁快;无死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

    案例1【加读锁】:

    [session1]
    -------
    lock table user read;
    -------
    	这里只能执行查询当前表,不能查询其他表,插入或更新当前表都会提示错误
    -------
    unlock tables;
    
    [session2]
    -------
    在session1锁定表后,session2能查询或更新未锁定的表,能查询锁定表,插入或者更新锁定表会一直等待锁被释放。
    

    案例1【加写锁】:

    [session1]
    -------
    lock tables user write;
    -------
    	这里可以对锁定表做查询、更新、插入操作
    -------
    unlock tables;
    
    [session2]
    -------
    在session1锁定表后,查询、更新、插入操作均需要等到锁被释放。
    

    结论:

    1. MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会堵塞同一表的写请求。只要当读锁释放后,才会执行其他进程的写操作。
    2. MyISAM表的写操作(加写锁),会阻塞其他进程的对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。

    查看哪些表被加锁show open tables;

    分析表锁定:show status like 'table%';

    在这里插入图片描述
    Table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数,每立即获取锁值加1 ;
    Table_locks_waited:出现表级锁定争用而发生等待的次数(不能立即获取锁的次数,每等待一次锁值加1),此值高则说明存在着较严重的表级锁争用情况;

    Myisam的读写锁调度是读优先,这也是myisam不适合做写为主表的引擎。因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞

    2.3 行锁

    特点:

    1. 偏向InnoDB存储引擎,开销大,加锁慢;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
    2. InnoDBMyISAM的最大不同有两点:一是支持事务;二是采用了行级锁。

    案例【加行锁】

    [session1]
    -------
    set autocommit=0;
    -------
    	这里可以对锁定表做更新操作
    -------
    commit;
    
    [session2]
    -------
    在session2锁定表后不commit时,这里对锁定表进行update操作,会等待锁释放。
    

    无索引行锁升级为表锁

    当某个索引列没有正常使用,如赋错误的类型的值,会导致行锁变表锁。

    间隙锁危害

    间隙锁:当我们用范围条件而不是相等条件检索数据,并请求共享或拍他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”进行加锁,这种锁机制就是所谓的间隙锁(Next-Key)。

    危害:当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据,在某些场景下这可能会对性能造成很大的危害。

    【面试题】 如何锁定一行

    select * from user for update;

    结论:

    Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的的性能损耗可能比表级锁定会要更高一些,但是整体并发处理能力方面要远远优于MyISAM的表级锁定。当系统并发量较高的时候,InnoDB的整体性能和MyISAM相比就有比较明显的优势了。

    但是Innodb的行级锁定同样也有脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现不仅不能比MyISAM高,甚至可能会更差。

    分析行锁定:

    通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况

    命令:mysql> show status like 'innodb_row_lock%';
    在这里插入图片描述
    Innodb_row_lock_current_waits:当前正在等待锁定的数量;
    Innodb_row_lock_time:从系统启动到现在锁定总时间长度;
    Innodb_row_lock_time_avg:每次等待所花平均时间;
    Innodb_row_lock_time_max:从系统启动到现在等待最常的一次所花的时间;
    Innodb_row_lock_waits:系统启动后到现在总共等待的次数;

    优化建议

    • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。
    • 合理设计索引,尽量缩小锁的范围
    • 尽可能较少检索条件,避免间隙锁
    • 尽量控制事务大小,减少锁定资源量和时间长度
    • 尽可能低级别事务隔离

    2.4 页锁

    开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

    三、MySQL实战问题

    3.1 重复数据问题

    /*
    编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。
    示例:
      +----+---------+
      | Id | Email   |
      +----+---------+
      | 1  | a@b.com |
      | 2  | c@d.com |
      | 3  | a@b.com |
      +----+---------+
    根据以上输入,你的查询应返回以下结果:
      +---------+
      | Email   |
      +---------+
      | a@b.com |
      +---------+
     */
    select p1.Email from person p1 where p1.Email in (select p2.Email from person p2 where p1.Id!=p2.Id);
    
    
    []SELECT email FROM `person` group by email HAVING count(email)>1;
    
    [拓展]删除重复数据
    [思路]根据重复数据进行分组,然后查出最小的id,删除其他之外的id行,这里得创建一个临时表,
    在mysql中,不能在一条Sql语句中,即查询这些数据,同时修改这些数据
    DELETE from person  where id not in( select temp.id from (SELECT min(id) id FROM person group by email)as temp);
    注意:这里在mysql5.7以上版本会报错,因为不支持select那些group by和聚合函数之外的字段
    

    3.2 索引创建和查看

    创建:create index idx_a_b on table(col_a,col_b);

    查看:show index from table;

    3.3 where 1=1和where 1=0的意义

    where 1=1用于拼接多条件语句时,这样就不用管条件是否存在,拼where还是拼and

    where1=0不返回数据,仅返回结构,用于快熟建表。

    展开全文
  • 如何学习mysql

    千次阅读 2019-03-26 17:30:21
    由于之前没有对mysql 详细的了解(基础不牢固),只会简单的使用,往往遇到一些问题不知道怎么解决, 所以今天踏上了mysql学习之路,和你们谈谈我是怎么学习它的。 以下内容是我个人对于mysql的学习路线和笔记 如有...
    由于之前没有对mysql 详细的了解(基础不牢固),只会简单的使用,往往遇到一些问题不知道怎么解决,
    所以今天踏上了mysql学习之路,和你们谈谈我是怎么学习它的。
    以下内容是我个人对于mysql的学习路线和笔记  如有错误之处, 还请大神及时纠正。
    

    要想了解任何一个东西 首先我们要对它有个基本认识
    1.它是干嘛的
    2.它怎么操作的
    3,它的原理,以及怎样运行
    带着以上的问题我们开始接触mysql。

    1.  MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件。
    
    2.  MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
    
    3.  MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。
    
    4 . MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择。
    
    5.  MySQL 作为网站数据库。由于其社区版的性能卓越,搭配 PHP 和 Apache 可组成良好的开发环境。
    

    所有平台的 MySQL 下载地址为:MySQL 下载 。 挑选你需要的 MySQL Community Server 版本及对应的平台。
    在这里我就不介绍了 比如安装呀配置呀 连接等。

    同过网上资料的一些了解(百度百科等),针对于我学习mysql制定了下面的学习路线:

    在这里插入图片描述
    你们也可以根据自己情况来制定思维导图学习mysql,
    这样可以提高学习效率又可以做笔记,有些东西忘记了还可以翻出来复习
    养成一个好习惯从我做起
    详细过程在下一篇哟

    展开全文
  • MySQL语句学习

    千次阅读 2020-04-21 00:30:28
    MySQL学习 在学习数据库命令之前首先了解一下MySQL,首先MySQL是DBMS(数据库管理系统),DBMS是位于用户与操作系统之间的一层数据管理软件。DB(数据库)是指:长期储存在计算机内的、有组织的、可共享的大量数据...
  • MySQL数据库学习

    万次阅读 多人点赞 2018-08-13 20:41:03
    虽然笔者从事的是Android客户端的开发,平时和数据库打的交道并不多,但是我们对于数据库这一块的学习还是很重要的,今天笔者想总结下MySQL关系型数据库的一些常用知识点 数据库概述 一、常见的概念 数据库...
  • 年轻人为什么要学习MySQL数据库

    千次阅读 2018-11-12 17:55:59
    知道我什么时候接触MySQL的数据库么?那还是上个世纪,1998年,当时我在广州一家公司,开始接手一个人才网站,我把整站从asp+access的架构,调整为PHP+MyS...
  • MySQL 学习资源整理

    万次阅读 多人点赞 2017-01-23 16:16:38
    MySQL也有了几年了,说不出来个所以然,认知比较肤浅。所以需要加深学习呀,这里是学习过程中收集的一些好的资源,希望大家共同进步了。不是很系统的整理,看到了就记录了下来。 博客前辈们的博客就是他们成长的足迹...
  • 程序员的MySQL学习宝典

    千人学习 2021-04-09 10:33:09
    什么说每一个程序员都应该学习MySQL? 根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。 使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库...
  • 推荐几本学习MySQL的好书

    万次阅读 2016-10-31 01:15:21
    推荐几本学习MySQL的好书
  • mysql学习经验&学习资料下载

    千次阅读 2018-09-12 01:49:48
    先给出我的核心观点:学习,无论你是学什么,也无论你有没有基础。思考永远是第一位的,有些知识你没接触过不要紧,用不着害怕,也没必要害怕。重要的是一秒钟也不要停止思考,问题要想透彻,正所谓磨刀不误砍柴工。...
  • 文章目录内容简介Mysql 概述Mysql 特点MySQL服务的安装配置MySQL客户机连接MySQL服务器 内容简介 通过本文学习可以掌握一些常用的MySQL命令,从而对MySQL数据库进行一些简单的管理。 Mysql 概述 MySQL由瑞典MySQL ...
  • MySQL什么推荐的学习书籍?

    万次阅读 2017-12-15 15:54:15
    1.MySQL的使用 1.1 MySQL技术内幕:InnoDB存储引擎 学习MySQL的使用,首推姜承尧的《MySQL技术内幕:InnoDB存储引擎》,当然不是因为姜sir是我的经理才推荐这本书。这本书确实做到了由渐入深、深入浅出,是中国...
  • MySql数据库学习(一)

    千次阅读 多人点赞 2019-10-23 16:31:00
    MySql数据库学习(一) mySQL (关系型数据库管理系统) MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL...
  • mysql学习入门

    千次阅读 2013-11-13 18:24:29
    最近要使用数据库,mysql开源所以决定使用它。   学习书籍:mysql必知必会 1、mysql下载 http://dev.mysql.com/downloads/   在这个下载界面会有几个版本的选择。 1. MySQL Community Server 社区版本,开源免费,...
  • 将数据库进行到底原理为什么要主从服务器主从知识扩展Mysql主从服务搭建(1)建立时间同步环境(2)编译安装MySQL数据库(3)登录Master主服务器配置 20.0.0.21(4)登录salve 从服务器配置(5)验证 原理 为什么要...
  • “老袁啊,你先跟我说下什么是mysql,还有为什么你建议我学完python以后,先学mysql呢?”一进门,晓白就迫不及待的问。 “行,那我今天就先给你讲讲什么是mysql,为什么要先学习mysql。然后讲下数据库的安装...
  • Mysql学习书籍推荐

    千次阅读 2019-12-06 10:44:40
    学习了MySQl一段时间之后,发现了一些比较好的书籍,在这里推荐给还在学习或者刚开始学习的你,可以根据自己的需求选择合适自己的资料来学习。 入门级: 《MySQL必知必会》,比较老,适合入门。 《MySQL 8 ...
  • MySQL学习总结

    千次阅读 2015-09-12 14:11:34
    MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQLAB公司,在2008年1月16号被Sun公司收购。MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,...
  • MySQL学习6:MySQL基本数据类型

    千次阅读 2016-05-07 20:47:21
    MySQL中常用的的数据类型包括:数值类型、日期和时间类型和字符串类型等。  一数值类型  MySQL支持所有标准SQL中的数值类型,其中包括严格数据类型(INTEGER、SMALLINT、DECIMAL、 NUMBERIC),以及近似数值数据...
  • 小白学MySQL,这点基础你都不知道?

    千次阅读 2020-06-02 11:00:51
    这里介绍的MySQL相关知识,并不是针对那些想学习DBA的同学,而是针对那些想转行、从事数据分析行业的同学。下面这些知识点,是我学习MySQL数据库时,觉得有必要掌握的一些知识点。
  • MySQL - 学习/实践

    千次阅读 2019-11-21 12:49:36
    学习, 实践MySQL. 2.学习/操作 1.官方手册 //推荐, 解决问题以及验证结论 最终还是回到官方手册. https://dev.mysql.com/doc/refman/5.5/en/data-size.html //5.5手册 ...
  • 【转】推荐几本学习MySQL的好书-MySQL 深入的书籍

    万次阅读 多人点赞 2018-01-21 18:36:43
    )[-]MySQL的使用1 MySQL技术内幕InnoDB存储引擎2 MySQL的官方手册3 MySQL排错指南4 高性能MySQL5 数据库索引设计与优化6 Effective MySQL系列MySQL的源码21 InnoDB - A journey to the core2 深入MySQL源码3 深入...
  • 文章目录内容简介MySQL数据类型数值类型(整数类型)数值类型(小数类型)字符串类型日期类型复合类型(包括enum类型和set类型)二进制类型选择合适的数据类型创建表 内容简介 本章详细讲解《三国志》数据库各个表的...
  • 但是要以学习为目的,你会发现很多东西我们得深入到计算机基础上才能发现其中奥秘,很多人问我怎么记住这么多东西,其实学习本身就是一个很无奈的东西,既然我们不那为啥不好好?去学会享受呢?最近我也在恶...
  • MySQL的结构化查询语言数据库设计《三国志》的开发人员都了哪些事情?《三国志》武将团队系统概述《三国志》定义问题域是什么?数据库的编码规范E-R图《三国志》数据的实体与属性《三国志》各类数据间的关系ER图的...
  • Mysql学习(全)

    千次阅读 多人点赞 2020-05-27 10:11:57
    1.安装Mysql 1.1 关于密码的一些事 登录mysqlmysql -uroot -p 回车,输入密码 修改密码的常见方法: set password命令: 登录mysql set password for 用户名@localhost = password(‘新密码’); 例如:...
  • 大多数人去MySQL官网下载,不知道要下载哪一个文件,比如有MySQL Enterprise Edition和 MySQL Community Edition. 社区版里又有很多组件,比如MySQL Community Server、MySQL Workbench、MySQL Co
  • 学习MySQL官方文档(一)

    千次阅读 2019-10-22 17:16:30
    前提:看这篇文档之前我已经装了一台虚拟机,并在虚拟机上装好了mysql服务,还装了Navicat并连接上虚拟机的mysql服务 1、连接到服务器和从服务器断开连接 shell> mysql -h host -u user -p Enter password: *****...
  • MySQL 到底放到 Docker 里跑?同程旅游目前已经有超过一千个 MySQL 实例安全稳定地跑在 Docker 平台上。前 * 言前几月经常看到有 MySQL 到底放到 Docker 里跑的各种讨论。这样是错的!这样是对的!...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 240,583
精华内容 96,233
关键字:

学mysql能从事什么工作

mysql 订阅