mysql數據庫學習二

  最近又複習了mysql中的一些概念:視圖,觸發器,存儲過程,函數,事務,記錄下。html

1.視圖前端

  視圖是一個虛擬表,自己並不存儲數據,當sql在操做視圖時全部數據都是從其餘表中查出來的,所以其本質是:根據SQL語句獲取動態的數據集,併爲其命名,用戶使用時只需使用【名稱】便可獲取結果集,並能夠將其看成表來使用。python

視圖操做:mysql

-- CREATE TABLE students(
--         nid INT NOT NULL AUTO_INCREMENT,
--         name VARCHAR(128) NOT NULL,
--         gender CHAR(8) NOT NULL,
--         age INT NOT NULL,
--         class VARCHAR(64) NOT NULL,
--         PRIMARY KEY (nid)
-- )DEFAULT CHARSET=utf8;

-- INSERT INTO students(name, gender,age,class) VALUES('李木','',24,'python班');

-- INSERT INTO students(name, gender,age,class) 
-- VALUES('王華','',26,'python班'),
-- ('王鈺','',22,'前端');



-- 建立並使用視圖view1
-- SELECT * FROM (SELECT nid,name FROM students WHERE nid>1) AS view1 WHERE view1.name="王華";

-- 建立視圖格式: CREATE VIEW 視圖名稱 AS sql語句;
-- CREATE VIEW view1 AS SELECT nid, name FROM students WHERE nid>1;

-- 修改視圖格式:ALTER VIEW 視圖名稱 AS sql語句;
-- ALTER VIEW view1 AS SELECT nid,name FROM students WHERE name="李木";

-- 使用視圖:使用視圖時,將其看成表進行操做便可,因爲視圖是虛擬表,因此沒法使用其對真實表進行建立、更新和刪除操做,僅能作查詢用。
-- SELECT * FROM view1;

-- 刪除視圖格式:DROP VIEW 視圖名稱;
-- DROP VIEW view1;
視圖操做

 2.觸發器git

   對某個表行進行增刪改操做,若是但願操做先後觸發某些特定的操做,即可以使用觸發器。觸發器就像信號或中間件相似,能夠定製特定的操做,注意的是行操做觸發。github

觸發器操做:算法

-- 建立觸發器語法
 
每一行插入前觸發
CREATE TRIGGER tri_before_insert_table BEFORE INSERT ON students FOR EACH ROW;
BEGIN

END

插入後觸發
CREATE TRIGGER tri_after_insert_table AFTER INSERT ON students FOR EACH ROW;
BEGIN

END


刪除前觸發
CREATE TRIGGER tri_before_delete_table BEFORE DELETE ON students FOR EACH ROW;
BEGIN

END

刪除後觸發
CREATE TRIGGER tri_after_delete_table AFTER DELETE ON students FOR EACH ROW;
BEGIN

END

更新前觸發
CREATE TRIGGER tri_before_update_table BEFORE UPDATE ON students FOR EACH ROW;
BEGIN

ON
更新後觸發
CREATE TRIGGER tri_after_update_table AFTER UPDATE ON students FOR EACH ROW;
BEGIN
觸發器語法

觸發器使用示例sql

CREATE TABLE class(
    nid INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(64) NOT NULL,
    count INT NOT NULL,
    PRIMARY KEY (nid)
) DEFAULT CHARSET = utf8

INSERT INTO class(name,count) VALUES("python班",45),("算法班",50);

建立插入前觸發器
NEW表示即將新插入的行
delimiter //
CREATE TRIGGER tri_before_insert BEFORE INSERT ON students FOR EACH ROW
BEGIN
    IF
        NEW.class = "前端" THEN
            INSERT INTO class ( name,count )
        VALUES
            ( "前端",1 ) ;
    END IF;
END// 
delimiter;

建立插入後觸發器
delimiter //
CREATE TRIGGER tri_after_insert AFTER INSERT ON students FOR EACH ROW 
BEGIN
    IF NEW.class="python" THEN
        INSERT INTO class(name,count) VALUES("python",1);
    ELSEIF NEW.class = "數據結構" THEN
        INSERT INTO class(name,count) VALUES("數據結構",2);
    END IF;
END//
delimiter;

使用觸發器(插入一行數據時觸發)
insert into students(name,gender,age,class)values('李曼',"",25,"python");
insert into students(name,gender,age,class)values('王軍',"",25,"數據結構");

刪除觸發器
DROP TRIGGER tri_before_insert;
觸發器示例

(觸發器中,NEW表示即將插入的數據行,OLD表示即將刪除的數據行。)數據庫

觸發器性能:https://segmentfault.com/q/1010000004907411segmentfault

      https://www.cnblogs.com/geaozhang/p/6819648.html

3. 存儲過程

  存儲過程是一組SQL語句集合,通過編譯建立並保存在數據庫中,用戶能夠經過指定存儲過程的名字並給定參數(若須要時)來調用。當調用存儲過程時,其內部的SQL語句會按邏輯順序執行。

建立存儲過程:

--建立存儲過程
delimiter // 
CREATE PROCEDURE p1()
BEGIN
    SELECT * FROM    students WHERE class = "前端";
END // 
delimiter;

--調用存儲過程
call p1()
建立和使用存儲過程

存儲過程還能夠接受參數,包括三類參數:

  • in          僅用於傳入參數用
  • out        僅用於返回值用
  • inout     既能夠傳入又能夠看成返回值
-- 傳入和傳出參數

delimiter //
CREATE PROCEDURE p2(
    IN i1 INT,
    IN i2 INT,
    INOUT i3 INT,
    OUT i4 INT
)
BEGIN
DECLARE temp1 INT;
DECLARE temp2 INT DEFAULT 0;
SET temp1=1;
SET i4 =i1+i2+temp1+temp2;
set i3 = i3+100;
END//
delimiter;

-- 執行存儲過程p2()
SET @t1=4;
SET @t2=5;
CALL p2(1,2,@t1,@t2);
SELECT @t1,@t2;

-- 輸出結果
-- @t1,@t2
-- 104, 4
傳入參數

經過存儲過程的返回值,能夠用來判斷其執行狀態,以下:

-- 支持事務(經過返回值能判斷執行的狀態)
delimiter//
CREATE PROCEDURE p3(
    OUT p_return_code TINYINT
)
BEGIN
-- 出現錯誤
DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
    set p_return_code=1;
    ROLLBACK;
    END;
-- 出現警告
DECLARE EXIT HANDLER FOR SQLWARNING
    BEGIN
    set p_return_code=2;
    ROLLBACK;
    END;
START TRANSACTION;
    DELETE FROM class;
    INSERT INTO students(name,gender,age,class) VALUES("宋紅雲","",23,"python");
COMMIT;
-- 成功執行
SET p_return_code = 0;
END//
delimiter;

SET @r1 = -1;
CALL p3(@r1);
SELECT @r1;
-- 輸出結果 @r1=0
存儲過程當中事務執行狀態

存儲過程使用遊標

-- 使用遊標
delimiter//
CREATE PROCEDURE p4()
BEGIN
DECLARE sage INT;
DECLARE sname VARCHAR(128);
DECLARE done INT DEFAULT FALSE;

DECLARE my_cursor CURSOR FOR SELECT name,age FROM students;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done =TRUE;

OPEN my_cursor;
    myloop: LOOP
     FETCH my_cursor INTO sname,sage;
         IF done THEN
             LEAVE myloop;
       END IF; 
         INSERT INTO class(cname) values(sname);
  END LOOP myloop;
CLOSE my_cursor;
END//
delimiter;

CALL p4();
使用遊標

利用prepare,execute,dellocate, 能夠實現動態執行SQL語句,同時對SQL語句進行檢查,防治SQL注入(?爲查詢條件中佔位符)

delimiter//
CREATE PROCEDURE p5(
    IN i INT
)
BEGIN
    SET @i2 = i;
    PREPARE prod FROM "select * from students where nid=? ";
    EXECUTE prod USING @i2;  
-- 變量只能是SET @i2 = value的變量,傳入和declare的變量不行
    DEALLOCATE PREPARE prod;

END//
delimiter;

CALL p5(2);

-- sql注入:
-- sql = "select * from students where name="+i+";"
-- 若是採用上面字符竄拼接sql語句時,當用戶輸入的i="ss or 1=1",則where語句確定爲TRUE,會拿到全部的name數據
動態執行sql

上述語句中注意EXECUTE prod USING @i1,@i2;能夠傳入多個查詢變量,和佔位符按順序對應,並且變量只能是變量只能是SET @i2 = value的變量,傳入和declare的變量不行。

python中經過pymysql模塊也能夠調用存儲過程

#coding:utf-8

import pymysql

conn = pymysql.connect(host="localhost",port=3306,db="learningsql",user="root",passwd="",charset="utf8")

cursor = conn.cursor()
#cursor = conn.cursor(cursor = pymysql.cursors.DictCursors)  最後返回的結果,每一行爲字典
cursor.callproc("p5",args=(1,))

#執行須要參數的存儲過程
# a,b=0,0
# cursor.callproc("p2",args=(1,2,a,b))
# cursor.execute("select @_p2_0,@_p2_1,@_p2_3,@_p2_4")  #拿到第1,2,3,4個參數。。。。


result = cursor.fetchall()
cursor.close()
conn.close()

print(result)
pymysql執行調用存儲過程

4.函數

  內置函數:https://dev.mysql.com/doc/refman/5.7/en/functions.html(官方文檔)

經常使用內置函數

CHAR_LENGTH(str)
        返回值爲字符串str 的長度,長度的單位爲字符。一個多字節字符算做一個單字符。
        對於一個包含五個二字節字符集, LENGTH()返回值爲 10, 而CHAR_LENGTH()的返回值爲5。

length:   是計算字段的長度,一個漢字是算兩個或三個字符,一個數字或字母算一個字符;

char_length:無論漢字仍是數字或者是字母都算是一個字符;


    CONCAT(str1,str2,...)
        字符串拼接
        若有任何一個參數爲NULL ,則返回值爲 NULL。
    CONCAT_WS(separator,str1,str2,...)
        字符串拼接(自定義鏈接符)
        CONCAT_WS()不會忽略任何空字符串。 (然而會忽略全部的 NULL)。

    CONV(N,from_base,to_base)
        進制轉換
        例如:
            SELECT CONV('a',16,2); 表示將 a 由16進制轉換爲2進制字符串表示

    FORMAT(X,D)
        將數字X 的格式寫爲'#,###,###.##',以四捨五入的方式保留小數點後 D 位, 並將結果以字符串的形式返回。若  D 爲 0, 則返回結果不帶有小數點,或不含小數部分。
        例如:
            SELECT FORMAT(12332.1,4); 結果爲: '12,332.1000'
    INSERT(str,pos,len,newstr)
        在str的指定位置插入字符串
            pos:要替換位置其實位置
            len:替換的長度
            newstr:新字符串
        特別的:
            若是pos超過原字符串長度,則返回原字符串
            若是len超過原字符串長度,則由新字符串徹底替換
    INSTR(str,substr)
        返回字符串 str 中子字符串的第一個出現位置。

    LEFT(str,len)
        返回字符串str 從開始的len位置的子序列字符。

    LOWER(str)
        變小寫

    UPPER(str)
        變大寫

    LTRIM(str)
        返回字符串 str ,其引導空格字符被刪除。
    RTRIM(str)
        返回字符串 str ,結尾空格字符被刪去。
    SUBSTRING(str,pos,len)
        獲取字符串子序列

    LOCATE(substr,str,pos)
        獲取子序列索引位置

    REPEAT(str,count)
        返回一個由重複的字符串str 組成的字符串,字符串str的數目等於count 。
        若 count <= 0,則返回一個空字符串。
        若str 或 count 爲 NULL,則返回 NULL 。
    REPLACE(str,from_str,to_str)
        返回字符串str 以及全部被字符串to_str替代的字符串from_str 。
    REVERSE(str)
        返回字符串 str ,順序和字符順序相反。
    RIGHT(str,len)
        從字符串str 開始,返回從後邊開始len個字符組成的子序列

    SPACE(N)
        返回一個由N空格組成的字符串。

    SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
        不帶有len 參數的格式從字符串str返回一個子字符串,起始於位置 pos。帶有len參數的格式從字符串str返回一個長度同len字符相同的子字符串,起始於位置 pos。 使用 FROM的格式爲標準 SQL 語法。也可能對pos使用一個負值。倘若這樣,則子字符串的位置起始於字符串結尾的pos 字符,而不是字符串的開頭位置。在如下格式的函數中能夠對pos 使用一個負值。

        mysql> SELECT SUBSTRING('Quadratically',5);
            -> 'ratically'

        mysql> SELECT SUBSTRING('foobarbar' FROM 4);
            -> 'barbar'

        mysql> SELECT SUBSTRING('Quadratically',5,6);
            -> 'ratica'

        mysql> SELECT SUBSTRING('Sakila', -3);
            -> 'ila'

        mysql> SELECT SUBSTRING('Sakila', -5, 3);
            -> 'aki'

        mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
            -> 'ki'

    TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str) TRIM(remstr FROM] str)
        返回字符串 str , 其中全部remstr 前綴和/或後綴都已被刪除。若分類符BOTH、LEADIN或TRAILING中沒有一個是給定的,則假設爲BOTH 。 remstr 爲可選項,在未指定狀況下,可刪除空格。

        mysql> SELECT TRIM('  bar   ');
                -> 'bar'

        mysql> SELECT TRIM(LEADING 'x' FROM 'xxxbarxxx');
                -> 'barxxx'

        mysql> SELECT TRIM(BOTH 'x' FROM 'xxxbarxxx');
                -> 'bar'

        mysql> SELECT TRIM(TRAILING 'xyz' FROM 'barxxyz');
                -> 'barx'

部份內置函數
內置函數

自定義函數

-- 定義函數,注意定義返回值類型
delimiter \\
CREATE FUNCTION fun(
    i1 INT,
    i2 INT
)
RETURNS INT
BEGIN
    DECLARE sum INT;
    SET sum = i1+i2;
    RETURN(sum);
END \\
delimiter ;

-- -- 經過select使用
SELECT fun(1,2);

-- -- 對查詢表字段進行函數操做
SELECT name,fun(1,age) from students;

-- 將函數結果存儲到變量
SELECT fun(1,2) INTO @sum;
SELECT @sum;

SELECT UPPER("zack") INTO @name;
SELECT @name;

-- 刪除函數
DROP FUNCTION fun;
函數定義,使用,刪除

 自定義函數時注意用戶變量,局部變量,全局變量,會話變量,參考:https://blog.csdn.net/qq_34626097/article/details/86528466

5.事務

  事務是知足 ACID 特性的一組操做,要麼所有執行,要麼所有不執行,能夠經過 Commit 提交一個事務,也可使用 Rollback 進行回滾。在mysql中,事務用於將某些操做的多個SQL操做做爲原子性操做,一旦有某一個出現錯誤,便可回滾到原來的狀態,從而保證數據庫數據完整性。

原子性(Atomicity):事務被視爲不可分割的最小單位,要麼所有執行成功,要麼所有失敗,進行回滾。(回滾能夠經過回滾日誌實現,回滾日誌記錄着事務所執行的修改操做,在回滾時反向執行這些修改操做便可。)

一致性(Consistency):數據庫在事務執行先後都保持一致性狀態。在一致性狀態下,全部事務對一個數據的讀取結果都是相同的。

隔離性(Isolation):一個事務所作修改在最終提交前,對其餘事務是不可見的。多個事務併發執行時互不影響。

持久性(Durability):一但事務提交,其所作的修改將永遠保存在數據庫中,即便系統發生崩潰,事務執行的結果也不能丟失。(能夠用重作日誌來保證持久性)

對ACID特性的理解:(幾個特性不是一種平級關係)

  • 只有知足一致性,事務的執行結果纔是正確的。
  • 在無併發的狀況下,事務串行執行,隔離性必定可以知足。此時只要能知足原子性,就必定能知足一致性。
  • 在併發的狀況下,多個事務並行執行,事務不只要知足原子性,還須要知足隔離性,才能知足一致性。
  • 事務知足持久化是爲了能應對數據庫崩潰的狀況

ACID特性

一致性狀態和中間狀態

 

   5.1 事務的併發一致性問題

    在多併發條件下,多個事務的隔離性很難保證,所以會出現不少併發一致性問題,包括丟失修改,髒讀,不可重複讀,幻讀。

    丟失修改:事務T1和T2都修改了數據,T1先修改,T2後修改,T2的修改覆蓋了T1的修改。

    髒讀:事務T1修改了數據,事務T2讀取了修改後的數據。隨後T1回滾撤銷了修改,事務T2讀取到的就是髒數據。

 

    不可重複讀:事務T2讀取一個數據,T1對數據作了修改,若是T2再次 讀取這個數據,此時讀取的結果和第一次不一致。

    幻讀:T1讀取某個範圍的數據,T2在這個範圍了插入了一條數據,T1再次讀取這個範圍了數據,和第一次讀取的結果不一樣。

    (場景:系統管理員A將數據庫中全部學生的成績從具體分數改成ABCDE等級,可是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺同樣,這就叫幻讀。)

  5.2 事務的隔離級別

  上述的併發一致性問題是因爲破壞了事務的隔離性,得經過併發控制來保證事務的隔離性。數據庫管理系統提供了事務的隔離級別來處理併發一致性問題,包括未提交讀(read uncommitted),提交讀(read committed),可重複讀(repeated read),可串行化(serilization)。(併發控制能夠經過封鎖來實現,可是封鎖操做須要用戶本身控制,至關複雜。)

  未提交讀:最低的隔離級別,什麼都不須要作,一個事務能夠讀到另外一個事務未提交的結果。全部的併發事務問題都會發生

  提交讀:只有在事務提交後,其更新結果纔會被其餘事務看見。能夠解決髒讀問題。

  可重複讀:在一個事務中,對於同一份數據的讀取結果老是相同的,不管是否有其餘事務對這份數據進行操做,以及事務是否提交。能夠解決髒讀、不可重複讀。

   可串行化:事務串行化執行,隔離級別最高,犧牲了系統的併發性。能夠解決併發事務的全部問題。

  5.3 多版本併發控制(MVCC,Multi-Version Concurrent Control)

    多版本併發控制是MySQL的InnoDB提供的一種實現隔離級別的具體方式。MVCC能夠用於實現提交讀和可重複讀。未提交讀隔離級別,老是讀取最新的數據行,無需使用 MVCC。可串行化須要對全部讀取的行都加鎖,單純使用 MVCC 沒法實現。(一句話講,MVCC就是同一份數據臨時保留多個版本/快照)

  MVCC實現機制

    1.版本號:    

      系統版本號:是一個遞增的數字,每開始一個新的事務,系統版本號就會自動遞增。(包含insert、delete和update操做的事務)

      事務版本號:事務開始時的系統版本號。

    2.隱藏的列

      MVCC 在每行記錄後面都保存着兩個隱藏的列,用來存儲兩個版本號:建立版本號和刪除版本號

      建立版本號:對該行數據建立操做時的事務版本號

                 刪除版本號:對該行數據進行刪除操做時的事務版本號

    3.實現過程(可重複讀隔離級別)  

  • select:知足如下兩個條件innodb會返回該行數據
    • 該行的建立版本號小於等於當前版本號,用於保證在select操做以前全部的操做已經執行落地。
    • 該行的刪除版本號大於當前版本或者爲空。刪除版本號大於當前版本意味着有一個併發事務將該行刪除了。
  • insert:將新插入的行的建立版本號設置爲當前系統的版本號。
  • delete:將要刪除的行的刪除版本號設置爲當前系統的版本號。
  • update:不執行原地update,而是轉換成 delete+insert。將舊行的刪除版本號設置爲當前系統版本號,並將新行insert,同時設置建立版本號爲當前系統版本號。
  • 在寫操做(insert、delete和update)執行後,須要將系統版本號遞增
  • 因爲舊數據並不真正的刪除,因此必須對這些數據進行清理,innodb會開啓一個後臺線程執行清理工做,具體的規則是將刪除版本號小於當前系統版本的行刪除,這個過程叫作purge。

   4.undo日誌

    MVCC 使用到的快照存儲在 Undo 日誌中,該日誌經過回滾指針把一個數據行(Record)的全部快照鏈接起來。

   (TRX_ID: 事務版本號,爲3時表示最新版本快照,經過回滾指針依次指向2,1,版本號)

    

  5.4 Next-key locks

    參考:https://www.cnblogs.com/zhoujinyi/p/3435982.html

       http://hedengcheng.com/?p=771

       https://zhuanlan.zhihu.com/p/35477890

   Next-Key Locks是MySQL的InnoDb的一種鎖實現。MVCC不能解決幻讀問題,Next-Key Locks 就是爲了解決這個問題而存在的。在可重複讀隔離級別下,MVCC+Next-Key Locks能夠解決幻讀問題。Next-Key Locks是Record Locks和Gap Locks的結合。

   Record Locks:鎖定一個記錄上的索引,而不是記錄自己。(若是表沒有設置索引,InnoDB 會自動在主鍵上建立隱藏的聚簇索引,所以 Record Locks 依然可使用。)

   Gap Locks:鎖定索引之間的間隙,可是不包含索引自己。例如當一個事務執行如下語句,其它事務就不能在 t.c 中插入 15。

      SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;

   Next-Key Locks:不只鎖定一個記錄上的索引,也鎖定索引之間的間隙。例如一個索引包含如下值:10, 11, 13, and 20,那麼就須要鎖定如下區間:

      (negative infinity, 10]
      (10, 11]       (11, 13]       (13, 20]       (20, positive infinity)

   索引在[10,20]區間會被鎖定,鎖定後對該區間的操做都會被阻塞

   5.5 封鎖

    5.5.1封鎖粒度:

      MySQL提供了兩種封鎖粒度:行級鎖和表級鎖。 在選擇封鎖粒度時,須要在鎖開銷和併發程度之間作一個權衡。由於鎖定的數據量越少,發生鎖爭用的可能就越小,系統的併發程度就越高。可是加鎖須要消耗資源,鎖的各類操做(包括獲取鎖、釋放鎖、以及檢查鎖狀態)都會增長系統開銷。所以封鎖粒度越小,系統開銷就越大。

    5.5.2封鎖類型:

      a.讀寫鎖:

                       排它鎖(Exclusive),簡寫爲 X 鎖,又稱寫鎖。

          一個事務對數據對象 A 加了 X 鎖,就能夠對 A 進行讀取和更新。加鎖期間其它事務不能對 A 加任何鎖。

                       共享鎖(Shared),簡寫爲 S 鎖,又稱讀鎖。

          一個事務對數據對象 A 加了 S 鎖,能夠對 A 進行讀取操做,可是不能進行更新操做。加鎖期間其它事務能對 A 加 S 鎖,可是不能加 X 鎖。

      兼容性

 

      b .意向鎖:        

      使用意向鎖(Intention Locks)能夠更容易地支持多粒度封鎖。

      在存在行級鎖和表級鎖的狀況下,事務 T 想要對錶 A 加 X 鎖,就須要先檢測是否有其它事務對錶 A 或者表 A 中的任意一行加了鎖,那麼就須要對錶 A 的每一行都檢測一次,這是很是耗時的。

      意向鎖在原來的 X/S 鎖之上引入了 IX/IS,IX/IS 都是表鎖,用來表示一個事務想要在表中的某個數據行上加 X 鎖或 S 鎖。有如下兩個規定:

          1.  一個事務在得到某個數據行對象的 S 鎖以前,必須先得到表的 IS 鎖或者更強的鎖;

          2. 一個事務在得到某個數據行對象的 X 鎖以前,必須先得到表的 IX 鎖。

                       經過引入意向鎖,事務 T 想要對錶 A 加 X 鎖,只須要先檢測是否有其它事務對錶 A 加了 X/IX/S/IS 鎖,若是加了就表示有其它事務正在使用這個表或者表中某一行的鎖,所以事務 T 加 X 鎖失敗。

       兼容性:

           任意 IS/IX 鎖之間都是兼容的,由於它們只是表示想要對錶加鎖,而不是真正加鎖;

        S 鎖只與 S 鎖和 IS 鎖兼容,也就是說事務 T 想要對數據行加 S 鎖,其它事務能夠已經得到對錶或者表中的行的 S 鎖。

    5.5.3封鎖協議:

    參考:https://yq.aliyun.com/articles/626848

               https://yq.aliyun.com/articles/626848

     a.三級封鎖協議

       一級封鎖協議:事務T修改數據時必須加X鎖,直到T結束才能釋放。由於不能同時有兩個事務對數據修改,能夠解決丟失修改問題

       二級封鎖協議:在一級的基礎上,要求讀數據A時必須加S鎖,讀完立刻釋放鎖。由於一個事務對數據A修改時會加X鎖,就不會再加S鎖,不能               讀取數據,能夠解決髒讀問題。

       三級封鎖協議:在二級的基礎上,要求讀取數據A時必須加S鎖,直到事務結束時才能釋放鎖。由於讀數據A時一直有S鎖,不能再加X鎖,保證了              數據不會改變,能夠解決不可重複讀問題

         b.兩段鎖協議:加鎖和解鎖分爲兩個階段進行。

          可串行化調度是指,經過併發控制,使得併發執行的事務結果與某個串行執行的事務結果相同。

          事務遵循兩段鎖協議是保證可串行化調度的充分條件

   5.5.4隱式鎖和顯式鎖:MySQL 的 InnoDB 存儲引擎採用兩段鎖協議,會根據隔離級別在須要的時候自動加鎖,而且全部的鎖都是在同一時刻被釋放,這被  稱爲隱式鎖定。InnoDB 也可使用特定的語句進行顯示鎖定。(SELECT ... LOCK In SHARE MODE;

  5.6 事務語句

    start transaction........commit;

    失敗時rollback

delimiter \\
create PROCEDURE p1(
    OUT p_return_code tinyint
)
BEGIN 
  DECLARE exit handler for sqlexception 
  BEGIN 
    -- ERROR 
    set p_return_code = 1; 
    rollback; 
  END; 
 
  DECLARE exit handler for sqlwarning 
  BEGIN 
    -- WARNING 
    set p_return_code = 2; 
    rollback; 
  END; 
 
  START TRANSACTION; 
    DELETE from tb1;
    insert into tb2(name)values('seven');
  COMMIT; 
 
  -- SUCCESS 
  set p_return_code = 0; 
 
  END\\
delimiter ;


使用事務
set @i=-1;
call p1(@i);
select @i;
存儲過程當中使用事務

6.條件判斷和循環語句

  條件語句:if..then.;.elseif.then.;.else..;.end if;

-- 條件判斷語句
delimiter \\
CREATE PROCEDURE p1(
    IN i INT
)
BEGIN
    IF i = 2 THEN
            SELECT * FROM students WHERE nid=2;
    ELSEIF i>2 THEN
            SELECT * FROM students WHERE nid>2;
    ELSE 
        SELECT * FROM students WHERE nid<2;
    END IF;
END\\
delimiter ;

CALL p1(2);
條件判斷語句

  循環語句:while循環,repeat循環,loop循環

-- while 循環語句
delimiter \\
CREATE PROCEDURE p2(
    IN i INT
)
BEGIN
    DECLARE sum INT;
    SET sum = 0;
    WHILE sum<10 DO
        SELECT sum;
        SET sum = sum +i;
    END WHILE;
END \\
delimiter ;

CALL p2(1);
while循環
-- repeat 循環
delimiter \\
CREATE PROCEDURE p3()
BEGIN 
    DECLARE i INT;
    SET i = 0;
    REPEAT
       SET i = i+1;
         SELECT i;
  UNTIL i>3 END REPEAT;
END \\
delimiter;

CALL p3();
repeat循環
-- loop循環
delimiter \\
CREATE PROCEDURE p4()
BEGIN
    DECLARE i INT DEFAULT 0;
    label: LOOP
    SET i = i+2;
    IF i=4 THEN
       SELECT * FROM students WHERE nid>4;
     END IF;
    IF i>6 THEN
        LEAVE label; 
    END IF;
    SELECT i;
END LOOP label;
END \\
delimiter;

CALL p4();
loop循環

 

參考:http://www.cnblogs.com/wupeiqi/articles/5713323.html

   https://github.com/CyC2018/CS-Notes

相關文章
相關標籤/搜索