1. 程式人生 > 其它 >MySQL事務、觸發器、檢視與儲存過程

MySQL事務、觸發器、檢視與儲存過程

目錄

事務

# 事務(重要)
	ACID
    	A:原子性
        C:一致性
        I:隔離性
        D:永續性
原子性(atomicity)
	一個事務是一個不可分割的工作單位,事務中包括的諸操作要麼都做,要麼都不做。
一致性(consistency)
	事務必須是使資料庫從一個一致性狀態變到另一個一致性狀態。一致性與原子性是密切相關的。
隔離性(isolation)
	一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的資料對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。
永續性(durability)
	永續性也稱永久性(permanence),指一個事務一旦提交,它對資料庫中資料的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響
    
    
事務相關操作
	start transcation;  # 開啟事務
  	諸多SQL操作
    rollback  # 回滾到操作之前的狀態
    commit  # 確認事務操作 之後不能回滾

案例:

create table user(
id int primary key auto_increment,
name char(32),
balance int
);

insert into user(name,balance)
values
('jason',1000),
('egon',1000),
('tank',1000);

# 修改資料之前先開啟事務操作
start transaction;

# 修改操作
update user set balance=900 where name='jason'; #買支付100元
update user set balance=1010 where name='egon'; #中介拿走10元
update user set balance=1090 where name='tank'; #賣家拿到90元

# 回滾到上一個狀態
rollback;

# 開啟事務之後,只要沒有執行commit操作,資料其實都沒有真正重新整理到硬碟
commit;
"""開啟事務檢測操作是否完整,不完整主動回滾到上一個狀態,如果完整就應該執行commit操作"""

# 站在python程式碼的角度,應該實現的虛擬碼邏輯,
try:
    update user set balance=900 where name='jason'; #買支付100元
    update user set balance=1010 where name='egon'; #中介拿走10元
    update user set balance=1090 where name='tank'; #賣家拿到90元
except 異常:
    rollback;
else:
    commit;

檢視

1.什麼是檢視?

檢視就是通過查詢得到一張虛擬表,然後儲存下來,下次直接使用即可。

2.為什麼要用檢視?

如果要頻繁使用一張虛擬表,可以不用重複查詢。

3.如何使用檢視

正常兩張表連線情況(拼接)查詢
select * from emp inner join dep on emp.id=dep.id; 

使用內連線:
	inner join	: 連線兩表中都存在(對應關係)的資料
	
dep	: 部門表		emp : 員工詳細表

4.反覆拼接的繁瑣(引入檢視的作用)

反覆拼接繁瑣之處:
當我們頻繁的去查詢連表,反覆拼接,會出現繁瑣的現象,影響效率。

5.解決方法

如果要頻繁使用一張虛擬表,可以不用重複查詢,而使用檢視來進行操作,將拼接的連表儲存起來。

二:檢視的應用

1.建立檢視的格式:

create view 建立檢視名字 as 執行連表的SQL語句

2.刪除視圖表

刪除視圖表格式:
	drop view 檢視名;

觸發器

1.什麼時觸發器?

在滿足對某張表資料的增,刪,改的情況下,自動觸發的功能稱之為觸發器

2.為何要用觸發器?

觸發器專門針對我們對某一張表的增insert,刪delete,改update的行為,這類行為一旦執行
就會觸發觸發器的執行,既自動執行另外一段sql語句。

3.觸發器trigger

觸發器:滿足特點條件之後自動執行
在MySQL只有三種情況下可以觸發
	1.針對表的增
    	增前 增後
    2.針對表的改
    	改前 改後
    3.針對表的刪
    	刪前 刪後

4.觸發器語法結構

create trigger 觸發器的名字 before/after insert/update/delete on 表名 for each row
begin
	sql語句
end

5.觸發器名字在命名的時候推薦使用下列的方式(見名知意)

tri_after_insert_t1				tri_before_delete_t1

6.觸發器三種狀態(六種演示)

增加:
create trigger tri_after_insert_t1 after insert on 表名 for each row
begin
	 sql語句
end	 # 增加之後觸發

create trigger tri_before_insert_t1 before insert on 表名 for each row
begin
	 sql語句
end  # 增加之前觸發


修改:
create trigger tri_after_update_t1 after update on 表名 for each row
begin
	 sql語句
end  # 修改之後觸發

create trigger tri_before_insert_t1 before insert on 表名 for each row
begin
	sql語句
end # 修改之前觸發


刪除:
create trigger tri_after_delete_t1 after delete on 表名 for each row
begin
	sql語句
end # 刪除之前觸發

create trigger tri_before_delete_t1 defore delete on 表名 for each row

begin
	sql語句
end # 刪除之後觸發

7.注意事項(臨時更換結束符)

需要注意 在書寫sql程式碼的時候結束符是; 而整個觸發器的結束符也是;
這就會出現語法衝突 需要我們臨時修改結束符號

臨時修改結束符格式:
	delimiter 名字
	
delimiter $$
臨時修改sql語句結束符,該語法只在當前視窗有效

四:觸發器實戰案例

1.1.MySQL中NEW作用

在MySQL中NEW特指資料物件可以通過點的方式獲取欄位對應的資料
	id    name	pwd  hobby
	1     jason  123  read
	NEW.name  >>>  jason

2.建立cmd命令表與報錯日誌

# 模擬cmd命令表
CREATE TABLE cmd (
    id INT PRIMARY KEY auto_increment,
    USER CHAR (32),
    priv CHAR (10),
    cmd CHAR (64),     # cmd命令欄位
    sub_time datetime, # 提交時間
    success enum ('yes', 'no') #0代表執行失敗
);

# 報錯日誌表
CREATE TABLE errlog (
    id INT PRIMARY KEY auto_increment,
    err_cmd CHAR (64),
    err_time datetime
);

3.建立觸發器

1.建立之前修改結束符
delimiter $$  # 將mysql預設的結束符由;換成$$
# 建立觸發器
create trigger tri_after_insert_cmd after insert on cmd for each row
begin
	# 觸發器啟動 判斷cmd中success欄位內容記錄是否為no,為no則執行以下程式碼
    if NEW.success = 'no' then  # 新記錄都會被MySQL封裝成NEW物件
        insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time);
    end if;
end $$
2.建立之後修改結束符
delimiter ;  # 結束之後記得再改回來,不然後面結束符就都是$$了。

4.cmd表內插入記錄(資料)

#往表cmd中插入記錄,觸發觸發器,根據IF的條件決定是否插入錯誤日誌
INSERT INTO cmd (
    USER,
    priv,
    cmd,
    sub_time,
    success
)
VALUES
    ('tony','0755','ls -l /etc',NOW(),'yes'),
    ('tony','0755','cat /etc/passwd',NOW(),'no'),
    ('tony','0755','useradd xxx',NOW(),'no'),
    ('tony','0755','ps aux',NOW(),'yes');

5.驗證觸發器(查詢結果)

查詢errlog表記錄
select * from errlog;

解析:
	1.當cmd命令列後臺被插入資料時,if判斷出現為‘on’ 報錯的資料時
	2.會自動觸發 觸發器會執行程式碼,將為‘on’錯誤程式碼 插入到《errlog報錯日誌》

6.檢視觸發器

show triggers\G;  # 格式化展示

7.刪除觸發器

drop trigger tri_after_insert_cmd;

儲存過程

1.什麼是儲存過程?

儲存過程包含了一系列可執行的sql語句,儲存過程存放於MySQL中,通過呼叫它的名字可以執行其內部的一堆sql,類似於python中的自定義函式。

2.儲存過程格式

關鍵字: procedure
格式:
create procedure 函式名(引數)
begin
	功能體程式碼
end

呼叫其內部sql程式碼格式
call 函式名()
  • 類似於python中的自定義函式

3.無參儲存過程

delimiter $$  # 修改結束符
create procedure p1()
begin
	select * from user;
end $$
delimiter ;  # 修改回來結束符

# 通過p1()呼叫其內部sql程式碼
call p1();

4.有參儲存過程

delimiter $$
create procedure p2(
    in m int,  # in表示這個引數必須只能是傳入不能被返回出去
    in n int,  
    out res int  # out表示這個引數可以被返回出去,還有一個inout表示即可以傳入也可以被返回出去
)
begin
    select * from user where id > m and id < n;
    set res=0;  # 用來標誌儲存過程是否執行
end $$
delimiter ;


# 針對res需要提前定義
set @res=10;  # 定義/賦值  # 指定res=10
select @res;  # 檢視
call p2(1,3,@res);  # 呼叫
select @res;  # 呼叫

5.檢視儲存過程-檢視所有儲存過程-刪除儲存過程

檢視儲存過程具體資訊
show create procedure status;
檢視所有儲存過程
show procedure status;
刪除儲存過程
drop procedure pro2;

6.pyMySQL程式碼呼叫儲存過程

import pymysql

# 建立連結
conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    passwd='123',
    db='db6',
    charset='utf8',
    autocommit=True  # 涉及到增刪改,二次確認
)

# 生成一個遊標物件(操作資料庫)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 呼叫儲存過程固定語法callproc('p2',(1,3,10))
cursor.callproc('p2',(1,3,10))  # 內部原理 @_p1_0=1,@_p1_1=3,@_p1_2=10;
# 檢視結果
print(cursor.fetchall())

隔離級別

在SQL標準中定義了四種隔離級別,每一種級別都規定了一個事務中所做的修改
InnoDB支援所有隔離級別
	set transaction isolation level 級別

1.read uncommitted(未提交讀)
	事務中的修改即使沒有提交,對其他事務也都是可見的,事務可以讀取未提交的資料,這一現象也稱之為"髒讀"
2.read committed(提交讀)
	大多數資料庫系統預設的隔離級別
  一個事務從開始直到提交之前所作的任何修改對其他事務都是不可見的,這種級別也叫做"不可重複讀"
3.repeatable read(可重複讀)		# MySQL預設隔離級別
	能夠解決"髒讀"問題,但是無法解決"幻讀"
  所謂幻讀指的是當某個事務在讀取某個範圍內的記錄時另外一個事務又在該範圍內插入了新的記錄,當之前的事務再次讀取該範圍的記錄會產生幻行,InnoDB和XtraDB通過多版本併發控制(MVCC)及間隙鎖策略解決該問題
4.serializable(可序列讀)
	強制事務序列執行,很少使用該級別