MySQL笔记


一、前期准备

  1. SQL语句分类
    • DQL - 数据查询语言 --> 查询语句,select 语句都是DQL

    • DML - 数据操作语言 --> insert、delete、update 等等对表数据进行增删改

    • DDL - 数据定义语言 --> create、 drop、 alter 等等对表结构的增删改

    • TCL - 事务控制语言 --> Transaction Commit - 提交事务 Rollback - 回滚事务

    • DCL - 数据控制语言 --> grant - 授权 revoke - 撤销权限

  2. MySQL卸载
    • 去安装目录找到my.ini文件
    • 复制文件中配置的路径:【 datadir="C:/ProgramData/MySQL/MySQL Server 5.5/Data/" 】
    • 控制面板卸载MySQL
    • 去第二步里复制的路径中删除 C:/ProgramData下的MySQL文件夹
  3. 常见的cmd命令
    • 打开服务窗口 services.msc
    • 打开/关闭MySQL服务 net start/shut mysql
    • 登录MySQL mysql -uroot -p密码
    • 访问别人的MySQL mysql -h别人IP -uroot -p别人密码
    • 退出MySQL exit/quit

二、DDL -- 对数据库、表的操作

  1. 操作数据库
    • C(Create):创建
      • create database 数据库名;
      • create database if not exists 数据库名; -- 判断不存在再创建
      • create database 数据库名 character set 字符集名; -- 创建库并指定字符集
      • 练习: create database if not exists db0 character set utf8;
    • R(Retrieve):查询
      • show databases; -- 查询所有的数据库名
      • show create database 数据库名; -- 查看创建库的语句
    • U(Update):修改
      • alterdatabase 数据库名 character set 字符集名;
    • D(Delete):删除
      • drop database 数据库名;
      • drop database if exists 数据库名; -- 先判断是否存在
    • 使用数据库
      • 查询当前正使用的数据库
        • selsect database();
      • 使用数据库
        • use 数据库名;
  2. 操作表
    • C(Create):创建
      • 语法:create table 表名(列名1 类型1,

        列名2 类型2,

        列名3 类型3);

      • 数据库数据类型

        • int -- 整数类型
          • age int
        • double -- 小数类型
          • score double(3, 1); -- 最多三位,一位小数
        • date -- 日期 只包含年月日 yyyy- MM-dd
        • datetime -- 时间戳类型 包含年月日时分秒 yyyy- MM-dd HH:mm:ss
        • timestamp -- 包含年月日时分秒 yyyy- MM-dd HH:mm:ss
          • 如果不给这个字段赋值或赋值为null,则默认值为系统当前时间
        • varchar -- 字符串
          • name varchar(20);
          • 张三 8个字符 zhangsan 两个字符
      • 复制表 -- create table 表名 like 源表名

      • 练习:

        create table t_student(
        id int,
        name varchar(30),
        age int,
        score double(4,1),
        birthday date,
         insert_time timestamp);
    • R(Retrieve):查询
    • show tables; -- 查询当前数据库的所有表

  • desc 表名; -- 查询表结构

    • U(Update):修改
      • 修改表名
        • alter table 表名 rename to 新表名
      • 修改表字符集
        • alter table 表名 character set 字符集名;
      • 添加一列
        • alter table 表名 add 列名 类型;
      • 修改列名称、类型
        • alter table 表名 change 列名 新列名 新类型;
        • alter table 表名 modify 列名 新类型;
    • 删除列

  • alter table 表名 drop 列名;

  • D(Delete):删除
    • drop table if exists 表名;

三、DML -- 增删改表中数据

  1. 添加数据
    • 语法:
      • insert into 表名(列名1, 列名2, 列名3...) values(数据1, 数据2, 数据3...);
    • 注意!!
        1. 前后括号的 列名和值(类型)要一一对应
        2. 如果表名后不定义列名,则默认给所有列添加值 (也要对应上所有坑,不然报错)
          • insert into stu values(2, 'Jones', 18, 90.7, null,null);
        3. 除了数值类型,其他的类型都需要是哟个引号括起来【单双引号都可】
  2. 删除数据
    • 语法:
      • delete from 表名 [where 条件 ];
    • 注意!!
      • 如果不写条件则会删除表中所有记录
      • 如果要删除所有记录,有两种方式:
        • delete from 表名; -- 有多少条记录都会一条一条删除掉
        • truncate table 表名; -- 先删除整张表【包括其数据】,然后创建一张一模一样的空表,效率高
  3. 修改数据
    • 语法:
      • update 表名 set 列名1 = 值1, 列名2 = 值2...[where 条件]
    • 注意!!
      • 如果不加任何条件,则会将表中所有记录全部修改

四、DQL -- 查询语句

  1. 查询表中记录
    1. 语法:
      select       
          字段列表
      from         
          表名列表
      where       
          条件列表
      group by  
          分组字段
      having      
          分组之后补充的条件
      order by   
          排序
      limit     
           分页查询
    2. 基础查询

      • 多个字段的查询
        • select name, age from stu;
        • 有null参与的任何运算结果为null 如下:
          • 3c82RS.png
          • 解决方案:在可能出现问题的计算的地方添加ifnull(表达式1, 表达式2)即可
            • 表达式1 -- 哪个字段需要判断是否为null
            • 表达式2 -- 如果该字段值为null,替换为表达式2值
          • SELECT s.name, s.math, s.english, (ifnull(s.math, 0) + ifnull(s.english, 0)) totalScore FROM stu s ;
      • 去除重复
        • select distinct address from stu; -- 地址重复去除
      • 起别名
        • SELECT s.name AS 姓名,(IFNULL(s.math, 0) + IFNULL(s.english, 0)) AS 总分 FROM stu s ; -- as 看省略
          • 3c84qs.png
    3. 条件查询
      1. where子句后跟条件

      2. 运算符

        • <、>、<=、>=、=、<>

          • 查询年龄大于20岁的

            select * from stu where age > 20;

        • beteen...and

          # 查询年龄位于20-30岁的
          SELECT * FROM stu WHERE age <= 30 && age >= 20;
          SELECT * FROM stu WHERE age BETWEEN 20 AND 30;  #推荐写法
        • like

          • 模糊查询

          • 占位符

            • __ 表示单个任意字符
            • % 表示多个任意字符
          • 举例:

            # 查询姓马的记录
            SELECT s.name, s.math, s.english FROM stu s WHERE s.name LIKE '马%';    #第一个字是“马”,其余任意多字无所谓
            # 查询姓名中第二个字是'化'的人
            select * from stu where name like '_化%';  # 第一个任意
            # 查询姓名有三个字的人
            SELECT * FROM stu WHERE NAME LIKE '___';  # 三个下划线
            # 查询姓名中包含“马”和“德”的人
            SELECT * FROM stu WHERE NAME LIKE "%德%" OR "%马%";
          • is null

            #查询英语成绩为null的列 与不为null的列
            SELECT s.name FROM stu s WHERE s.english IS NULL;
            SELECT s.name FROM stu s WHERE s.english IS NOT NULL;
          • and 或者 &&

          • or 或者 ||

            # 查询年龄为19 22 25 的
            SELECT * FROM stu WHERE age = 19 or age = 22 or age = 25;
            select * from stu where age in(18, 22, 25);  #推荐写法
          • not 或者 !

    4. 排序查询
      1. 语法:order by 子句

        • order by 排序字段1 排序方式1, 排序字段2 排序方式2...
      2. 排序方式:

        • asc:升序【默认】
        • desc :降序
      3. 注意!!如果有多个排序条件,则当前边的条件值一样时,才会执行第二判断条件

      4. 练习:

        -- 按照数学成绩排名,如果数学一样,则按照英语成绩排名
        SELECT * FROM stu ORDER BY math ASC, english ASC;  -- 先按照前面的升序,如果前面的一样则再按照后面的升序
    5. 聚合函数 -- 将一列数据作为一个整体,进行纵向的计算
      1. count -- 计算个数

        • 一般选择主键
      2. max -- 计算最大值

      3. min -- 计算最小值

      4. sum -- 计算和

      5. avg -- 计算平均数

         -- 看下英语成绩平均值
         SELECT AVG(IFNULL(english, 0)) FROM stu;
      6. 注意!!聚合函数计算,是排除null值的

        • 解决方案一:选择不包含null的列进行计算
        • 解决方案二:使用ifnull函数 SELECT COUNT(IFNULL(english, 0)) FROM stu;
    6. 分组查询 -- 统计某一类具有相同特征的数据,把他们看做一个整体
      1. 语法:group by分组字段

        -- 按照性别分组,看下男女同学的平均分
         SELECT sex 性别, AVG(IFNULL(math, 0)) 数序平均分, AVG(IFNULL(english, 0)) 英语平均分 FROM stu GROUP BY sex;
         -- 按照性别分组,看下男女同学的平均分 分数低于70的同学不参与分组
         SELECT sex, AVG(IFNULL(math, 0)), AVG(IFNULL(english, 0)), COUNT(id) FROM stu WHERE IFNULL(math, 0) > 70 GROUP BY sex;
        
         -- 按照性别分组,看下男女同学的平均分 分数低于70的同学不参与分组,
         -- 且分组后组内个数下雨2的不要了
         SELECT sex, AVG(IFNULL(math, 0)), AVG(IFNULL(english, 0)), COUNT(id) FROM stu WHERE IFNULL(math, 0) > 70 GROUP BY sex HAVING COUNT(id) > 2;
      2. 注意!

        • 分组之后查询的字段只能是分组字段或者聚合函数了,不能有与个人有关的字段
        • wherehaving的区别
          • where在分组之前【order by】进行限定,而having在分组之后进行限定
          • where后不可以跟聚合函数,而having可以
    7. 分页查询
      1. 语法:limit index, n index -- 开始的索引; n -- 每页查询的条数

      2. 公式:【当前页开始索引 = (当前页数 - 1) * 每页记录条数

         -- 每页显示三条,第一页
         SELECT * FROM stu LIMIT 0, 3;
         -- 第二页
         SELECT * FROM stu LIMIT 3, 3;
         -- 第三页
         SELECT * FROM stu LIMIT 6, 3;
         -- 每页开始索引    (当前页数 - 1) * 每页显示条数 = 每页开始索引
      3. 分页操作是一个方言 【在MySQL中分页是limit,其他数据库有各自额关键字】

  2. 约束
    1. 概念:对表中数据进行限定,保证数据的正确性、有效性与完整性

    2. 约束分类:

      • 主键约束:primary key
      • 非空约束:not null
      • 唯一约束:unique
      • 外键约束:foreign key
    3. 主键 -- 该字段值非空且唯一

      • 注意!!

          1. 一张表只能有一个字段为主键
          2. 主键就是表中记录的唯一标识
      • 创建表时添加主键

        -- 创建一个新表,id是主键
        create table stu1(
            id int primary key,
            name varchar(30) not null -- name字段非空
        );
      • 删除主键

        alter table stu1 drop primary key;  -- 一个表只有一个主键
      • 创建表之后添加主键

        -- 给 id 字段添加约束主键
        alter table stu1 modify id int primary key;
        • 添加前删除所有重复字段
    4. 非空 -- 值不能为null

      • 创建表时添加非空约束

        -- 创建一个新表,name字段非空
        create table stu1(
            id int,
            name varchar(30) not null -- name非空
        );
      • 创建表后添加非空约束

        alter table stu1 modify name varchar(30);
      • 删除已经创建的表的非空约束

        -- 给name字段添加约束非空
        alter table stu1 modify name varchar(30) not null;
    5. 唯一 -- 值不能重复

      • 创建表时添加

        -- 创建一个新表,phoneName唯一
        CREATE TABLE stu1(
            id INT,
            phoneName VARCHAR(20) UNIQUE -- phoneName唯一
        );
      • 创建表之后添加

        -- 给 phoneName 字段添加约束唯一
        alter table stu1 modify phoneName varchar(20) unique;
      • 删除表字段的的唯一约束

        alter table stu1 drop index phoneName;  -- 删除表phoneName字段唯一约束
      • 注意!!

        • MySQL中unique限定的值可以有多个null
        • 删除唯一约束的语法特殊
        • 给已经创建的表的某个字段添加唯一约束时,需要删除掉该字段所有的重复的值
    6. 自动增长

      • 概念:如果某一字段是数值类型,使用auto_increment可以实现其自增【一般配合主键id一起使用】

      • 创建表时添加自增约束

        -- 创建一个新表,id是主键,且自增
        create table stu1(
            id int primary key auto_increment,
            name varchar(30) not null -- name字段非空
        );
        • 注意!!自增的数据只跟上一条记录有关,如id自增到6,插入数据时,指定了id为20 则下一次自增从21开始
      • 删除自增约束

        -- 删除自增约束
        alter table stu1 modify id int; --  id的主键约束不会被删除掉
      • 添加自增约束

        -- 给 id 字段添加约束自增
        alter table stu1 modify id int auto_increment;
    7. 外键 -- 添加外键前,外键表删除数据不会做检查【比如小李还在A部门,删除A部门不会做检查】

      1. 在创建表时。可以添加外键

        create table 表名(
            ...
            外键列,
            constraint 外键名 foreign key (外键列名) references 主表名(主表列名)
        );
      2. 删除外键

        -- 删除外键
        alter table 本表名 drop foreign key 外键名称;
      3. 创建表之后,添加外键

        alter table 本表名 add constraint 外键名 foreign key (要关联的本表列名) references 外键表名(要关联的外键表列名);
        
        --  如下
        alter table emp add constraint emp_edp_fk foreign key (dep_id) references dep(id);
      4. 添加外键,并设置级联更新[ -- 【更改/删除部门的id时,在员工表里自动更改了对应员工的部门号】用的时候谨慎

        -- 添加外键,并设置级联更新与级联删除
        ALTER TABLE emp ADD CONSTRAINT emp_edp_fk FOREIGN KEY
         (dep_id) REFERENCES dep(id) ON UPDATE CASCADE ON DELETE CASCADE;

五、数据库的设计

  1. 多表之间的关系
    1. 分类

      • 一对一(了解)
        • 如:人与身份证
        • 一个人只能有一个身份证,一个身份证只能对应一个人
      • 一对多(多对一)
        • 如:部门与员工
        • 一个部门可以有多个员工,一个员工只能对应一个部门
      • 多对多
        • 如:学生与课程
        • 一个学生可以选择多个课程,一个课程也可以被很多学生选择
    2. 如何实现
      • 一对多(多对一)

        • 如:部门与员工

        • MySQL实现:

          在多的一方【员工表】建立外键,指向一的一方【部门表】的主键

          总结 一对多两张表,多的一方加外键

      • 多对多

        • 如:学生与课程

        • MySQL实现:

          多对多关系实现需要借助第三张表,此第三话张表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键【选课表】

          总结 *多对多,三张表、关系表俩外键 *

      • 一对一【了解】

        • 一对一关系实现,在任意一方添加唯一外键指向另一方主键【直接放一张表吧。。。。】
  2. 范式
    1. 概念:设计数据库时,遵循不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小

    2. 分类:(目前关系型数据库有六种范式)

      • 第一范式(1NF): 任何一张表应该有主键,且每一个字段原子性不可再分

        • 如下图的系列还分两列,且存在问题【比如删除了张无忌会一起删除了高等数学课程】
        • 3c8qRU.png
      • 第二范式(2NF): 建立在1NF之上 另外要求所有非主键字段完全依赖主键,不能产生部分依赖 【消除非主字段对主键的部分函数依赖】

        • 几个概念

          • 函数依赖:A --> B ,如果通过A列的值可以唯一确定列B的值,则称B依赖于A
            • 如 学号 --> 姓名 姓名依赖于学号
            • (学号,课程) --> 分数 则分数依赖于属性组
          • 完全函数依赖: A --> B 如果A是一个属性组,则B值的确认依赖于A中每一个属性
            • 如:(学号,课程) -- > 分数 分数的确定单由一个学号无法确定,单由课程也无法确定,一个确定的学号+一个确定的课程确定唯一一个分数
          • 部分函数依赖: A --> B 如果A是一个属性组,则B值的确认依只需要依赖于A中某一部分属性
            • 如:(学号,系名) --> 姓名。我们发现前面属性组里,通过一个学号可以确定一个姓名,不需要系名,用这个属性组局多余
          • 传递依赖:A --> B, B -- > C,如果通过A属性(组)可以唯一确定B属性的值,再通过B属性(组)的值可以唯一确定C属性(组)的值,则C传递依赖于A
        • 如:

          • 图:3cRHxg.png

          • 学号与课程名可以作为主码【由(学号, 课程)可以唯一确定一个其他的唯一的值】,而系名与系主任可由学号直接确定,产生了部分依赖

          • 解决方案:拆分出选课表【学号、课程、分数】作为主码,与学生表【还存在传递依赖问题】

            3cWOSO.md.png

      • 第三范式(3NF): 建立在2NF基础上,所有外键字段直接依赖主键,不可产生传递依赖

        • 如:
          • 图:3cfbHs.png
          • 系名依赖于学号,系主任依赖于系名 则系主任传递依赖于学号 解决:拆分表,把系名与系主任另开为系表
  3. 数据库的备份与还原
    1. 命令行形式

      • 备份:mysqldump -u用户名 -p密码 要备份的数据库 > 保存的路径

        mysqldump -uroot -padmin db1 > D:\JavaSETestDirectory01\MySQLBackup\db1.sql

      • 还原:

          1. 登录数据库

          2. 创建数据库【还原的数据装在此数据库】

            create database backupdb;

          3. 使用数据库【进入这个数据库,把数据还原进来】

            use backupdb;

          4. 执行文件。source 文件路径

            source D:\JavaSETestDirectory01\MySQLBackup\ddd.sql

    2. 图形化工具


六、多表查询

  1. 查询语法:

    select    列名列表
    from    表名列表
    where
    ...
    • 笛卡尔积:两个集合,其所有情况为两个集合列的乘积
    • 消除笛卡尔积:下面三种方式
  2. 多表查询分类:

    1. 内连接:

      1. 隐式内连接:使用where条件消除无用数据
      -- 当员工的部门id与部门的id相等时才返回结果
      SELECT 
          e.name,        -- 员工表姓名
          e.gender,   -- 员工表性别
          d.name        -- 部门表名
      FROM
          emp e, dep d
      WHERE
          e.dep_id = d.id;
      1. 显示内连接:显示地指定连接方式
      • 语法:
      select 字段列表 from 表1 inner join 表2 on 条件
      -- 显示连接  查询所有的员工信息与对应的部门信息
      SELECT  * FROM emp e INNER JOIN dep d ON e.dep_id = d.id;      -- inner可省略
      • 可以看出内连接,查询的是两张表的交集
      1. 内连接注意事项:
        1. 从哪些表中查询数据
        2. 条件是什么
        3. 查询哪些字段
    2. 外连接

      1. 左外连接

        • 语法:
        select 字段列表 from 表1 left outer join 表2 on 条件    -- outer可省略
        -- 查询所有的员工信息,如果员工有部门,则查询部门名称。没有则不显示部门名
        SELECT * FROM emp e LEFT OUTER JOIN dep d ON e.`dep_id` = d.`id`;
        • 可以看出--左外连接是查询的左边的表另外与右边表的交集
      2. 右外连接

        • 语法:
        select 字段列表 from 表1 right outer join 表2 on 条件    -- outer可省略
        • 右外连接查询的就是右边的表及其交集
    3. 子查询

      1. 概念:查询中嵌套查询,称嵌套查询为子查询

      2. 案例: -- 查询工资最高的员工信息

        -- 查询工资最高的员工信息,分两步
        select max(salary) maxSalary from emp ;  -- 先查询最高工资是多少
        select * from emp where salary = 9000;   -- 带着最高工资查询信息
        -- 查询工资最高的员工信息,使用子查询
        SELECT * FROM emp WHERE salary = (SELECT MAX(salary) FROM emp);
      3. 子查询不同情况

        • 子查询是单行单列的

          • 子查询可以作为条件,使用运算符取判断,运算符【>, <, >=, <=, =】

            -- 查询工资小于平均工资的员工信息
            SELECT * from emp where salary < (SELECT avg(salary) e from emp);
        • 子查询是多行单列的

          • 子查询作为条件,使用运算符in作为判断

            -- 查询在开发部或者市场部工作的员工
            SELECT * FROM emp WHERE dep_id IN (( SELECT id FROM dep WHERE NAME = "开发部" ), ( SELECT id FROM dep WHERE NAME = "市场部" ));

            image-20200302190004915

        • 子查询是多行多列的

          • 子查询可以作为一张临时表参与查询

            -- 查询员工入职日期是 2011-11-11 日之后的员工信息和部门信息
            
            -- 使用普通的内连接
            SELECT * from emp e, dep d where e.dep_id = d.id and e.join_date > "2011-11-11";
            -- 使用子查询  多行多列
            SELECT * from (select * from emp where emp.join_date > "2011-11-11") t, dep d  where t.dep_id = d.id;
  3. 多表查询练习:

    1. 查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述

    2. 查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置

    3. 查询员工姓名,工资,工资等级

    4. 查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级

    5. 查询出部门编号、部门名称、部门位置、部门人数

    6. 查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询


    7. 答案:

      -- 1.  查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
      select e.id 员工编号, e.ename 员工姓名, e.salary 工资, j.jname 职务名称, j.de 职务描述 from emp e, job j where e.job_id = j.id;
      
      -- 2.  查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
      select e.id, e.ename, e.salary, j.jname, j.de, d.dname, d.loc from emp e, dep d, job j where e.dep_id = d.id and e.job_id = j.id;
      
      -- 3.  查询员工姓名,工资,工资等级
      SELECT e.ename, e.salary, s.grade from emp e, salarygrade s where e.salary between s.losalary and s.hissalary;
      
      -- 4.  查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
      select e.ename, e.salary, j.jname, j.de, d.dname, d.loc, s.grade from emp e, dep d, job j, salarygrade s where e.dep_id = d.id and e.job_id = j.id and e.salary BETWEEN s.losalary and s.hissalary;
      
      -- 5.  查询出部门编号、部门名称、部门位置、部门人数
              /*
                  分析:
          ·                1. 使用分组查询,对 emp.dep_id  字段进行分组,查询部门的id与其对应数量 COUNT(emp.id) 作为临时表 t
                          2. 把 1 中的表拿出来 子查询与 dep 表连接查询部门信息
      
                          条件:当临时表的id与部门表id相同时
      */
      SELECT
          dep.id 部门编号,
          dep.dname 部门,
          dep.loc 部门位置,
          t.tcount 部门人数
      FROM
          dep,
          (
              SELECT
                  emp.dep_id tid,
                  COUNT(id) tcount
              FROM
                  emp
              GROUP BY
                  dep_id
          ) t
      WHERE
          t.tid = dep.id
      
      -- 6.  查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询
      select t1.t1ename 员工姓名, emp.ename 上级领导 from (select ename t1ename,mgr t1mgr from emp) t1 LEFT OUTER JOIN emp on emp.id = t1.t1mgr; 
          -- 更简单的,起别名把员工表看做另一张领导表
      SELECT 
              e.ename,
              e.mgr,
              m.id,
              m.ename
      FROM
              emp e LEFT OUTER JOIN emp m 
      on
              e.mgr = m.id;

七、事务

  1. 事务介绍
    1. 概念一个包含多个步骤的业务操作,被事务管理,那么这些事务要么同时成功,要么同时失败【开启事务后中间某一步出现问题就回滚到所有步骤之前,没有任何异常则提交事务】

    2. 操作

      1. 开启事务:start transaction
      2. 回滚:rollback
      3. 提交:commit 【如果手动开启了事务但没有手动提交,事务会回滚】
    3. MySQL中数据库事务默认自动提交

      • 一条DML(增删改)语句会自动提交一次事务

      • 事务提交的两种方式:

        • 自动提交 -- MySQL是自动提交的【Oracle数据库时默认手动提交的(需要写commit)】
        • 手动提交 -- 需要手动start开启事务,然后手动commit提交
      • 修改事务的提交方式

        • 查看事务默认提交方式:select @@autocommit; -- 1为自动提交 0 为手动提交

          image-20200303135300042.png

        • 修改默认提交方式:SET @@autocommit = 0

  2. 事务的四大特征
    1. 原子性:事务是不可分割的最小操作单位,要么同时成功,要么同时失败
    2. 持久性:事务提交或回滚后,数据会持久化保存【关机,重启应用都已经保存】
    3. 隔离性:多个事务之间相互独立【期望互不影响】
    4. 一致性:事务操作前后,事务的总量不变【转钱前A100,B100。转钱后A20,B180】
  3. 事务的隔离级别(了解)
    1. 概念:多个事务之间是隔离的、独立的。但是如果多个事务曹组同一批数据,则会引发一些问题,设置不同的隔离级别可以解决这些问题

    2. 存在的问题:

      • 脏读:一个事务,读取到另一个事务汇总没有提交的数据
      • (虚 读)不可重复读:在同一个事务中,两次读取到的数据不一样
      • 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改
    3. 隔离级别:

      • read uncommitted:读未提交

        • 产生的问题:脏读、不可重复读、幻读
          • 左边事务更改信息还未提交或者回滚,右边读取到更新的信息【比如AB开启事务,A给B转账500,但未提交,B可以看到自己的账户多了500,但是A此时回滚可以把这500不转过去】
      • read committed :读已提交【Oracle默认】

        • 产生的问题:不可重复读、幻读
          • 左边事务提交更新信息,右边事务在提交之前可以看到更新的信息,而不是保持不变
      • repeatable read:可重复读【MySQL默认】

        • 产生的问题:幻读【左边事务提交更新的信息,但右边事务未提交之前,右边事务读到的数据是不会改变的(实际上已经改变了)。只有在右边事务提交之后才会看到更新的数据信息】
      • serializable:串行化

        • 可以解决所有的问题
        • 一个锁表的操作,一个事务在开启并操作【增删改查】时,其他任何事物不得操作【比如查询时会卡住不动】,只有当前操作事务提交/回滚,别的事务才能操作【效率低】

        注意!!隔离级别从小到大安全性愈高,但是效率愈低

    4. MySQL查询隔离级别

      • 查询:select @@tx_isolation
      • 修改:set global transaction isolation level 级别字符串 【级别字符串是上述的read uncommitted等】

八、DCL -- 控制权限与管理用户

  1. DBA :数据库管理员 -- 管理用户,授权

  2. 管理用户

    1. 添加用户:

      1. -- 创建用户【使用DCL语句】
        -- create user "用户名"@"主机名" IDENTIFIED by "密码";
        create user "aaa"@"localhost" IDENTIFIED by "123";  -- 这样就可以使用  mysql -uaaa -p123访问这个数据库
    2. 删除用户:

      1. -- 删除用户
        -- drop user "用户名"@"主机名":
        drop user "aaa"@"localhost";
    3. 修改用户密码:

      1. -- 可行的
        -- set password for "用户名"@"主机名" = password("新密码");
        set password for "aaa"@"localhost" = password("345");
      2. -- 修改用户的密码
        -- update user set PASSWORD = PASSWORD("新密码") where user = "用户名";
        update user set PASSWORD = PASSWORD("123") where user = "aaa";  #### 实测不行 =.=
      3. 如果忘记了自己的登录密码... =.=

        1. 停止MySQL服务 cmd --> net stop mysql 需要管理员权限

        2. 使用无验证启动MySQL服务:mysqld --skip-grant- tables

        3. 再新打开一个cmd窗口 输入mysql 回车登录

        4. 使用 mysql 表,改密码

          use mysql;
          set password for "root"@"localhost" = password("新密码");
          -- 或者下面这条命令
          update user set password = password('新密码') where user = 'root';
        5. 关闭两个窗口

        6. 打开任务管理器,手动结束mysqld.exe进程

        7. 启动mysql服务。使用新密码登录

    4. 查询用户:

      1. 切换到mysql数据库,用户表是mysql下的user

        use mysql;
        show tables;
        SELECT * from user;        -- 可以发现有两个用户,上面这个是本机登录,第二个是%通配符 任意的【远程登录】 

        image-20200303164817539有两个用户记录,上面的是本地主机,下面的是 % 通配符,表示可以在任意主机使用用户登录数据库

  3. 权限管理(权限授予、添加)

    1. 查询权限

      1. -- 查询权限   普通创建的用户只有登录的权限
        -- show grants for '用户名'@'主机名';
        SHOW GRANTS FOR 'aaa'@'localhost';
    2. 授予权限

      1. -- 授予权限  给谁授予哪个数据库的哪个表什么权限
        -- grant 权限列表 on 数据库名.表名 to '用户名'@'主机名';
        GRANT SELECT, UPDATE, DELETE ON db3.emp TO 'aaa'@'localhost';
      2. 授予全部权限

        -- 授予所有权限,在所有数据库的所有的表上【谨慎使用】
        GRANT SELECT, UPDATE, DELETE ON db3.emp TO 'aaa'@'localhost';
  1. 撤销权限

    1. -- 撤销权限  从谁撤销哪个数据库的哪个表什么权限
      -- revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';
      revoke select on db3.emp from 'aaa'@'localhost'; 
    2. 撤销所有权限

      revoke  all on *.* from 'aaa'@'localhost';