MySQL(05)觸發器&事件&事務&鎖
觸發器
create triggertrigger_name
before | after insert | update | delete
on表名 for each row
trigger_body
觸發器有六種: 觸發時機before(之前)和after(之後),觸發動作insert | update | delete
提供了兩個物件new和old
insert沒有old(源) 資料物件,只有new物件 update有new和old兩種資料物件 delete沒有new只有old
create table if not exists test1 ( id intexampleprimary key auto_increment, number decimal(10,2) #設定float的精度, 10代表小數點前保留10位, 2代表小數點後只保留兩位精度 )engine innodb default charset utf8; insert into test1 values(NULL,1.22),(NULL,2.22),(NULL,3.22); #建立觸發器:限制修改表, 觸發器被建立後只能插入 0~100的資料 create trigger test_trigger before update #表資料更新前觸發 on test1for each row begin if new.number < 0 THEN set new.number = 0; elseif new.number > 100 THEN set new.number = 100; end if; end; update test1 set number=102 where id=3; select * from test1; drop trigger test_trigger;
#觸發器都存放在information_schema.trigger
show DATABASES;
use information_schema;
show tables;
#檢視所有觸發器
select * from information_schema.TRIGGERS;
create table review ( id int primary key auto_increment, username varchar(64), action varchar(10), action_time date )engine innodb default charset utf8; #test1的增刪改都會觸發, 做成日誌資訊 create trigger test_insert after insert on test1 for each row begin insert into review value(null,user(),'insert',now()); end; create trigger test_update after update on test1 for each row begin insert into review value(null,user(),'update',now()); end; create trigger test_delete after delete on test1 for each row begin insert into review value(null,user(),'delete',now()); end; insert into test1 value(null,101); update test1 set number=102 where id=4; delete from test1 where id=4;做日誌
觸發器中不能將結果集返回(不能使用select來列印結果集)和call的動態SQL(不能用使用儲存過程) ,但可以通過引數帶出資料
create trigger tri_test after update on test1 for each row begin select 'update' into @msg; end; update test1 set number=66 where id=3; select @msg; drop trigger tri_test;通過引數把結果帶出
事件
create event insert_event #建立事件 on schedule #設定事件計劃任務(時間點,間隔時間) every 4 second #計劃任務設定成 每隔4秒執行一次 do 任務 do insert into test1 value(null,1000); create event truncate_event #建立事件 on schedule #設定事件計劃任務(時間點,間隔時間) every 1 minute #計劃任務設定成 每隔40秒執行一次 do 任務 do truncate table test1; #清空表資料 #檢視事件狀態 show events; #檢視排程器狀態並開啟 show variables like '%schedule%'; set global event_scheduler = on; #檢視程序列表 show processlist; #禁用個別事件 alter event insert_event disable; #開啟個別事件 alter event insert_event ensable; #drop event insert_event; #drop event truncate_event; #set global event_scheduler = off; #7天后開啟事件, 每天清空表 , 一個月後停止事件, 不保留事件 create event clear_event on schedule every 1 day starts current_timestamp + interval 7 day #當前時間 + 間隔7天后啟動 ends current_timestamp + interval 1 month #當前時間 + 間隔1個月後停止 on completion not preserve #完成後不保留事件 do truncate table test1;example
建立事件後,事件預設是開啟的,但事件排程器預設是關閉的,需要開啟後才能觸發事件(事件排程器是通過變數控制的),SQL系統會開啟一個程序來執行事件
事務 作為單個邏輯單元執行的一系列操作(建立 銷燬增刪改查都是單個的邏輯單元)
事務四個特性 ACID 分別是原子性、一致性、隔離性、永續性。
1、原子性(Atomicity)
原子性是指事務包含的所有操作要麼全部成功,要麼全部失敗回滾,因此事務的操作如果成功就必須要完全應用到資料庫,如果操作失敗則不能對資料庫有任何影響。
2、一致性(Consistency)
一致性是指事務必須使資料庫從一個一致性狀態變換到另一個一致性狀態,也就是說一個事務執行之前和執行之後都必須處於一致性狀態。舉例來說,假設使用者A和使用者B兩者的錢加起來一共是1000,那麼不管A和B之間如何轉賬、轉幾次賬,事務結束後兩個使用者的錢相加起來應該還得是1000,這就是事務的一致性。
3、隔離性(Isolation)
隔離性是當多個使用者併發訪問資料庫時,比如同時操作同一張表時,資料庫為每一個使用者開啟的事務,不能被其他事務的操作所幹擾,多個併發事務之間要相互隔離。關於事務的隔離性資料庫提供了多種隔離級別,稍後會介紹到。
4、永續性(Durability)
永續性是指一個事務一旦被提交了,那麼對資料庫中的資料的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丟失提交事務的操作。例如我們在使用JDBC操作資料庫時,在提交事務方法後,提示使用者事務操作完成,當我們程式執行完成直到看到提示後,就可以認定事務已經正確提交,即使這時候資料庫出現了問題,也必須要將我們的事務完全執行完成。否則的話就會造成我們雖然看到提示事務處理完畢,但是資料庫因為故障而沒有執行事務的重大錯誤。這是不允許的。
事務控制
隱式事務 insert update delete單個事務預設是隱式事務,由系統自動提交
顯式事務 需手動提交,
#資料的事務且由系統自動提交的,有變數控制 show variables like 'autocommit'; #關閉自動提交 set autocommit=off; #當關閉自動提交後 delete事務是無法對源表的資料有影響的 delete from test1 where id = 3; #雖然無法對源表做出影響,但能影響從表中讀到記憶體中的資料的結果集 select * from test1; #回滾,對結果集的資料回滾到事務未提交時 #rollback; #select * from test1; #手動提交事務, 對源表進行影響,提交後的事務無法回滾 # commit; #顯式事務 #重新開啟自動提交 set autocommit=on; #開啟顯式控制,作用和關閉自動提交是一樣的 start transaction; #後面的事務都都無法對源表有影響了,只會對結果集有影響 #可以通過rollback和commit,對結果集和源表進行回滾和提交顯式
開啟事務 starttransaction; 提交commit;後就算完成當前事務了,要繼續使用顯示事務時需再次開啟
事務隔離級別
當多個連線同時連線資料庫並開啟事務(starttransaction),要控制好 併發的事務 的隔離
讀未提交:A連線事務未提交 B連線可以讀到A連線未提交事務,但A有可能回滾,導致B讀取到錯誤資料 髒讀問題
讀提交: 大多數資料庫的預設級別 解決了髒讀問題 但B第一次讀和第二次讀同一資料可能不一致,因為可能A在中間提交了事務改變了B要讀的資料 導致不可重複讀
可重讀: MySQL預設級別 解決了不可重複讀 AB兩個連線在 開啟事務 時,等於各複製了一張和源表互不影響的臨時表,在未提交時這張臨時表不會被源表所影響, 一旦提交則會更新這張臨時表 幻讀問題:如果當前事務未提交臨時表而更新不及時,其他連線的事務影響了該資料,導致未提交的表可能對不存在的資料進行操作
序列化讀: 不允許多個事務同時操作 大大犧牲了效率 ,一般使用可重讀就夠了
#資料的事務且由系統自動提交的,有變數控制 show variables like 'autocommit'; #關閉自動提交 set autocommit=off; #當關閉自動提交後 delete事務是無法對源表的資料有影響的 delete from test1 where id = 3; #雖然無法對源表做出影響,但能影響從表中讀到記憶體中的資料的結果集 select * from test1; #回滾,對結果集的資料回滾到事務未提交時#rollback; #select * from test1; #手動提交事務, 對源表進行影響,提交後的事務無法回滾 #commit; #顯式事務 #重新開啟自動提交 set autocommit=on; #開啟顯式控制,作用和關閉自動提交是一樣的 start transaction; #後面的事務都都無法對源表有影響了,只會對結果集有影響 #可以通過rollback和commit,對結果集和源表進行回滾和提交事務
#檢視事務隔離級別 #當前會話(連線)的事務隔離級別 select @@session.tx_isolation; #當前服務的事務隔離級別 select @@global.tx_isolation; #設定當前會話(連線)的事務隔離等級 #讀未提交 set session transaction isolation level read uncommitted; #讀提交 set session transaction isolation level read committed; #可重讀 set session transaction isolation level repeatable read; #序列化讀 set session transaction isolation level serializable; #設定當前服務的事務隔離等級 #讀未提交 set global transaction isolation level read uncommitted; #讀提交 set global transaction isolation level read committed; #可重讀 set global transaction isolation level repeatable read; #序列化讀 set global transaction isolation level serializable;事務隔離級別
鎖 協調多併發的同時對某一資源進行訪問的機制
鎖的型別
MyISAM和MEMORY儲存引擎預設採用表級鎖(對整張表進行加鎖)
BDB儲存引擎採用頁面鎖(資料庫可以分頁讀,而頁的資料可能來自多張表,加了頁面鎖後,頁裡的資料也會加鎖,不在頁裡的資料不加鎖)
innodb引擎 採用表級鎖和行級鎖(可以對某一行資料加鎖), 預設是行級鎖可以切換
讀鎖(共享鎖) 對資料加了讀鎖後其他事務只能讀不能對其寫,其他事務可以對該資料疊加讀鎖
寫鎖(排他鎖) 對資料加了寫鎖後,其他事務不能讀寫,也不可以疊加鎖
MyISAM使用者讀資料時自動加read鎖,寫資料時自動加write鎖
加鎖 Lock tables 表名 read/write;鎖
解鎖 Unlock tables;
MyISAM當前連線對某個表加了鎖後,就無法再訪問其他的表只能訪問加了鎖的表