SQL必學必會筆記 —— 基礎篇

基礎篇

SQL語言按照功能劃分

DDL(DataDefinitionLanguage),也就是數據定義語言,它用來定義咱們的數據庫對象,包括 數據庫、數據表和列。經過使用DDL,能夠建立,刪除和修改數據庫和表結構。html

DDL的基礎語法及設計工具

  1. 對數據庫進行定義
CREATE DATABASE nba; // 建立一個名爲nba的數據庫 DROP DATABASE nba; // 刪除一個名爲nba的數據庫
  1. 對數據表進行定義
CREATE TABLE table_name

建立表結構mysql

CREATE TABLE player (  player_id int(11) NOT NULL AUTO_INCREMENT,  player_name varchar(255) NOT NULL );

修改表結構sql

// 修改字段 ALTER TABLE player ADD (age int(11));  // 修改字段名  ALTER TABLE player RENAME COLUMN age to player_age   // 修改字段的數據庫類型  ALTER TABLE player MODIFY (player_age float(3,1));   // 刪除字段  ALTER TABLE player DROP COLUMN player_age;

數據標的常見約束數據庫

目的:express

保證RDBMS裏面數據的準確性和一致性。編程

 

常見的約束:緩存

  • 主鍵約束
    • 一條記錄的惟一標識,不能重複,不能爲空。
    • 能夠是一個字段,也能夠由多個字段符合組成。
  • 外鍵約束
    • 一個表中的外鍵對應另外一張表中的主鍵。
    • 可重複,也可爲空。
  • 惟一性約束
  • NOT NULL約束
  • DEFAULT,代表字段的默認值。
  • CHECK約束

 

咱們常經過可視化管理和設計工具進行數據庫的設計。例如:Navicat安全

 

DML(DataManipulationLanguage),數據操做語言,咱們用它操做和數據庫相關的記錄,比 如增長、刪除、修改數據表中的記錄。服務器

DCL(DataControlLanguage),數據控制語言,咱們用它來定義訪問權限和安全級別。網絡

DQL(DataQueryLanguage),數據查詢語言,咱們用它查詢想要的記錄。

 

DB、DBS和DBMS的區別是什麼?

DB(DataBase),也就是數據庫。

DBS(DataBase System),也就是數據庫系統。它是更大的概念,包括了數據庫、數據庫管理系統以及數據庫管理人員DBA。

DBMS(DataBase Management System),也就是數據庫管理系統。DBMS = 多個數據庫(DB) + 管理程序。

日常咱們說的Oracle、MySQL等稱之爲數據庫,但確切講,它們應該是數據庫管理系統,即DBMS。

 

DBMS分類

關係型數據庫(RDBMS)和非關係型數據庫(NoSQL)

關係型數據庫就是創建在關係模型基礎上的數據庫,SQL就是關係數據庫的查詢語言。

非關係數據庫分類不少,主要有如下這些:

  • 鍵值型數據庫:經過Key - Value鍵值的方式來存儲數據。其中,Redis是最流行的鍵值型數據庫。
  • 文檔型數據庫:用來管理文檔,在數據庫中文檔做爲處理信息的基本單位,一個文檔就至關於一條記錄。其中,MongoDB是最流行的文檔型數據庫。
  • 搜索引擎
  • 列式數據庫
  • 圖形數據庫

 

SQL是如何執行的?

  • Oracle中的SQL在Oracle中的執行過程:

截屏2020-08-15下午3.30.10.png

  1. 語法檢查: 檢查SQL拼寫是否正確,若是不正確,Oracle會報語法錯誤。
  2. 語義檢查: 檢查SQL中的訪問對象是否存在。語法檢查和語義檢查的做用是保證SQL語句沒有錯誤。
  3. 權限檢查: 看用戶是否具有訪問該數據的權限。
  4. 共享池檢查: 共享池(SharedPool)是一塊內存池,最主要的做用是緩存SQL語句和該語句的執行計
    劃。

Oracle經過檢查共享池是否存在SQL語句的執行計劃,來判斷進行軟解析,仍是硬解析。

如何理解軟解析和硬解析?

在共享池中,Oracle首先對SQL語句進行Hash運算,而後根據Hash值在庫緩存(Library Cache)中查 找,若是存在SQL語句的執行計劃,就直接拿來執行,直接進入「執行器」的環節,這就是軟解析

若是沒有找到SQL語句和執行計劃,Oracle就須要建立解析樹進行解析,生成執行計劃,進入「優化 器」這個步驟,這就是硬解析

共享池是Oracle中的術語,包括了庫緩存,數據字典緩衝區等。

如何避免硬解析,儘可能使用軟解析?

在Oracle中,綁定變量是它的一大特點。綁定變量就是在SQL語句中使用變量,經過不一樣的變量取值來改變SQL的執行結果。這樣作的好處是能提高軟解析的可能性,不足之處在於可能會致使生成的執行計劃不夠優化,所以是否須要綁定變量還須要視狀況而定。

  1. 優化器: 優化器中就是要進行硬解析,也就是決定怎麼作,好比建立解析樹,生成執行計劃。
  2. 執行器: 當有了解析樹和執行計劃以後,就知道了SQL該怎麼被執行,這樣就能夠在執行器中執行語句
    了。

 

  • MySQL中的SQL是如何執行的

MySQL是典型的C/S架構,即Client/Server架構,服務器端程序使用的mysqld。總體的MySQL流程以下圖所示:

mySQL.png

MySQL由三層組成:

  1. 鏈接層:客戶端和服務端創建鏈接,客戶端發送SQL至服務器端;
  2. SQL層:對SQL語句進行查詢處理;
  3. 存儲引擎層:與數據庫文件打交道,負責數據的存儲和讀取。

其中,SQL層與數據庫文件的存儲方式無關,SQL層結構以下:

截屏2020-08-15下午4.11.12.png1. 查詢緩存: Server若是在查詢緩存中發現了這條SQL語句,就會直接將結果返回給客戶端;若是沒有,就進入到解析器階段。須要說明的是,由於查詢緩存每每效率不高,因此在My拼SQ課L8.0以後就拋棄了這個功能。

2. 解析器: 在解析器中對SQL語句進行語法分析、語義分析。

3. 優化器: 在優化器中會肯定SQL語句的執行路徑,好比是根據全表檢索,仍是根據索引來檢索等。

4. 執行器: 在執行以前須要判斷該用戶是否具有權限,若是具有權限就執行SQL查詢並返回結果。在

MySQL8.0如下的版本,若是設置了查詢緩存,這時會將查詢結果進行緩存。

這部分與Oracle執行SQL的原理是同樣的。

 

與Oracle不一樣的是,MySQL的存儲引擎採用了插件的形式,每一個存儲引擎都面向一種特定的數據庫應用環境。同時開源的MySQL還容許開發人員設置本身的存儲引擎,下面是一些常見的存儲引擎

  1. InnoDB存儲引擎:它是MySQL5.5版本以後默認的存儲引擎,最大的特色是支持事務、行級鎖定、外鍵 約束等。
  2. MyISAM存儲引擎:在MySQL5.5版本以前是默認的存儲引擎,不支持事務,也不支持外鍵,最大的特色 是速度快,佔用資源少。
  3. Memory存儲引擎:使用系統內存做爲存儲介質,以便獲得更快的響應速度。不過若是mysqld進程崩 潰,則會致使全部的數據丟失,所以咱們只有當數據是臨時的狀況下才使用Memory存儲引擎。
  4. NDB存儲引擎:也叫作NDBCluster存儲引擎,主要用於MySQLCluster分佈式集羣環境,相似於Oracle 的RAC集羣。
  5. Archive存儲引擎:它有很好的壓縮機制,用於文件歸檔,在請求寫入時會進行壓縮,因此也常常用來作 倉庫。

 

設計數據表的原則

「三少一多」

  1. 數據表的個數越少越好
  2. 數據表中的字段個數越少越好
  3. 數據表中聯合主鍵的字段個數越少越好
  4. 使用主鍵和外鍵越多越好

 

SELECT查詢的基礎語法

通常在生產環境下,不推薦直接使用SELECT*進行查詢。(由於效率不高)

// 查詢列 colmns代指須要查詢列(* 查詢所有,但在生產環境中較少使用,影響效率); tablename爲表名 SELECT columns FROM tablename  // 起別名 SELECT name AS n, hp_max AS hm  // 查詢常數 SELECT '王者榮耀' AS platfor, name FROM heros  // 去除重複行 // DISTINCT須要放到全部列名的前面; DISTINCT實際上是對後面全部列名的組合進行去重 SELECT DISTINCT attack_range FROM heros  // 如何排序檢索數據( ORDER BY 子句 默認按ASC遞增排序) // ORDER BY 一般位於 SELECT 語句的最後一條子句 SELECT name, hp_max FROM heros ORDER BY mp_max, hp_max DESC  // 約束返回結果的數量 LIMIT // 約束返回結果的數量能夠減小數據表的網絡傳輸量,也能夠提高查詢效率。 SELECT name, hp_max FROM heros, ORDER BY hp_max DESC LIMIT 5
  • SELECT的執行順序
  1. 關鍵字的順序是不能顛倒的:

SELECT...FROM...WHERE...GROUP BY...HAVING...ORDER BY...

  1. SELECT語句的執行順序(在MySQL和Oracle中,SELCT執行順序基本相同):

FROM > WHERE > GROUP BY > HAVING > SELCT的字段 > DISTINCT > ORDER BY > LIMIT

// 例如一個SQL語句,執行順序以下: SELECT DISTINCT palyer_id, player_name, count(*) as num #順序5 FROM player JOIN team ON player.team_id = team.team_id #順序1 WHERE height > 1.80 #順序2 GROUP BY player.team_id #順序3 HAVING num > 2 #順序4 ORDER BY num DESC #順序6 LIMIT 2 #順序7

在SELECT語句執行這些步驟的時候,每一個步驟都會產生一個虛擬表,而後將這個虛擬表傳入下一個步驟中做爲輸入。

SQL的執行原理

SQL語句的SELECT是先執行FROM這一步的。在這個階段,若是是多張表聯查,還會經歷下面的幾個步驟:

  1. 首先先經過CROSS JOIN求笛卡爾積,至關於獲得虛擬表vt(virtual table)1-1;
  2. 經過on進行篩選,在虛擬表vt1-1的基礎上進行篩選,獲得虛擬表vt1-2;
  3. 添加外部行。若是咱們使用的是左鏈接、右鏈接或者全鏈接,就會涉及外部行,也就是在虛擬表vt1-2的基礎上增長外部行,獲得虛擬表vt1-3。

 

若是操做的是兩張以上的表,還會重複上面的步驟,直到全部表都被處理完爲止。這個過程獲得是原始數據,也就是最終的虛擬表vt1,就能夠在這個基礎上再進行WHERE階段。在這個階段中,會根據vt1表的結果進行篩選過濾,獲得虛擬表vt2。

 

而後進入第三步和第四步,也就是GROUP和HAVING階段。在這個階段中,其實是在虛擬表vt2的基礎上進行分組和分組過濾,獲得中間的虛擬表vt3和vt4。

 

完成條件篩選部分後,就能夠篩選表中提取的字段,也就是進入到SELECT和DISTINCT階段。

首先在SELECT階段會提取想要的字段,而後在DISTINCT階段過濾重複的行,分別獲得中間的虛擬表vt5-1和vt5-2。

 

當提取了想要的字段後,就能夠按照指定的字段進行排序,也就是ORDER BY階段,獲得虛擬表vt6。

 

最後在vt6的基礎上,取出指定行的記錄,也就是LIMIT階段,獲得最終的結果,對應的是虛擬表vt7。

 

提高查詢效率的手段

  1. 儘可能少使用SELECT*,它會查詢全部列,效率不高;
  2. 當你知道查詢中有n條記錄或者須要n條記錄時,可使用LIMIT n進行約束,從而提升查詢效率;
  3. 指定篩選條件,進行過濾。過濾能夠篩選符合條件的結果,並進行返回,減小沒必要要的數據行。
  4. 儘可能少使用通配符,由於它須要消耗數據庫更長的時間進行匹配。

 

SQL數據過濾的方法

子查詢

子查詢既嵌套在查詢中的查詢,有便於咱們進行更復雜的查詢。

它劃分爲關聯子查詢非關聯子查詢。

 

  • 關聯子查詢

子查詢須要執行屢次,採用循環的方式,先從外部查詢開始,每次都傳入子查詢進行查詢,而後再將結果反饋給外部,這種嵌套的執行方式就稱爲關聯子查詢。

SELECT player_name, height, team_id FROM player AS a WHERE height > (SELECT avg(height) FROM player AS b WHERE a.team_id = b.team_id

 

  • 非關聯子查詢

子查詢從數據表中查詢了數據結果,若是這個數據結果只執行一次,而後這個數據結果做爲主查詢的條件進行執行,那麼這樣的子查詢叫作非關聯子查詢。

 SELECT player_name, height FROM player WHERE height = (SELECT max(height) FROM player)

 

  • 子查詢中的關鍵字

EXISTS子查詢

關聯子查詢一般也會和EXISTS子查詢一塊兒使用。EXISTS子查詢用來判斷條件是否知足,知足爲True,不知足爲False。

 

集合比較子查詢(IN、ANY、ALL、SOME)

IN:判斷是否在集合中

ANY:須要與比較操做符一塊兒使用,與子查詢返回的任何值作比較

ALL:須要與比較操做符一塊兒使用,與子查詢返回的任何值作比較

SOME:其實是ANY的別名,做用相同,通常常使用ANY

 

  • 子查詢做爲計算字段

把子查詢的結果做爲主查詢的列

SQL函數

SQL標準

SQL存在不一樣版本的標準規範,由於不一樣規範下的錶鏈接操做是有區別的。其有兩個主要的標準,分別是SQL92SQL99

 

SQL92

  • 在SQL92中是如何使用鏈接的

SQL92的5種鏈接方式,它們分別是笛卡爾積等值鏈接非等值鏈接外鏈接(左鏈接、右鏈接)和自鏈接

笛卡爾積(交叉鏈接)CROSS JOIN

笛卡爾積是一個數學運算。假設兩個集合X和Y,X和Y的笛卡爾積就是X和Y的全部可能組合。

它的做用就是能夠把任何表進行鏈接,即便這兩張表不相關。

 

等值鏈接

兩張表的等值鏈接就是用兩張表中都存在的列進行鏈接。也能夠對多張表進行等值鏈接。

 

非等值鏈接

進行多表查詢的時候,若是鏈接多個表的條件是等號時,就是等值鏈接,其餘的運算符鏈接就是非等值查詢。

 

外鏈接

兩張表的外鏈接,會有一張主表,另外一張是從表。若是是多張表的外鏈接,那麼第一張表是主表,即顯示所有的行,而剩下的表則顯示對應鏈接的信息。

在SQL92中才用(+)表明從表所在的位置,其只有左外鏈接和右外鏈接,沒有全外鏈接。

 

左外鏈接:

指左邊的表是主表,須要顯示左邊表的所有行,而右側的表是從表,(+)表示哪一個是從表。

 

右外鏈接:

指的是右邊的表是主表,須要顯示右邊表的所有行,而左側的是從表。

 

自鏈接

自鏈接能夠對多個表進行操做,也能夠對同一個表進行操做。也就是說查詢條件使用了當前表的字段。

 

SQL99

交叉鏈接

即SQL92中的笛卡爾乘積,這裏採用的是CROSS JOIN

 

天然鏈接

即SQL92的等值鏈接。這裏採用的是NATURAL JOIN

// SQL92 SELECT player_id, a.team_id, player_name, height, team_name FROM player as a, team as b WHERE a.team_id = b.team_id  // SQL99 SELECT player_id, team_id, player_name, height, team_name FROM player NATURAL JOIN team

 

ON鏈接

ON鏈接用來指定想要的鏈接條件。

通常來講在SQL99中,須要鏈接的表會採用JOIN進行鏈接,ON指定了鏈接條件,後面能夠是等值鏈接,也能夠採用非等值鏈接。

 

USING鏈接

使用USING指定數據表裏同名字段進行等值鏈接。使用JOIN USING能夠簡化JOIN ON的等值鏈接。例如:

// JOIN ON SELECT player_id, player.team_id, player_name, height, team_name FROM player JOIN team ON player.team_id = team.team_id  // JOIN USING SELECT player_id, team_id, player_name, height, team_name FROM player JOIN team USING(team_id)

 

外鏈接

SQL99的外鏈接包括三種形式:

  1. 左外鏈接:LEFT JOIN 或 LEFT OUTER JOIN
  2. 右外鏈接:RIGHT JOIN 或 RIGHT OUTER JOIN
  3. 全外鏈接:FULL JOIN 或 FULL OUTER JOIN

MySQL不支持全外鏈接,不然的話全外鏈接會返回左表和右表中的全部行。

全外鏈接的結果 = 左右表匹配的數據 + 左表沒有匹配到的數據 + 右表沒有匹配到的數九

 

自鏈接

自鏈接的原理在SQL92和SQL99中都是同樣的,只是表述方式不一樣。

 

SQL99和SQL92的區別

  • 二者的鏈接方式略有不一樣,這些鏈接操做基本能夠分爲三種狀況:
  1. 內鏈接:將多個表之間知足鏈接條件的數據行查詢出來。它包括了等值鏈接、非等值鏈接和自鏈接。
  2. 外鏈接:會返回一個表中的全部記錄,以及另外一個表中匹配的行。它包括了左外鏈接、右外鏈接和全鏈接。
  3. 交叉鏈接:也稱爲笛卡爾積,返回左表中每一行與右表中每一行的組合。在SQL99中使用CROSS JOIN。

 

  • SQL99相對SQL92,寫法更加可讀和嚴謹

在SQL92中進行查詢時,會把全部須要鏈接的表都放到FROM以後,而後在WHERE中寫明鏈接的條件。

而在SQL99中這方面更靈活,它不須要一次性把全部須要鏈接的表都放到FROM以後,而是採用JOIN的方式,每次鏈接一張表,能夠屢次使用JOIN進行鏈接。

SELECT ... FROM table1  JOIN table2 ON table1和table2的鏈接條件  JOIN table3 ON table2和table3的鏈接條件

多表鏈接建議使用SQL99標準,由於層次性更強,可讀性更強

 

視圖

視圖即虛擬表,它至關因而一張表或多張表的數據結果集。

截屏2020-08-17下午5.37.42.png

一般狀況下,小型項目的數據庫能夠不使用視圖,可是在大型項目中,以及數據表比較複製的狀況下,視圖的價值就凸顯出來了,它能夠幫助咱們把常常查詢的結果集放到虛擬表中,提高使用效率。

 

視圖的操做

  • 建立視圖:CREATE VIEW
// 語法 CREATE VIEW view_name AS SELECT column1, column2 FROM table WHERE condition  // 實例 CREATE VIEW player_above_avg_height AS SELECT player_id, height FROM player WHERE height > (SELECT AVG(height) from player)
  • 嵌套視圖
CREATE VIEW player_above_above_avg_height AS SELECT player_id, height FROM player WHERE height > (SELECT AVG(height) from player_above_avg_height)
  • 修改視圖:ALTER VIEW
ALTER VIEW view_name AS SELECT column1, column2 FROM table WHERE condition
  • 刪除視圖:DROP VIEW
DROP VIEW view_name

 

如何使用視圖簡化SQL操做

  • 視圖的做用:封裝SQL查詢,提高SQL複用率
  • 利用視圖完成複雜的鏈接
  • 利用視圖對數據進行格式化
  • 使用視圖和計算字段

 

視圖 VS 臨時表

  • 視圖是虛擬表,臨時表是實體表。
  • 臨時表只在當前鏈接存在,關閉鏈接後,臨時表就會自動釋放。

 

存儲過程

存儲過程(Stored Procedure)是程序化的SQL,能夠直接操做底層數據表,相比於面向集合的操做方式,可以實現一些更復雜的數據處理。它由SQL語句和流控制語句共同組成。

CREATE PROCEDURE 存儲過程名稱([參數列表]) BEGIN  須要執行的語句 END

與視圖類型,刪除存儲過程使用的是DROP PROCEDURE;更新存儲過程爲ALTER PROCEDURE。

下面看一個簡單的例子:

// 1+2+...+n CREATE PROCEDURE `add_num`(IN n INT) BEGIN  DECLARE i INT;  DECLARE sum INT;  SET i = 1;  SET sum = 0;  WHILE i <= n DO  SET sum = sum + i;  SET i = i + 1;  END WHILE;  SELECT sum; END

若是須要再次使用這個存儲過程時,直接使用CALL add_num(50);便可。

 

三種參數類型

參數類型

是否返回

做用

IN

向存儲過程傳入參數,存儲過程當中修改該參數的值,不能被返回。

OUT

把存儲過程計算的結果放到該參數中,調用者能夠獲得返回值。

INOUT

IN和OUT的結合,既用於存儲過程的傳入參數,同時又能夠把計算結果放到參數中,調用者能夠獲得返回值

IN和OUT的結合,既用於存儲過程的傳入參數,同時又能夠把計算機結果放到參數中,調用者能夠獲得返回值。

IN參數必須在調用過程時指定,而在存儲過程當中修改該參數的值不能被返回。而OUT參數和INOUT參數能夠在存儲過程當中被改變,並可返回。

例如以下:

// 查詢某一類型英雄中的最大的最大生命值,最小的最大魔法值,以及平均最大攻擊值 CREATE PROCEDURE `get_hero_scores`(  OUT max_max_hp FLOAT,  OUT min_max_mp FLOAT,  OUT avg_max_attack FLOAT,  s VARCHAR(255)  ) BEGIN  SELECT MAX(hp_max), MIN(mp_max), AVG(attack_max) FROM heros  WHERE role_main = s INTO max_max_hp, min_max_mp, avg_max_attack END  // 進行調用 CALL get_hero_scores(@max_max_hp, @min_max_mp, @avg_max_attack, '戰士'); SELECT @max_max_hp, @min_max_mp, @avg_max_attack;

 

流控制語句

  • BEGIN...END

其中間包含了多個語句,每一個語句都以(;)號爲結束符。

  • DECLARE

用於聲明變量,使用的位置在於BEGIN...END語句中間,並且須要在其餘語句以前進行變量的聲明。

  • SET

賦值語句,用於對變量進行賦值。

  • SELECT...INTO

把從數據表中查詢的結果存放到變量中,也就是爲變量賦值。

  • IF...THEN...ENDIF

條件判斷語句,咱們還能夠在iF...THEN...ENDIF中使用ELSE和ELSEIF來進行條件判斷。

  • CASE

用於多條件的分支判斷,語法以下:

CASE  WHEN expression1 THEN ...  WHEN expression2 THEN ...  ...  ELSE  --ELSE可加可不加。加的話表明全部條件都不知足時採用的方式 END
  • LOOP、LEAVE和ITERATE

LOOP是循環語句,使用LEAVE能夠跳出循環,使用ITERATE則能夠進入下一 次循環。若是你有面向過程的編程語言的使用經驗,你能夠把LEAVE理解爲BREAK,把ITERATE理解爲 CONTINUE。

  • REPEAT...UNTIL...END REPEAT

這是一個循環語句,首先會執行一次循環,而後在UNTIL中進行表達式 的判斷,若是知足條件就退出,即END REPEAT;若是條件不知足,則會就繼續執行循環,直到知足退出條 件爲止。

  • WHILE...DO...END WHILE

這也是循環語句,和REPEAT循環不一樣的是,這個語句須要先進行條件判斷, 若是知足條件就進行循環,若是不知足條件就1退出循環。

 

優缺點

有些公司對於大型項目要求使用存儲過程,而有些則在手冊中明確禁止使用存儲過程。

  • 優勢
    • 一次編譯屢次使用,提高SQL的執行效率
    • 減小開發工做量
    • 安全性強
    • 減小網絡傳輸量
  • 缺點
    • 可移植性差
    • 調試困難
    • 版本管理困難
    • 不適合高併發的場景

 

事務處理

保證了一次處理的完整性,也保證了數據庫中的數據一致性。

 

特性:ACID

  1. A,原子性(Atomicity)。進行數據處理操做的基本單位。
  2. C,一致性(Consistency)。指的是數據庫在進行事務操做後,會由原來的一致狀態,變成另外一種一致的狀態。
  3. I,隔離性(Isolation)。每一個事務都是彼此獨立的,不會受到其餘事務的執行影響。
  4. D,持久性(Durability)。事務提交以後對數據的修改是持久性的,即便在系統出故障的狀況下,好比系統崩潰或者存儲介質發送故障,數據的修改依然是有效的。持久性是經過事務日誌來保證的。日誌包括了回滾日誌和重作日誌。

ACID是事務的四大特性。原子性是基礎,隔離性是手段,一致性是約束條件,而持久性使咱們的目的。

 

事務的控制

使用事務有兩種方式,分爲隱式事務和顯式事務。隱式事務實際上就是自動提交,Oracle默認不自動提交,須要手動COMMIT命令,而MySQL默認自動提交。

  • 經常使用的控制語句
  1. STARTTRANSACTION或者BEGIN,做用是顯式開啓一個事務。
  2. COMMIT: 提交事務。當提交事務後,對數據庫的修改是永久性的。
  3. ROLLBACK或者ROLLBACKTO[SAVEPOINT],意爲回滾事務。意思是撤銷正在進行的全部沒有提交的修
    改,或者將事務回滾到某個保存點。
  4. SAVEPOINT: 在事務中建立保存點,方便後續針對保存點進行回滾。一個事務中能夠存在多個保存點。
  5. RELEASESAVEPOINT: 刪除某個保存點。
  6. SETTRANSACTION,設置事務的隔離級別。

 

事務隔離

  • 事務併發處理可能存在的異常都有哪些?

共有3種異常狀況:髒讀(Dirty Read)、不可重複讀和幻讀(Phantom Read)

  1. 髒讀:讀到了其餘事務尚未提交的數據。
  2. 不可重複讀:對某數據進行讀取,發現兩次讀取的結果不一樣,也就是說沒有讀到相同的內容。這是由於有其餘事務對這個數據同時進行了修改或刪除。
  3. 幻讀:事務A根據條件查詢獲得了N條數據,但此時事務B更改或者增長了M條符合事務A查詢條件的數據,這樣事務A再次進行查詢的時候會發現會有N+M條數ujuu,產生了幻讀。

 

  • 事務隔離的級別有哪些?

 

髒讀

不可重複讀

幻讀

讀未提交(READ UNCOMMITTED)

容許

容許

容許

讀已提交(READ COMMITTED)

禁止

容許

容許

可重複讀(REPEATABLE READ)

禁止

禁止

容許

可串行化(SERIALIZABLE)

禁止

禁止

禁止

讀未提交,也就是容許讀到未提交的數據,這種狀況下查詢是不會使用鎖的,可能會產生髒讀、不可重複 讀、幻讀等狀況。

讀已提交就是隻能讀到已經提交的內容,能夠避免髒讀的產生,屬於RDBMS中常⻅的默認隔離級別(好比說Oracle和SQL Server),但若是想要避免不可重複讀或者幻讀,就須要咱們在SQL查詢的時候編寫帶加鎖 的SQL語句(我會在進階篇裏講加鎖)。

可重複讀,保證一個事務在相同查詢條件下兩次查詢獲得的數據結果是一致的,能夠避免不可重複讀和髒讀,但沒法避免幻讀。MySQL默認的隔離級別就是可重複讀

可串行化,將事務進行串行化,也就是在一個隊列中按照順序執行,可串行化是最高級別的隔離等級,能夠解決事務讀取中全部可能出現的異常狀況,可是它犧牲了系統的併發性。

 

遊標

遊標,一種靈活的操做方式,可讓咱們從數據結果集中每次提取一條數據記錄進行操做。

在SQL中,遊標是一種臨時的數據庫對象,能夠指向存儲在數據庫表中的數據行指針。這裏遊標充當了指針的做用,能夠經過操做遊標來對數據行進行操做。

 

  • 如何使用遊標?

通常須要經歷五個步驟。不一樣DBMS中,使用遊標的語法可能略有不一樣。

一、定義遊標

// 適用於MySQL,SQL Server,DB2和MariaDB DECLARE cursor_name CURSOR FOR select_statement  // Oracle / PostgreSQL DECLARE cursor_name CURSOR IS select_statement

二、打開遊標

OPEN cursor_name

三、從遊標中取得數據

FETCH cursor_name INTO var_name ...

這句話的做用是使用cursor_name這個遊標來讀取當前行,而且將數據保存到var_name這個變量中,遊標指針指到下一行。若是遊標讀取的數據行有多個列明,則在INTO關鍵字後面賦值多個變量名便可。

四、關閉遊標

CLOSE cursor_name

五、釋放遊標

DEALLOCATE PREPARE

 

  • 簡單例子

假設想用遊標掃描heros數據表中的數據行,而後累計最大生命值。

CREATE PROCEDURE `calc_hp_max`() BEGIN  -- 建立接收遊標的變量  DECLARE hp INT;  -- 建立總數變量  DECLARE hp_sum INT DEFAULT 0;  -- 建立結束標誌變量  DECLARE done INT DEFAULT false;  -- 定義遊標  DECLARE cur_hero CURSOR SELECT hp_max FROM heros;   OPEN cur_hero;  read_loop:LOOP  FETCH cur_hero INTO hp;  -- 判斷遊標的訓話是否結束  IF done THEN  LEAVE read_loop;  END IF   SET hp_sum = hp_sum + hp;  END LOOP;  CLOSE cur_hero  SELECT hp_sum;  DEALLOCATE PREPARE cur_hero;  END

 

  • 遊標性能
    • 好處:靈活性強,能夠解決複雜的數據處理問題,對數據進行逐行掃描處理
    • 不足:使用遊標的過程當中會對數據進行加鎖,當業務併發量大的時候,會影響到業務的效率。同時遊標是在內存中進行的處理,會消耗系統資源,容易形成內存補足。
    • 建議:一般遊標有替代方案的時候,能夠採用替代方案,若是實在繞不開有時候仍是會用到遊標。
相關文章
相關標籤/搜索