MySQL多表查詢與事務

學習目標

  1. 能夠使用內連接進行多表查詢
  2. 能夠使用左外連接和右外連接進行多表查詢
  3. 能夠使用子查詢進行多表查詢
  4. 能夠理解多表查詢的規律
  5. 能夠理解事務的概念
  6. 能夠說出事務的原理
  7. 能夠在MySQL中使用事務
  8. 能夠理解髒讀,不可重複讀,幻讀的概念及解決辦法

第1章 多表查詢

1.1 什麼是多表查詢

同時查詢多張表獲取到需要的數據
比如:我們想查詢到開發部有多少人,需要將部門表和員工表同時進行查詢
在這裏插入圖片描述

多表查詢的分類
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yoz81IHA-1582193672229)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A202.png)]

準備數據:

-- 創建部門表
CREATE TABLE dept (
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20)
);

INSERT INTO dept (NAME) VALUES ('開發部'),('市場部'),('財務部');

-- 創建員工表
CREATE TABLE emp (
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(10),
  gender CHAR(1),   -- 性別
  salary DOUBLE,   -- 工資
  join_date DATE,  -- 入職日期
  dept_id INT
);

INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孫悟空','男',7200,'2013-02-24',1);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('豬八戒','男',3600,'2010-12-02',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('唐僧','男',9000,'2008-08-08',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女',5000,'2015-10-07',3);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女',4500,'2011-03-14',1);

1.2 笛卡爾積現象

1.2.1 什麼是笛卡爾積現象

多表查詢時左表的每條數據和右表的每條數據組合,這種效果成爲笛卡爾積

需求:查詢每個部門有哪些人

具體操作:

SELECT * FROM dept, emp;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6RM1mmMm-1582193672230)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A203.png)]

以上數據其實是左表的每條數據和右表的每條數據組合。左表有3條,右表有5條,最終組合後3*5=15條數據。

左表的每條數據和右表的每條數據組合,這種效果稱爲笛卡爾乘積
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kSxUkYTV-1582193672230)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A204.png)]

1.2.2 如何清除笛卡爾積現象的影響

我們發現不是所有的數據組合都是有用的,只有員工表.dept_id = 部門表.id 的數據纔是有用的。所以需要通過條件過濾掉沒用的數據。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4hic9Zob-1582193672231)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A205.png)]

SELECT * FROM dept, emp WHERE emp.`dept_id`=dept.`id`; 

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Y6m9Bho3-1582193672231)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A206.png)]

1.3 內連接

用左邊表的記錄去匹配右邊表的記錄,如果符合條件的則顯示

1.3.1 隱式內連接

隱式內連接:看不到JOIN關鍵字,條件使用WHERE指定
SELECT 字段名 FROM 左表, 右表 WHERE 條件;

1.3.2 顯示內連接

顯示內連接:使用INNER JOIN ... ON語句, 可以省略INNER
SELECT 字段名 FROM 左表 INNER JOIN 右表 ON 條件;

具體操作:

  • 查詢唐僧的信息,顯示員工id,姓名,性別,工資和所在的部門名稱,我們發現需要聯合2張表同時才能查詢出需要的數據,我們使用內連接

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yhsxVO0N-1582193672231)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A215.png)]

  1. 確定查詢哪些表
SELECT * FROM dept INNER JOIN emp;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-z018Pz8z-1582193672231)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A207.png)]

  1. 確定表連接條件,員工表.dept_id = 部門表.id 的數據纔是有效的
SELECT * FROM dept INNER JOIN emp ON emp.`dept_id`=dept.`id`;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BUN35u5h-1582193672232)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A208.png)]

  1. 確定表連接條件,我們查詢的是唐僧的信息,部門表.name=‘唐僧’
SELECT * FROM dept INNER JOIN emp ON emp.`dept_id`=dept.`id` AND emp.`NAME`='唐僧';

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KGF6mpfW-1582193672232)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A209.png)]

  1. 確定查詢字段,查詢唐僧的信息,顯示員工id,姓名,性別,工資和所在的部門名稱
SELECT emp.`id`, emp.`NAME`, emp.`gender`, emp.`salary`, dept.`NAME` FROM dept INNER JOIN emp ON emp.`dept_id`=dept.`id` AND emp.`NAME`='唐僧';

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IrOpAC6q-1582193672232)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A210.png)]

  1. 我們發現寫表名有點長,可以給表取別名,顯示的字段名也使用別名
SELECT e.`id` 員工編號, e.`NAME` 員工姓名, e.`gender` 性別, e.`salary` 工資, d.`NAME` 部門名稱 FROM dept d INNER JOIN emp e ON e.`dept_id`=d.`id` AND e.`NAME`='唐僧';

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mVfTzdhu-1582193672233)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A211.png)]

總結內連接查詢步驟:

  1. 確定查詢哪些表
  2. 確定表連接條件
  3. 確定查詢字段

1.4 左外連接

左外連接:使用LEFT OUTER JOIN ... ONOUTER可以省略
SELECT 字段名 FROM 左表 LEFT OUTER JOIN 右表 ON 條件;
用左邊表的記錄去匹配右邊表的記錄,如果符合條件的則顯示;否則,顯示NULL
可以理解爲:在內連接的基礎上保證左表的數據全部顯示

具體操作:

  • 在部門表中增加一個銷售部
INSERT INTO dept (NAME) VALUES ('銷售部');

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VGc9Bvk0-1582193672233)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A212.png)]

  • 使用內連接查詢
SELECT * FROM dept INNER JOIN emp ON emp.`dept_id`=dept.`id`;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xh9CIs1O-1582193672233)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A213.png)]

  • 使用左外連接查詢
SELECT * FROM dept LEFT OUTER JOIN emp ON emp.`dept_id`=dept.`id`;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8juI6jme-1582193672233)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A214.png)]

1.5 右外連接

右外連接:使用RIGHT OUTER JOIN ... ONOUTER可以省略
SELECT 字段名 FROM 左表 RIGHT OUTER JOIN 右表 ON 條件;
用右邊表的記錄去匹配左邊表的記錄,如果符合條件的則顯示;否則,顯示NULL
可以理解爲:在內連接的基礎上保證右表的數據全部顯示

具體操作:

  • 在員工表中增加一個員工
  INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('沙僧','男',6666,'2013-02-24',NULL);

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NOm3W26G-1582193672234)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A217.png)]

  • 使用內連接查詢
 SELECT * FROM dept INNER JOIN emp ON emp.`dept_id`=dept.`id`;

在這裏插入圖片描述

  • 使用右外連接查詢
  SELECT * FROM dept RIGHT OUTER JOIN emp ON emp.`dept_id`=dept.`id`;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DC6Iau3z-1582193672234)(imgs/%E8%A1%A8%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A216.png)]

1.6 子查詢

一條SELECT語句結果作爲另一條SELECT語法一部分(查詢條件,查詢結果,表)
SELECT 查詢字段 FROM 表 WHERE 查詢條件;
SELECT * FROM employee WHERE salary=(SELECT MAX(salary) FROM employee);
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IRVjnMLw-1582193672234)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A201.png)]
子查詢需要放在()中

子查詢結果的三種情況:

  1. 子查詢的結果是一個值的時候
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-PMcJU59G-1582193672234)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A202.png)]
  2. 子查詢結果是單例多行的時候
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-f1MHyqYo-1582193672235)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A203.png)]
  3. 子查詢的結果是多行多列
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YjNgn244-1582193672235)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A204.png)]

說明:
子查詢結果只要是單列,肯定在WHERE後面作爲條件
子查詢結果只要是多列,肯定在FROM後面作爲

1.6.1 子查詢的結果是一個值的時候

子查詢結果只要是單列,肯定在WHERE後面作爲條件
SELECT 查詢字段 FROM 表 WHERE 字段=(子查詢);

  1. 查詢工資最高的員工是誰?

    1. 查詢最高工資是多少
      SELECT MAX(salary) FROM emp;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ODFYReQe-1582193672235)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A205.png)]

    1. 根據最高工資到員工表查詢到對應的員工信息
      SELECT * FROM emp WHERE salary=(SELECT MAX(salary) FROM emp);
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xnUYZSL8-1582193672235)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A206.png)]

  2. 查詢工資小於平均工資的員工有哪些?

    1. 查詢平均工資是多少
      SELECT AVG(salary) FROM emp;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tZG7PU60-1582193672235)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A207.png)]

    1. 到員工表查詢小於平均的員工信息
      SELECT * FROM emp WHERE salary < (SELECT AVG(salary) FROM emp);
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NGspJfO3-1582193672236)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A208.png)]

1.6.2 子查詢結果是單例多行的時候

子查詢結果只要是單列,肯定在WHERE後面作爲條件
子查詢結果是單例多行,結果集類似於一個數組,父查詢使用IN運算符
SELECT 查詢字段 FROM 表 WHERE 字段 IN (子查詢);

  1. 查詢工資大於5000的員工,來自於哪些部門的名字

    1. 先查詢大於5000的員工所在的部門id
      SELECT dept_id FROM emp WHERE salary > 5000;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BcFv0C7O-1582193672236)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A209.png)]

    1. 再查詢在這些部門id中部門的名字
      SELECT dept.name FROM dept WHERE dept.id IN (SELECT dept_id FROM emp WHERE salary > 5000);
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rJcOYOte-1582193672236)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A210.png)]

  2. 查詢開發部與財務部所有的員工信息

    1. 先查詢開發部與財務部的id
    SELECT id FROM dept WHERE NAME IN('開發部','財務部');
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JCX9kVoM-1582193672236)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A211.png)]

    1. 再查詢在這些部門id中有哪些員工
    SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE NAME IN('開發部','財務部'));
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Y7pnk7b4-1582193672236)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A212.png)]

1.6.3 子查詢的結果是多行多列

子查詢結果只要是多列,肯定在FROM後面作爲
SELECT 查詢字段 FROM (子查詢) 表別名 WHERE 條件;
子查詢作爲表需要取別名,否則這張表沒用名稱無法訪問表中的字段

  • 查詢出2011年以後入職的員工信息,包括部門名稱

    1. 在員工表中查詢2011-1-1以後入職的員工
    SELECT * FROM emp WHERE join_date > '2011-1-1';
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-0JUXKMBr-1582193672237)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A214.png)]

    1. 查詢所有的部門信息,與上面的虛擬表中的信息組合,找出所有部門id等於的dept_id
    SELECT * FROM dept d, (SELECT * FROM emp WHERE join_date > '2011-1-1') e WHERE e.dept_id = d.id;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ImkDe9S6-1582193672237)(imgs/%E5%AD%90%E6%9F%A5%E8%AF%A213.png)]

使用表連接:

SELECT d.*, e.* FROM dept d INNER JOIN emp e ON d.id = e.dept_id WHERE e.join_date > '2011-1-1';

1.6.4 多表查詢總結

  • 子查詢結果只要是單列,肯定在WHERE後面作爲條件
    SELECT 查詢字段 FROM 表 WHERE 字段=(子查詢);
  • 子查詢結果只要是多列,肯定在FROM後面作爲
    SELECT 查詢字段 FROM (子查詢) 表別名 WHERE 條件;

第2章 多表查詢案例

我們在公司開發中,根據不同的業務需求往往需要通過2張及以上的表中去查詢需要的數據。所以我們有必要學習2張及以上的表的查詢。其實不管是幾張表的查詢,都是有規律可循的。

2.1 準備數據

-- 部門表
CREATE TABLE dept (
  id INT PRIMARY KEY PRIMARY KEY, -- 部門id
  dname VARCHAR(50), -- 部門名稱
  loc VARCHAR(50) -- 部門位置
);

-- 添加4個部門
INSERT INTO dept(id,dname,loc) VALUES 
(10,'教研部','北京'),
(20,'學工部','上海'),
(30,'銷售部','廣州'),
(40,'財務部','深圳');

-- 職務表,職務名稱,職務描述
CREATE TABLE job (
  id INT PRIMARY KEY,
  jname VARCHAR(20),
  description VARCHAR(50)
);

-- 添加4個職務
INSERT INTO job (id, jname, description) VALUES
(1, '董事長', '管理整個公司,接單'),
(2, '經理', '管理部門員工'),
(3, '銷售員', '向客人推銷產品'),
(4, '文員', '使用辦公軟件');

-- 員工表
CREATE TABLE emp (
  id INT PRIMARY KEY, -- 員工id
  ename VARCHAR(50), -- 員工姓名
  job_id INT, -- 職務id
  mgr INT , -- 上級領導
  joindate DATE, -- 入職日期
  salary DECIMAL(7,2), -- 工資
  bonus DECIMAL(7,2), -- 獎金
  dept_id INT, -- 所在部門編號
  CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id),
  CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id)
);

-- 添加員工
INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES 
(1001,'孫悟空',4,1004,'2000-12-17','8000.00',NULL,20),
(1002,'盧俊義',3,1006,'2001-02-20','16000.00','3000.00',30),
(1003,'林沖',3,1006,'2001-02-22','12500.00','5000.00',30),
(1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20),
(1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30),
(1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30),
(1007,'劉備',2,1009,'2001-09-01','24500.00',NULL,10),
(1008,'豬八戒',4,1004,'2007-04-19','30000.00',NULL,20),
(1009,'羅貫中',1,NULL,'2001-11-17','50000.00',NULL,10),
(1010,'吳用',3,1006,'2001-09-08','15000.00','0.00',30),
(1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20),
(1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30),
(1013,'小白龍',4,1004,'2001-12-03','30000.00',NULL,20),
(1014,'關羽',4,1007,'2002-01-23','13000.00',NULL,10);

-- 工資等級表
CREATE TABLE salarygrade (
  grade INT PRIMARY KEY,
  losalary INT,
  hisalary INT
);

-- 添加5個工資等級
INSERT INTO salarygrade(grade,losalary,hisalary) VALUES 
(1,7000,12000),
(2,12010,14000),
(3,14010,20000),
(4,20010,30000),
(5,30010,99990);

分析4張表的關係:通過4張表可以查出一個員工的所有信息
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-cnznWCpV-1582193672237)(imgs\多表查詢01.png)]

2.2 練習

2.2.1 練習1

查詢所有員工信息。顯示員工編號,員工姓名,工資,職務名稱,職務描述

具體操作:
1.確定要查詢哪些表:emp e, job j

SELECT * FROM emp e INNER JOIN job j;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fhG7u7IR-1582193672238)(imgs\多表查詢02.png)]

2.確定表連接條件: e.job_id=j.id

SELECT * FROM emp e INNER JOIN job j ON e.job_id=j.id;

在這裏插入圖片描述

3.確定查詢字段:員工編號,員工姓名,工資,職務名稱,職務描述

SELECT e.`id`, e.`ename`, e.`salary`, j.`jname`, j.`description` FROM emp e INNER JOIN job j ON e.job_id=j.id;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WxhDi3Dd-1582193672239)(imgs\多表查詢05.png)]

2.2.2 練習2

查詢所有員工信息。顯示員工編號,員工姓名,工資,職務名稱,職務描述,部門名稱,部門位置

具體操作:
1. 確定要查詢哪些表,emp e, job j, dept d

SELECT * FROM emp e INNER JOIN job j INNER JOIN dept d;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9fGi5nAl-1582193672240)(imgs\多表查詢06.png)]

在這裏插入圖片描述

  2. 確定表連接條件 e.job_id=j.id and e.dept_id=d.id
SELECT * FROM emp e INNER JOIN job j INNER JOIN dept d ON e.job_id=j.id AND e.dept_id=d.id;

在這裏插入圖片描述

  3. 確定查詢字段:員工編號,員工姓名,工資,職務名稱,職務描述,部門名稱,部門位置
SELECT e.`id`, e.`ename`, e.`salary`, j.`jname`, j.`description`, d.`dname`, d.`loc` FROM emp e INNER JOIN job j INNER JOIN dept d ON e.job_id=j.id AND e.dept_id=d.id;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-q3ymjWvZ-1582193672241)(imgs\多表查詢10.png)]

2.2.3 練習3

查詢所有員工信息。顯示員工姓名,工資,職務名稱,職務描述,部門名稱,部門位置,工資等級

具體操作:
1. 確定要查詢哪些表,emp e, job j, dept d, salarygrade s

SELECT * FROM emp e INNER JOIN job j INNER JOIN dept d INNER JOIN salarygrade s;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RQloeO6c-1582193672241)(imgs\多表查詢11.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-urUpTuDO-1582193672242)(imgs\多表查詢12.png)]

  2. 確定表連接條件 e.job_id=j.id and e.dept_id=d.id and e.salary between s.losalary and hisalary
SELECT * FROM emp e INNER JOIN job j INNER JOIN dept d INNER JOIN salarygrade s ON e.job_id=j.id AND e.dept_id=d.id AND e.salary BETWEEN s.losalary AND hisalary;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8qwigFz2-1582193672242)(imgs\多表查詢13.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uP8UZxCG-1582193672242)(imgs\多表查詢14.png)]

  3. 確定查詢字段:員工姓名,工資,職務名稱,職務描述,部門名稱,部門位置,工資等級
SELECT e.`ename`, e.`salary`, j.`jname`, j.`description`, d.`dname`, d.`loc`, s.`grade` FROM emp e INNER JOIN job j INNER JOIN dept d INNER JOIN salarygrade s ON e.job_id=j.id AND e.dept_id=d.id AND e.salary BETWEEN s.losalary AND hisalary;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DDFDTrsb-1582193672242)(imgs\多表查詢15.png)]

2.2.3.1 多表查詢規律總結

  1. 不管我們查詢幾張表,表連接查詢會產出笛卡爾積,我們需要消除笛卡爾積,拿到正確的數據。我們需要找到表與表之間通過哪個字段關聯起來的(通常是外鍵=主鍵
  2. 消除笛卡爾積規律:2張表需要1個條件,3張表需要2個條件,4張表需要3個條件。(條件數量=表的數量-1),每張表都要參與進來
  3. 多表連接查詢步驟:
    3.1. 確定要查詢哪些表
    3.2. 確定表連接條件
    3.3. 確定查詢字段

2.2.4 練習4

查詢經理的信息。顯示員工姓名,工資,職務名稱,職務描述,部門名稱,部門位置,工資等級

具體操作:
1. 確定要查詢哪些表,emp e, job j, dept d, salarygrade s

  SELECT * FROM emp e INNER JOIN job j INNER JOIN dept d INNER JOIN salarygrade s;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jJa0FiFv-1582193672242)(imgs\多表查詢11.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-djMEqNIF-1582193672243)(imgs\多表查詢12.png)]

  2. 確定表連接條件 e.job_id=j.id and e.dept_id=d.id and e.salary between s.losalary and hisalary
SELECT * FROM emp e INNER JOIN job j INNER JOIN dept d INNER JOIN salarygrade s ON e.job_id=j.id AND e.dept_id=d.id AND e.salary BETWEEN s.losalary AND hisalary;

在這裏插入圖片描述

額外條件:只需要查詢經理的信息(j.jname=‘經理’)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CTr22ZIc-1582193672243)(imgs\多表查詢16.png)]

  3. 確定查詢字段:員工姓名,工資,職務名稱,職務描述,部門名稱,部門位置,工資等級
SELECT e.`ename`, e.`salary`, j.`jname`, j.`description`, d.`dname`, d.`loc`, s.`grade` FROM emp e INNER JOIN job j INNER JOIN dept d INNER JOIN salarygrade s ON e.job_id=j.id AND e.dept_id=d.id AND e.salary BETWEEN s.losalary AND hisalary AND j.jname='經理';

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pSTGqejF-1582193672243)(imgs\多表查詢17.png)]

2.2.5 練習5

查詢出部門編號、部門名稱、部門位置、部門人數

具體操作:
1. 去員工表中找到每個部門的人數和部門id

SELECT dept_id, COUNT(*) FROM emp GROUP BY dept_id;

在這裏插入圖片描述

  2. 再和部門表連接查詢
SELECT * FROM dept d INNER JOIN (SELECT dept_id, COUNT(*) FROM emp GROUP BY dept_id) e ON e.dept_id=d.`id`;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-C0lD7HfO-1582193672244)(imgs\多表查詢19.png)][外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mGPJ1F4D-1582193672244)(imgs\多表查詢20.png)]

  3. 顯示對應的字段
SELECT d.`id`, d.dname, d.`loc`, e.total 部門人數 FROM dept d INNER JOIN (SELECT dept_id, COUNT(*) total FROM emp GROUP BY dept_id) e ON e.dept_id=d.`id`;

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uDhbTpgb-1582193672244)(imgs\多表查詢21.png)]
最終效果:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SYJoUtLy-1582193672244)(imgs\多表查詢22.png)]

第3章 事務安全

3.1 事務的應用場景說明

在實際的業務開發中,有些業務操作要多次訪問數據庫。一個業務要發送多條SQL語句給數據庫執行。需要將多次訪問數據庫的操作視爲一個整體來執行,要麼所有的SQL語句全部執行成功。如果其中有一條SQL語句失敗,就進行事務的回滾,所有的SQL語句全部執行失敗。

例如: 張三給李四轉賬,張三賬號減錢,李四賬號加錢

-- 創建數據表
CREATE TABLE account (
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10),
	balance DOUBLE
);

-- 添加數據
INSERT INTO account (NAME, balance) VALUES ('張三', 1000), ('李四', 1000);

模擬張三給李四轉500元錢,一個轉賬的業務操作最少要執行下面的2條語句:

  1. 張三賬號-500
  2. 李四賬號+500
-- 1. 張三賬號-500
UPDATE account SET balance = balance - 500 WHERE id=1;
-- 2. 李四賬號+500
UPDATE account SET balance = balance + 500 WHERE id=2;
假設當張三賬號上-500元,服務器崩潰了。李四的賬號並沒有+500元,數據就出現問題了。我們需要保證其中一條SQL語句出現問題,整個轉賬就算失敗。只有兩條SQL都成功了轉賬纔算成功。這個時候就需要用到事務

3.2 操作事務

MYSQL中可以有兩種方式進行事務的操作:1.手動提交事務2.自動提交事務

3.2.1 手動提交事務

事務有關的SQL語句:

SQL語句 描述
start transaction; 開啓事務
commit; 提交事務
rollback; 回滾事務

手動提交事務使用步驟
第1種情況:開啓事務 -> 執行SQL語句 -> 成功 -> 提交事務
第2種情況:開啓事務 -> 執行SQL語句 -> 失敗 -> 回滾事務
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Axpv6MUM-1582193672244)(imgs\事務01.png)]

案例演示1:模擬張三給李四轉500元錢(成功)
目前數據庫數據如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OkJN2bXc-1582193672245)(imgs\事務03.png)]

  1. 使用DOS控制檯進入MySQL

  2. 執行以下SQL語句: 1.開啓事務2.張三賬號-5003.李四賬號+500

    START TRANSACTION;
    UPDATE account SET balance = balance - 500 WHERE id=1;
    UPDATE account SET balance = balance + 500 WHERE id=2;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OsgzCIRB-1582193672245)(imgs\事務02.png)]

  3. 使用SQLYog查看數據庫:發現數據並沒有改變
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yMMBQSgX-1582193672245)(imgs\事務03.png)]

  4. 在控制檯執行commit提交任務:
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DosJHbSS-1582193672245)(imgs\事務04.png)]

  5. 使用SQLYog查看數據庫:發現數據改變
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aPF4f9Qb-1582193672245)(imgs\事務05.png)]


案例演示2:模擬張三給李四轉500元錢(失敗)
目前數據庫數據如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gOFG6SlI-1582193672245)(imgs\事務05.png)]

  1. 在控制檯執行以下SQL語句:1.開啓事務2.張三賬號-500

    START TRANSACTION;
    UPDATE account SET balance = balance - 500 WHERE id=1;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Vuv9q9Oc-1582193672246)(imgs\事務06.png)]

  2. 使用SQLYog查看數據庫:發現數據並沒有改變
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-atwTHN7a-1582193672246)(imgs\事務07.png)]

  3. 在控制檯執行rollback回滾事務:
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-p4w5ktAB-1582193672246)(imgs\事務08.png)]

  4. 使用SQLYog查看數據庫:發現數據沒有改變
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BBux9wla-1582193672246)(imgs\事務09.png)]

總結:
如果事務中SQL語句沒有問題,commit提交事務,會對數據庫數據的數據進行改變。
如果事務中SQL語句有問題,rollback回滾事務,會回退到開啓事務時的狀態。

3.2.2 自動提交事務

MySQL的每一條DML(增刪改)語句都是一個單獨的事務,每條語句都會自動開啓一個事務,執行完畢自動提交事務,MySQL默認開始自動提交事務

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-7jPVlpKK-1582193672246)(imgs\事務10.png)]

  1. 將金額重置爲1000
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tVnfQEgJ-1582193672246)(imgs\事務11.png)]

  2. 執行以下SQL語句

    UPDATE account SET balance = balance - 500 WHERE id=1;
    
  3. 使用SQLYog查看數據庫:發現數據已經改變
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CzzoL8VY-1582193672247)(imgs\事務12.png)]

    通過修改MySQL全局變量"autocommit",取消自動提交事務
    使用SQL語句:show variables like '%commit%';查看MySQL是否開啓自動提交事務
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MMZT2kCK-1582193672247)(imgs\事務13.png)]
    0:OFF(關閉自動提交)
    1:ON(開啓自動提交)

  4. 取消自動提交事務,設置自動提交的參數爲OFF,執行SQL語句:set autocommit = 0;
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wMvfjwnn-1582193672247)(imgs\事務14.png)]

  5. 在控制檯執行以下SQL語句:張三-500

    UPDATE account SET balance = balance - 500 WHERE id=1;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NwFxXYlf-1582193672247)(imgs\事務15.png)]

  6. 使用SQLYog查看數據庫,發現數據並沒有改變
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iy0WtGqI-1582193672247)(imgs\事務16.png)]

  7. 在控制檯執行commit提交任務
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WeYCPWcF-1582193672247)(imgs\事務17.png)]

  8. 使用SQLYog查看數據庫,發現數據改變
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1mMUSwKG-1582193672248)(imgs\事務18.png)]

3.3 事務原理

事務開啓之後, 所有的操作都會臨時保存到事務日誌, 事務日誌只有在得到`commit`命令纔會同步到數據表中,其他任何情況都會清空事務日誌(rollback,斷開連接)

在這裏插入圖片描述

3.4 回滾點

在某些成功的操作完成之後,後續的操作有可能成功有可能失敗,但是不管成功還是失敗,前面操作都已經成功,可以在當前成功的位置設置一個回滾點。可以供後續失敗操作返回到該位置,而不是返回所有操作,這個點稱之爲回滾點。

設置回滾點語法:savepoint 回滾點名字;
回到回滾點語法: rollback to 回滾點名字;

具體操作:

  1. 將數據還原到1000
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HZ9zPcLg-1582193672248)(imgs\事務20.png)]

  2. 開啓事務
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8guQ4kTu-1582193672248)(imgs\事務21.png)]

  3. 讓張三賬號減3次錢

    UPDATE account SET balance = balance - 10 WHERE id=1;
    UPDATE account SET balance = balance - 10 WHERE id=1;
    UPDATE account SET balance = balance - 10 WHERE id=1;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-n6VQnjWr-1582193672248)(imgs\事務22.png)]

  4. 設置回滾點:savepoint abc;
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VsZqq9SC-1582193672249)(imgs\事務23.png)]

  5. 讓張三賬號減4次錢

    UPDATE account SET balance = balance - 10 WHERE id=1;
    UPDATE account SET balance = balance - 10 WHERE id=1;
    UPDATE account SET balance = balance - 10 WHERE id=1;
    UPDATE account SET balance = balance - 10 WHERE id=1;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pJxTN4vm-1582193672249)(imgs\事務24.png)]

  6. 回到回滾點:rollback to abc;
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VVWL5exw-1582193672249)(imgs\事務25.png)]

  7. 分析過程
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RLuTYbMF-1582193672249)(imgs\事務26.png)]

  8. 如果是事務回滾到指定的位置上,如果需要生效,那麼必須要commit提交。

總結:設置回滾點可以讓我們在失敗的時候回到回滾點,而不是回到事務開啓的時候。

3.5 事務的四大特性

3.5.1 事務的四大特性

事務特性 含義
原子性(Atomicity) 事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。
一致性(Consistency) 事務前後數據的完整性必須保持一致
隔離性(Isolation) 是指多個用戶併發訪問數據庫時,一個用戶的事務不能被其它用戶的事務所幹擾,多個併發事務之間數據要相互隔離,不能相互影響。
持久性(Durability) 指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響

3.5.2 事務的隔離級別

事務在操作時的理想狀態:多個事務之間互不影響,如果隔離級別設置不當就可能引發併發訪問問題。

併發訪問的問題 含義
髒讀 一個事務讀取到了另一個事務中尚未提交的數據
不可重複讀 一個事務中兩次讀取的數據內容不一致,要求的是一個事務中多次讀取時數據是一致的,這是事務update時引發的問題
幻讀 一個事務中兩次讀取的數據的數量不一致,要求在一個事務多次讀取的數據的數量是一致的,這是insert或delete時引發的問題

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-v5QtROIs-1582193672249)(imgs\事務58.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AFcRm9Pp-1582193672250)(imgs\事務59.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KrUvRuMT-1582193672250)(imgs\事務60.png)]

MySQL數據庫有四種隔離級別:上面的級別最低,下面的級別最高。“是”表示會出現這種問題,“否”表示不會出現這種問題。

級別 名字 隔離級別 髒讀 不可重複讀 幻讀 數據庫默認隔離級別
1 讀未提交 read uncommitted
2 讀已提交 read committed Oracle和SQL Server
3 可重複讀 repeatable read MySQL
4 串行化 serializable

MySQL事務隔離級別相關的命令

  1. 查詢全局事務隔離級別

    show variables like '%isolation%';
    -- 或
    select @@tx_isolation;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kGaeNF17-1582193672250)(imgs\事務27.png)]

  2. 設置事務隔離級別,需要退出MSQL再進入MYSQL才能看到隔離級別的變化

    set global transaction isolation level 級別字符串;
    -- 如:
    set global transaction isolation level read uncommitted;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KtFkghZ2-1582193672250)(imgs\事務28.png)]

3.5.2.1 髒讀的演示

將數據進行恢復:UPDATE account SET balance = 1000;

  1. 打開A窗口登錄MySQL,設置全局的隔離級別爲最低

    mysql -uroot -proot
    set global transaction isolation level read uncommitted;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ep7VIJse-1582193672250)(imgs\事務29.png)]

  2. 打開B窗口,AB窗口都開啓事務

    use day23;
    start transaction;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HnkxbzoD-1582193672251)(imgs\事務30.png)]

  3. A窗口更新2個人的賬戶數據,未提交

    update account set balance=balance-500 where id=1;
    update account set balance=balance+500 where id=2;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JzZ7nifH-1582193672251)(imgs\事務31.png)]

  4. B窗口查詢賬戶

    select * from account;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-zYzI6Td7-1582193672251)(imgs\事務32.png)]

  5. A窗口回滾

    rollback;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-EOb3OYHg-1582193672251)(imgs\事務33.png)]

  6. B窗口查詢賬戶,錢沒了
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VXEojmRb-1582193672251)(imgs\事務34.png)]

髒讀非常危險的,比如張三向李四購買商品,張三開啓事務,向李四賬號轉入500塊,然後打電話給李四說錢已經轉了。李四一查詢錢到賬了,發貨給張三。張三收到貨後回滾事務,李四的再查看錢沒了。

解決髒讀的問題:將全局的隔離級別進行提升
將數據進行恢復:UPDATE account SET balance = 1000;

  1. 在A窗口設置全局的隔離級別爲read committed

    set global transaction isolation level read committed;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RXjbE1Va-1582193672251)(imgs\事務35.png)]

  2. B窗口退出MySQL,B窗口再進入MySQL
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hdUQmClA-1582193672252)(imgs\事務36.png)]

  3. AB窗口同時開啓事務
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YnvDCAvW-1582193672252)(imgs\事務37.png)]

  4. A更新2個人的賬戶,未提交

    update account set balance=balance-500 where id=1;
    update account set balance=balance+500 where id=2;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AF9ERdGP-1582193672252)(imgs\事務38.png)]

  5. B窗口查詢賬戶
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XICNZwpT-1582193672252)(imgs\事務39.png)]

  6. A窗口commit提交事務
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-S6kqj66g-1582193672252)(imgs\事務40.png)]

  7. B窗口查看賬戶
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Iz0jHt4x-1582193672255)(imgs\事務41.png)]

結論:read committed的方式可以避免髒讀的發生

3.5.2.2 不可重複讀的演示

將數據進行恢復:UPDATE account SET balance = 1000;

  1. 開啓A窗口

    set global transaction isolation level read committed;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2fBuxXZM-1582193672255)(imgs\事務42.png)]

  2. 開啓B窗口,在B窗口開啓事務

    start transaction;
    select * from account;
    

在這裏插入圖片描述

  1. 在A窗口開啓事務,並更新數據

    start transaction;
    update account set balance=balance+500 where id=1;
    commit;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Lea8NVuT-1582193672255)(imgs\事務44.png)]

  2. B窗口查詢

    select * from account;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lS237JcQ-1582193672256)(imgs\事務45.png)]

兩次查詢輸出的結果不同,到底哪次是對的?不知道以哪次爲準。
很多人認爲這種情況就對了,無須困惑,當然是後面的爲準。我們可以考慮這樣一種情況,比如銀行程序需要將查詢結果分別輸出到電腦屏幕和發短信給客戶,結果在一個事務中針對不同的輸出目的地進行的兩次查詢不一致,導致文件和屏幕中的結果不一致,銀行工作人員就不知道以哪個爲準了。

解決不可重複讀的問題:將全局的隔離級別進行提升爲:repeatable read
將數據進行恢復:UPDATE account SET balance = 1000;

  1. A窗口設置隔離級別爲:repeatable read

    set global transaction isolation level repeatable read;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mB0OzmYk-1582193672256)(imgs\事務46.png)]

  2. B窗口退出MySQL,B窗口再進入MySQL

    start transaction;
    select * from account;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XGnqvRbm-1582193672256)(imgs\事務47.png)]

  3. A窗口更新數據

    start transaction;
    update account set balance=balance+500 where id=1;
    commit;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8E96CTTp-1582193672256)(imgs\事務48.png)]

  4. B窗口查詢

    select * from account;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6Jb6xmVD-1582193672256)(imgs\事務49.png)]

結論:同一個事務中爲了保證多次查詢數據一致,必須使用repeatable read隔離級別
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5Y5QYoXo-1582193672256)(imgs\事務50.png)]

3.5.2.3 幻讀的演示

在MySQL中無法看到幻讀的效果。但我們可以將事務隔離級別設置到最高,以擋住幻讀的發生
將數據進行恢復:UPDATE account SET balance = 1000;

  1. 開啓A窗口

    set global transaction isolation level serializable; -- 設置隔離級別爲最高
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-W0CL7P9k-1582193672257)(imgs\事務51.png)]

  2. A窗口退出MySQL,A窗口重新登錄MySQL

    start transaction;
    select count(*) from account;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CnyLgGZM-1582193672257)(imgs\事務52.png)]

  3. 再開啓B窗口,登錄MySQL

  4. 在B窗口中開啓事務,添加一條記錄

    start transaction; -- 開啓事務
    insert into account (name,balance) values ('LaoWang', 500);
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-n0eyriwz-1582193672257)(imgs\事務53.png)]

  5. 在A窗口中commit提交事務,B窗口中insert語句會在A窗口事務提交後立馬運行
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jf4VGjmA-1582193672257)(imgs\事務54.png)]

  6. 在A窗口中接着查詢,發現數據不變

    select count(*) from account;
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xbwYBYgg-1582193672257)(imgs\事務55.png)]

  7. B窗口中commit提交當前事務
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Xh46LW6e-1582193672258)(imgs\事務56.png)]

  8. A窗口就能看到最新的數據
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OApxovCl-1582193672258)(imgs\事務57.png)]

結論:使用serializable隔離級別,一個事務沒有執行完,其他事務的SQL執行不了,可以擋住幻讀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章