1. 程式人生 > 其它 >MySQL中的一些方法

MySQL中的一些方法

觸發器

觸發器,字面意思達到某個條件後自動觸發
在MySQL中對觸發器的說明是:針對表繼續進行增刪改操作可以自動觸發
    主要有六種情況:分別是增、刪、改操作的前後、
create trigger 觸發器名稱 before/after insert/update/delete on 表名 for each row 
begin
    sql語句
end

1.觸發器的命名規律  # tri(表名是觸發器)_什麼時候觸發_什麼操作_表名
    tri_before_insert_t1  
    tri_after_delete_t2
    tri_after_update_t2
2.臨時修改SQL語句的結束符
    delimiter $$  # 修改結束符為$$
    
    
觸發器的實際應用
CREATE TABLE cmd (
    id INT PRIMARY KEY auto_increment,
    USER CHAR (32),
    priv CHAR (10),
    cmd CHAR (64),
    sub_time datetime, #提交時間
    success enum ('yes', 'no') #0代表執行失敗
);

CREATE TABLE errlog (
    id INT PRIMARY KEY auto_increment,
    err_cmd CHAR (64),
    err_time datetime
);

delimiter $$  # 將mysql預設的結束符由;換成$$
create trigger tri_after_insert_cmd after insert on cmd for each row
begin
    if NEW.success = 'no' then  # 新記錄都會被MySQL封裝成NEW物件
        insert into errlog(err_cmd,err_time) values(NEW.cmd,NEW.sub_time);
    end if;
end $$
delimiter ;  # 結束之後記得再改回來,不然後面結束符就都是$$了

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

# 查詢errlog表記錄
select * from errlog;
# 檢視所有的觸發器
show triggers;
# 刪除觸發器
drop trigger tri_after_insert_cmd;

事物

1.事物的四大特性(ACID)(重點)
    A:原子性
        事務中的各項操作是一個不可分割的整體,要麼同時成功要麼同時失敗
    C:一致性
        使資料庫從一個一致性狀態變為另一個一致性狀態
    I:隔離性
        多個事物之間彼此互不干擾
    D:永續性
        也可以稱之為永久性,一個事物一道提交,那麼他對資料庫中資料的改變就應該是永久的
        
create table user(
id int primary key auto_increment,
name char(32),
balance int
);

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

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

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

# 回滾到上一個狀態
rollback;

# 開啟事務之後,只要沒有執行commit操作,資料其實都沒有真正重新整理到硬碟
commit;

"""
事務相關關鍵字
	start transaction;  開啟事物操作
	rollback            回滾到上一個狀態
	commit              將資料真正重新整理到硬碟
	savepoint           儲存事物節點,就是儲存事物當前狀態
"""

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

InnoDB的MVCC通過在每行記錄後面儲存兩個隱藏的列來實現MVCC
	一個列儲存了行的建立時間
  一個列儲存了行的過期時間(或刪除時間)  # 本質是系統版本號
每開始一個新的事務版本號都會自動遞增,事務開始時刻的系統版本號會作為事務的版本號用來和查詢到的每行記錄版本號進行比較

例如
剛插入第一條資料的時候,我們預設事務id為1,實際是這樣儲存的
    username		create_version		delete_version
    jason						1					
可以看到,我們在content列插入了kobe這條資料,在create_version這列儲存了1,1是這次插入操作的事務id。
然後我們將jason修改為jason01,實際儲存是這樣的
    username		create_version		delete_version
    jason						1									2
    jason01					2
可以看到,update的時候,會先將之前的資料delete_version標記為當前新的事務id,也就是2,然後將新資料寫入,將新資料的create_version標記為新的事務id
當我們刪除資料的時候,實際儲存是這樣的
		username		create_version		delete_version
    jason01					2									 3
"""
由此當我們查詢一條記錄的時候,只有滿足以下兩個條件的記錄才會被顯示出來:
   1.當前事務id要大於或者等於當前行的create_version值,這表示在事務開始前這行資料已經存在了。
   2.當前事務id要小於delete_version值,這表示在事務開始之後這行記錄才被刪除。
"""

儲存過程

可以看成是python中自定義的函式

# 無參函式
delimiter $$
create procedure p1() 
begin
	select * from cmd;
end $$
delimiter ;

# 呼叫
call p1()


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

# 針對res需要先提前定義
set @res=10;  定義
select @res;  檢視
call p1(1,5,@res)  呼叫
select @res  檢視

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

# 大前提:儲存過程在哪個庫下面建立的就只能在對應的庫下面才能使用!!!

# 1、直接在mysql中呼叫
set @res=10  # res的值是用來判斷儲存過程是否被執行成功的依據,所以需要先定義一個變數@res儲存10
call p1(2,4,10);  # 報錯
call p1(2,4,@res);  

# 檢視結果
select @res;  # 執行成功,@res變數值發生了變化

# 2、在python程式中呼叫
pymysql連結mysql
產生的遊表cursor.callproc('p1',(2,4,10))  # 內部原理:@_p1_0=2,@_p1_1=4,@_p1_2=10;
cursor.excute('select @_p1_2;')

流程控制

# 分支結構
declare i int default 0;
IF i = 1 THEN
	SELECT 1;
ELSEIF i = 2 THEN
	SELECT 2;
ELSE
	SELECT 7;
END IF;

# 迴圈結構
DECLARE num INT ;
SET num = 0 ;
WHILE num < 10 DO
	SELECT num ;
	SET num = num + 1 ;
END WHILE ;

函式

可以看成是python中的內建函式

"ps:可以通過help 函式名    檢視幫助資訊!"
1.移除指定字元
Trim、LTrim、RTrim

2.大小寫轉換
Lower、Upper

3.獲取左右起始指定個數字元
Left、Right

4.返回讀音相似值(對英文效果)
Soundex
"""
eg:客戶表中有一個顧客登記的使用者名稱為J.Lee
		但如果這是輸入錯誤真名其實叫J.Lie,可以使用soundex匹配發音類似的
		where Soundex(name)=Soundex('J.Lie')
"""

5.日期格式:date_format
'''在MySQL中表示時間格式儘量採用2022-11-11形式'''
CREATE TABLE blog (
    id INT PRIMARY KEY auto_increment,
    NAME CHAR (32),
    sub_time datetime
);
INSERT INTO blog (NAME, sub_time)
VALUES
    ('第1篇','2015-03-01 11:31:21'),
    ('第2篇','2015-03-11 16:31:21'),
    ('第3篇','2016-07-01 10:21:31'),
    ('第4篇','2016-07-22 09:23:21'),
    ('第5篇','2016-07-23 10:11:11'),
    ('第6篇','2016-07-25 11:21:31'),
    ('第7篇','2017-03-01 15:33:21'),
    ('第8篇','2017-03-01 17:32:21'),
    ('第9篇','2017-03-01 18:31:21');
select date_format(sub_time,'%Y-%m'),count(id) from blog group by date_format(sub_time,'%Y-%m');

1.where Date(sub_time) = '2015-03-01'
2.where Year(sub_time)=2016 AND Month(sub_time)=07;
# 更多日期處理相關函式 
	adddate	增加一個日期 
	addtime	增加一個時間
	datediff計算兩個日期差值