首頁 > 軟體

MySQL資料庫設計概念及多表查詢和事物操作

2022-05-24 14:02:52

資料庫設計概念

資料庫設計簡介

1.資料庫設計概念

  • 資料庫設計就是根據業務系統具體需求,結合我們所選用的DBMS,為這個業務系統構造出最優的資料儲存模型。
  • 建立資料庫中的表結構以及表與表之間的關聯關係的過程。
  • 有哪些表?表裡有哪些欄位?表和表之間有什麼關係?

2.資料庫設計步驟

  • 需求分析:資料庫是什麼?資料具體有哪些屬性?資料與屬性的特點是什麼?
  • 邏輯分析:通過ER圖對資料庫進行邏輯建模,不需要考慮我們所選用的資料庫管理系統。
  • 物理設計:根據資料庫自身的特點把邏輯設計轉換為物理設計。
  • 維護設計:對新的需求進行建表和對錶的優化。

3.表關係簡介

  • 在真實的開發中,一個專案中的資料,一般都會儲存在同一個資料庫中,但是不同的資料需要儲存在不同的資料表中。這時不能把所有的資料都儲存在同一張表中。
  • 那麼在設計儲存資料的資料表時,我們就要根據具體的資料進行分析,然後把同一類資料儲存在同一張表中,不同的資料進行分表處理。
  • 資料之間必然會有一定的聯絡,我們把不同的資料儲存在不同的資料表中之後,同時還要在資料表中維護這些資料之間的關係。這時就會導致表和表之間必然會有一定的聯絡。這時要求設計表的人員,就需要考慮不同表之間的具體關係。

在資料庫中,表總共存在三種關係,真實的資料表之間的關係:多對多關係、一對多(多對一)、一對一(極少),(一對一關係就是我們之前學習的Map集合的key-value關係)

表關係(多對多)

1.多對多

  • 如:訂單 和 商品
  • 一個商品對應多個訂單,一個訂單對應多個商品
  • 實現方式:建立第三張中間表,中間表至少包含兩個外來鍵,分別關聯兩方主鍵

說明:如果兩張表是多對多的關係,需要建立第三張表,並在第三張表中增加兩列,引入其他兩張表的主鍵作為自己的外來鍵。

2.外來鍵約束

  • 外來鍵用來讓兩個表的資料之間建立連結,保證資料的一致性和完整性(例如上述多對多中的訂單商品表來維護訂單表和商品表之間的關係)
  • 使用之間表的目的是維護兩表之間多對多的關係:中間表插入的資料,必須在多對多的主表中存在如果主表的記錄在中間表中維護了關係,就不能隨意的刪除。如果要刪除,必須先要刪除中間表關聯的資料

3.外來鍵約束語法

-- 關鍵字解釋:
constraint: 新增約束,可以不寫
foreign key(當前表中的列名): 將某個欄位作為外來鍵
references 被參照表名(被參照表的列名) : 外來鍵參照主表的主鍵

-- 建立表時新增外來鍵約束
CREATE TABLE 表名(
   列名 資料型別,
   …
   [CONSTRAINT] [外來鍵名稱] FOREIGN KEY(外來鍵列名) REFERENCES 主表(主表列名) 
); 
-- 建完表後新增外來鍵約束
ALTER TABLE 表名 ADD CONSTRAINT 外來鍵名稱 FOREIGN KEY (外來鍵欄位名稱) REFERENCES 主表名稱(主表列名稱);
-- 刪除約束
ALTER TABLE 表名 DROP FOREIGN KEY 外來鍵名稱;

4.建立外來鍵約束

-- 訂單表
CREATE TABLE tb_orders
(
    id           int primary key auto_increment,
    payment      double(10, 2),
    payment_type TINYINT, -- 0 微信支付  1 支付寶支付
    status       TINYINT  -- 0 未付款  1 已經支付

);
-- 商品表
CREATE TABLE tb_goods
(
    id    int primary key auto_increment,
    title varchar(100),
    price double(10, 2)
);
-- 訂單商品中間表
CREATE TABLE tb_order_goods
(
    id       int primary key auto_increment,
    order_id int, -- 外來鍵,來自於訂單表的主鍵
    goods_id int, -- 外來鍵,來自於商品表的主鍵
    count    int,  -- 購買商品數量
    foreign key(order_id) references tb_orders(id),
    foreign key(goods_id) references tb_goods(id)
);

5.外來鍵級聯

在修改和刪除主表的主鍵時,同時更新或刪除從表的外來鍵值,稱為級聯操作

  • ON UPDATE CASCADE – 級聯更新,主鍵發生更新時,外來鍵也會更新
  • ON DELETE CASCADE – 級聯刪除,主鍵發生刪除時,外來鍵也會刪除

6.總結

1.為何要參照外來鍵約束?

讓表的資料有效性,正確性。提高查詢效率。

2.新增外來鍵約束語法?

constraint 外來鍵約束名 foreign key(當前表的欄位名) references 主表(主鍵)

3.有了外來鍵約束運算元據注意事項?

要求新增資料需要先新增主表,然後新增從表。要求刪除資料需要先刪除從表,然後再刪除主表。

表關係(一對多)

一對多(多對一)

  • 如:部門表 和 員工表
  • 一個部門對應多個員工,一個員工對應一個部門
  • 實現方式:在多的一方建立外來鍵,指向一的一方的主鍵

表關係之一對一

一對一

  • 如:使用者和 使用者資訊
  • 一對一關係多用於表拆分,將一個實體中經常使用的欄位放一張表,不經常使用的欄位放另一張表,用於提升查詢效能
  • 實現方式:在任意一方加入外來鍵,關聯另一方主鍵,並且設定外來鍵為唯一(UNIQUE)

多表查詢

準備資料

-- 價格
create table price
(

    id    int primary key auto_increment,
    price double
);
-- 水果 
create table fruit
(

    id       int primary key auto_increment,
    name     varchar(20) not null,
    price_id int,
    foreign key (price_id) references price (id)
);
-- 資料
insert into price
values (1, 2.30);
insert into price
values (2, 3.50);
insert into price
values (4, null);
insert into fruit
values (1, '蘋果', 1);
insert into fruit
values (2, '橘子', 2);
insert into fruit
values (3, '香蕉', null);

笛卡爾積現象

1.什麼是笛卡爾積現象

  • 笛卡爾積問題:把多張表放在一起,同時去查詢,會得到一個結果,而這結果並不是我們想要的資料,這個結果稱為笛卡爾積。
  • 笛卡爾積缺點:查詢到的結果冗餘了,裡面有很多錯誤的資料,需要過濾。
  • 多表查詢語法:select * from 表名1,表名2;

需求:查詢兩張表中關於水果的資訊,要顯示水果名稱和水果價格

表設計原則:將價格的主鍵作為水果的外來鍵

-- 多表查詢語法(同時查詢多個表獲取到需要的資料)
select * from 表名1,表名2;
-- 查詢價格(我們向查詢水果對應的價格,需要將水果表和價格表同時進行查詢;)
select * from fruit,price;

查詢結果:

2.笛卡爾積產生原因

fruit表中的每一條記錄,都和price表中的每一條進行匹配連線。所得到的最終結果是:fruit表中的條目數乘以price表中的資料的條目數。

fruit表的每行記錄和price表的每行記錄組合的結果就是笛卡爾積

3.如何避免笛卡爾積

解決上述查詢的方案:在查詢兩張表的同時新增條件進行過濾,比如fruit表的id和必須和price表的id相同

-- 條件過濾笛卡爾積
select * from fruit,price where fruit.price_id=price.id;

內連線查詢

1.什麼是內連線

內連線查詢又稱為交集查詢,也就是查詢只顯示滿足條件的資料

2.顯示內連線

顯示內連線:使用INNER JOIN...ON語句,可以省略INNER關鍵字

-- 語法核心
select * from 表名1 inner join 表名2 on 條件;
-- 或者
select * from 表名1 join 表名2 on 條件;

3.隱式內連線

看不到JOIN關鍵字,條件使用WHERE指定

select 列名,列名,... from 表名1,表名2 where 表名1.列名=表名2.列名; 

4.範例

查詢水果的價格

-- 隱式內連線
select * from fruit,price where fruit.price_id=price.id;
-- 顯式內連線
select * from fruit inner join price on fruit.price_id=price.id;

查詢蘋果的資訊,顯示蘋果的id,名字,價格

-- 方式1
select fruit.id, fruit.name, price.price
from fruit,
     price
where fruit.price_id = price.id
  and fruit.name = '蘋果';
-- 方式2
select fruit.id, fruit.name, price.price
from fruit
         inner join
     price
     on fruit.price_id = price.id
         and fruit.name = '蘋果';

5.總結

1.內連線作用?

  • 過濾笛卡爾積
  • 獲取兩表的交集部分(都滿足條件的部分)

2.什麼是隱式內連線和顯示內連線?

  • 隱式內連線:看不到JOIN:select 列名,列名....from 表名1,表名2 where 表名1.列名=表名2.列名;
  • 顯示內連線:看得到JOIN:select * from 表名1 inner join 表名2 on 條件;

3.內連線查詢步驟?

  • 1)確定查詢幾張表
  • 2)確定表連線條件
  • 3)根據需要在操作 外連線查詢

1.左外連線

  • 左表的記錄全部顯示出來
  • 外表只會顯示符合搜尋條件的記錄

語法格式:

select * from 表1 left [outer] join 表2 on 條件;

說明:

  • left關鍵字左邊的表定義為左表,left關鍵字右邊的表定義為右表,查詢的內容以左表為主
  • 如果左表有資料,而右表沒有資料對應的資料,仍然會把左表資料進行顯示
  • outer關鍵字可以省略

練習:

不管能否查到水果對應價格,都要把水果顯示出來

-- 左外連線查詢
select * from fruit left outer join price on fruit.price_id=price.id;

2.右外連線

  • 右表的記錄全部表示出來
  • 左表只會顯示符合搜尋條件的記錄

語法格式:

select * from 表名1 right [outer] join 表名2 on 條件;

說明:

  • right關鍵字左邊的表定義為左表,right關鍵字右邊的表定義為右表,查詢的內容以右表為主
  • 如果右表沒有資料,而左表沒有對應的資料,仍然會把右表資料進行顯示
  • outer關鍵字可以省略

練習:

不管能否查到價格對應的水果,都要把價格顯示出來

select * from fruit right outer join price on fruit.price_id=price.id;

總結:

1.掌握左外連線查詢格式?

select * from 表1 left outer join 表2 on 條件;
  • 表1看作為左表,表2看做為右表

2.左外連線查詢特點?

  • 在滿足要求的基礎上保證左表的資料全部顯示

3.掌握右外連線查詢格式?

select * from 表1 right outer join 表2 on 條件;

4.右外連線查詢特點?

在滿足要求的基礎上,保證右表的資料全部顯示

巢狀查詢(子查詢)

1.什麼是子查詢

一條查詢語句結果作為另一條查詢語法一部分。

SELECT 查詢欄位 FROM 表 WHERE 條件;
舉例:
SELECT * FROM employee WHERE salary=(SELECT MAX(salary) FROM employee);

說明:子查詢需要放在()中

三種子查詢情況:單行單列多行單列多行多列

2.單行單列

子查詢結果是單列,在WHERE後面作為條件

SELECT 查詢欄位 FROM 表 WHERE 欄位=(子查詢);

通常使用比較運運算元: >>=<<==

3.多行單列

子查詢結果是多行單列,結果集類似於一個陣列,在WHERE後面作為條件,父查詢使用IN運運算元

-- IN表示在數值中
SELECT 查詢欄位 FROM 表 WHERE 欄位 IN (子查詢);

4.多行多列

子查詢結果是多列,在FROM後面作為

SELECT 查詢欄位 FROM (子查詢) 表別名 WHERE 條件;

注意:子查詢作為表需要取別名,使用as,可以省略,否則這張表沒用名稱無法存取表中的欄位

事務操作

事務的概念

什麼是事務

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

簡而言之,事務指的是邏輯上的一組操作,組成這組操作的各個單元要麼全都成功,要麼全都失敗。

事務作用:保證在一個事務中多次運算元據庫表中資料時,要麼全都成功,要麼全都失敗。

事務的應用場景宣告

關於事務在實際中的應用場景:

假設我在淘寶買了一部手機,然後當我付完款,錢已經從我的賬戶中扣除。正當此時,淘寶轉賬系統宕機了,那麼此時淘寶還沒有收到錢,而我的賬戶的錢已經減少了,這樣就會導致我作為買家錢已經付過,而賣家還沒有收到錢,他們不會發貨物給我。這樣做顯然是不合理。實際生活中是如果淘寶出問題,作為使用者的賬戶中錢是不應該減少的。這樣使用者就不會損失錢。

還有種情況,就是當我付完款之後,賣家看到我付款成功,然後直接發貨了,我如果有許可權操作,我可以復原,這樣就會導致我的錢沒有減少,但是賣家已經發貨,同樣這種問題在實際生活中也是不允許出現的。

MySQL中可以有兩種方式進行事務的操作:

  • 手動提交事物:先開啟,在提交
  • 自動提交事物(預設的):即執行一條sql語句提交一次事物

資料準備

# 建立賬號表
create table account(
	id int primary key auto_increment,
	name varchar(20),
	money double
);
# 初始化資料
insert into account values (null,'a',1000);
insert into account values (null,'b',1000);

手動提交事務

手動提交事務有關的sql語句

SQL語句描述
start transaction開啟手動控制事物
commit提交事物
rollback回滾事物

手動提交事務使用步驟

  • 開啟事務–>執行SQL語句–>成功–>提交事務
  • 開啟事務–>執行SQL語句–>失敗–>回滾事務

演示案例:演示提交事務,a給b轉賬100元

-- 1.開啟事務
start transaction;
-- 2.執行sql語句
update account set money=money-100 where name='a';
update account set money=money+100 where name='b';
-- 3.提交事務
commit;

案例演示:演示回滾事務,a給b轉賬100元

-- 1.開啟事務
start transaction;
-- 2.執行sql語句
update account set money=money-100 where name='a';
update account set money=money+100 where name='b';
-- 3.回滾事務
rollback;

注意:

  • 提交事務(commit) :事務提交之後,sql語句對資料庫產生的操作才會被永久的儲存
  • 事務的回滾(rollback):復原已經成功執行的sql語句,回到開啟事務之前的狀態
  • 只要提交事務,那麼資料就會長久儲存了,就不能回滾事務了。即提交或者回滾事務都是代表結束當前事務的操作

自動提交事務

MySQL的每一條DML(增刪改)語句都是一個單獨的事務,每條語句都會自動開啟一個事務,執行完畢自動提交事務,MySQL預設開始自動提交事務。自動提交,通過修改mysql全域性變數autocommit進行控制。

通過以下命令可以檢視當前autocommit模式

show variables like '%commit%';

設定自動提交的引數為OFF

set autocommit = 0;  -- 0:OFF  1:ON

案例演示

-- 自動提交事務:每條sql語句就是一個事務,那麼執行一條sql語句就會提交一次事務
-- mysql資料庫就是自動提交事務
-- a給b轉賬100元
update account set money=money-100 where name='a';
update account set money=money+100 where name='b';

-- 檢視mysql是否自動提交事務
-- autocommit的值是on表示自動提交事務,值是off表示關閉自動提交事務
show variables like '%commit%';
-- 我們可以使用命令臨時設定mysql變為手動提交事務,即將自動提交事務關閉
-- 下次重新連線mysql依然是自動提交事務
set autocommit = 0; -- 0 表示關閉自動提交事務 1表示開啟自動事務
update account set money=money-100 where name='a'

注意:

1)MySql預設自動提交。即執行一條sql語句提交一次事務。

2)設定autocommit為off狀態,只是臨時性的,下次重新連線mysql,autocommit依然變為on狀態。

3)如果設定autocommit為off狀態,那麼當我們執行一條sql語句,就不會自動提交事務,重新啟動視覺化工具,資料並沒有改變。

4)如果設定autocommit為on狀態,如果我們先執行start transaction 然後在執行修改資料庫的語句:

update account set money = money-100 where name='a';
update account set money = money+100 where name='b';

那麼此時就表示上述修改資料庫的sql語句都在同一個事務中,此時必須手動提交事務,即commit

換句話說,如果我們手動開啟事務start transaction那麼此時mysql就不會自動提交事務,必須手動提交事務。

5)如果設定autocommit為on狀態,如果我們不執行start transaction 直接執行修改資料庫的語句:

update account set money = money-100 where name='a';
update account set money = money+100 where name='b';

那麼此時mysql就會自動提交事務,即上述每條sql語句就是一個事務

事務原理和四大特徵

事務原理

原理說明

  • 一個使用者登入成功以後,伺服器會建立一個臨時紀錄檔檔案。紀錄檔檔案用來儲存使用者事務狀態。
  • 如果沒有使用事務,則所有的操作直接寫到資料庫中,不會使用紀錄檔檔案。
  • 如果開啟事務,將所有的寫操作寫到紀錄檔檔案中。
  • 如果這時使用者提交了事務,則將紀錄檔檔案中所有的操作寫到資料庫中。
  • 如果使用者回滾事務,則紀錄檔檔案會被清空,不會影響到資料庫的操作。

事務的四大特徵

事務的四大特徵(ACID)

資料庫的事務必須具備ACID特徵,ACID是指Atomicity(原子性)、Consistensy(一致性)、Isolation(隔離性)和Durabiliyt(永續性)

隔離性(Isolation)

多個使用者並行的存取資料庫時,一個使用者的事務不能被其他使用者的事物干擾,多個並行的事務之間相互隔離


永續性(Durability)

指一個事務一旦被提交,它對資料庫的改變是永久性的,哪怕資料庫發生異常,重啟之後資料依然會存在


原子性(Atomicity)

指事務包裝的一組sql語句(一組業務邏輯)是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生

一致性(Consistency)

一致性是指資料處於一種語意上有意義且正確的狀態;

事務一致性是指事務執行的結果必須是使資料從一個一致性狀態變到另一個一致性狀態。

事務的成功與失敗,最終資料庫的資料都是符合實際生活的業務邏輯。一致性絕大多數依賴業務邏輯和原子性

事務的並行存取引發的三個問題(面試)

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

並行存取的問題含義
髒讀一個事務讀取到了另一個事務中尚未提交的資料。最嚴重,杜絕發生。
不可重複讀一個事務中兩次讀取的資料內容不一致,要求的是一個事務中多次讀取時資料是不一致的,這是事務update時引發的問題
幻讀(虛讀)一個事務內讀取到了別的事務插入或者刪除的資料,導致前後讀取記錄行數不同。這是insert或delete時引發的問題

 

1.髒讀:指一個事務讀取了另外一個事務未提交的資料。(非常危險)


2.不可重複讀:在一個事務內多次讀取表中的資料,多次讀取的結果不同。


3.幻讀(虛讀):一個事務內讀取到了別的事務插入或者刪除的資料,導致前後讀取記錄行數不同

4.總結

  • 贓讀:一個事務讀取另一個事務還沒有提交的資料,一定避免。
  • 不可重複讀:一個事務讀取多次資料內容不一樣,主要是update語句。事務已經提交了。 可以發生的。
  • 幻讀(虛讀):一個事務讀取多次數量不一樣,主要是delete或者insert語句。事務已經提交了。可以發生的。

事務的隔離級別

通過以上問題演示,我們發現如果不考慮事務的隔離性,會遇到髒讀、不可重複讀和虛讀等問題。所以在資料庫中我們要對上述三種問題進行解決。MySQL資料庫規範規定了4種隔離級別,分別用於描述兩個事務並行的所有情況。

事物隔離級別

上面的級別最低,下面的級別最高。表示會出現這種問題,表示不會出現這種問題。

級別名字隔離級別髒讀不可重複讀幻讀資料庫預設隔離級別
1讀未提交read uncommitted 
2讀已提交read committedOracle和SQL Server
3可重複讀repeatable readMySQL
4序列化serializable

安全和效能對比

  • 安全: 序列化>可重複讀>讀已提交>讀未提交
  • 效能: 序列化<可重複讀<讀已提交<讀未提交

其實三個問題中,最嚴重的就是髒讀(讀取了錯誤資料),這個問題一定要避免;

關於不可重複讀和虛讀其實並不是邏輯上的錯誤,而是資料的時效性問題,所以這種問題並不屬於很嚴重的錯誤;

如果對於資料的時效性要求不是很高的情況下,我們是可以接受不可重複讀和虛讀的情況發生的

到此這篇關於MySQL資料庫設計概念及多表查詢;事物操作的文章就介紹到這了,更多相關mysql資料庫設計內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com