6、事物(Transaction)★★★★★
(1)、基礎知識:
事務是由一步或幾步數據庫操作序列組成的邏輯執行單元,這系列操作要麼全部執行,要麼全部放棄執行。程序和事務是兩個不同的概念。一般而言,一段程序中可能包含多個事務。事務具有四個特性ACID:
(2)、事物的四大特性,簡稱“一致持久隔離原子”
①、原子性(Atomicity) ,事物是應用中最小的執行單位,就如原子是自然界最小的顆粒一樣(現代物理研究表明,原子並不是微 微觀物質中最小的顆粒);
②、一致性(Consistency) ,事物的執行結果,必須使數據庫從一個一致性狀態變到另一個一致性狀態;
③、隔離性(Isolation) ,各個事物的執行互不干擾,任意一個事務的內部操作對其他併發的事物都是隔離的,也就是說,併發執 執行的事物之間不能看到對方的中間狀態,併發執行的事物之間不能互相影響;
④、持續性也成爲持久性(Durability),指事物一旦提交,對數據的任何改變,都要永久記錄到存儲器中,通常是保存進物理數據 據庫。
(3)、數據隔離問題
多線程下多個線程同時修改,肯定會互相搗亂, 隔離;
多線程下多個線程同時讀取,沒有任何問題;
多線程下一個線程修改,一個線程讀取,可能出現下面的問題:
①、髒讀( Dirty Reads):所謂髒讀就是對髒數據( Drity Data)的讀取,而髒數據所指的就是未提交的數據。也就是說,一個事務正在對條記錄做修改,在這個事務完成並提交之前,這條數據是處於待定狀態的(可能提交也可能回滾)這時,第二個事務來讀取這條沒有提交的數據,並基於此數據做進一步的處理,就會生未提交的數據依賴關係。這種現象被稱爲髒讀;
②、不可重複讀(Non-Repeatable Reads):一個事務先後讀取同—條記錄,但兩次讀取的數據不同,我們稱之爲不可重複讀。也就是說,這個事務在兩次讀取之間該數據被其它事務所修改;
③、幻讀( Phantom Reads):一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就稱爲幻讀。
(4)、事務的四個隔離級別:
①、未提交讀( Read Uncommitted):SELECT語句以非鎖定方式被執行,所以有可能讀到髒數據,隔離級別最低。
②、提交讀( Read Committed):只能讀取到已經提交的數據。即解決了髒讀但未解決不可重複讀。
③、可重複讀( Repeated Read):在同一個事務內的查詢都是事務開始時刻一致的,InnoDB引擎的默認級別。在SQL標準中,該隔離級別消除了不可重複讀,但是還存在幻讀。
④、串行讀( Serializable):完全的串行化讀,所有 SELECT語句都被隱式的轉換成SELECT....LOCK IN SHARE MODE,即讀取使用表級共享鎖,讀寫相互都會阻塞。隔離級別最高。
1、查看數據的隔離級別
show variables like 'transaction_isolation';
或者是:
select @@transaction_isolation;
2、開啓事務,事物是基於數據庫連接的,默認引擎下,事物是關閉的,並且是自動提交的,
start transaction;
savepoint /**保存點,回滾的時候可以選擇保存點回滾**/
(5)、手動提交、關閉事物
先關閉事物的自動提交
set autocommit=0; /**1:自動提交,0:手動提交**/
insert into tsinger(sname,ssalary,sdisplay) values('譚維維','1111.11','實力唱將');
/**此時刷新表數據,並未實際插入成功**/
commit;
/**提交後,數據插入成功**/
insert into tsinger(sname,ssalary,sdisplay) values('蕭敬騰','1111.11','退出直播間');
/**此時刷新表數據,並未插入成功**/
rollback;
/**事物的回滾,即撤銷數據的插入**/
(6)、事物的執行、提交、回滾(此處有問題,按理說應該set autocommit=0然後纔會出現下面的效果,但是autocommit=1時也是出現了手動提交的情況,即將autocommit設置爲0和1都是手動提交的效果,留以後證)
set autocommit=1; /**先關閉自動提交,及設置爲手動提交**/
start transaction; /**開啓事物**/
select * from tsinger; /**查詢操作**/
update tsinger set sage=58 where sname='騰格爾';
delete from tsinger where sname='洛天依';
commit; /**等執行了這句後,上述操作纔會一次性完成**/
rollback; /**若執行了這句後,則上述操作不會成功**/
(7)、JDBC中的事物
超級明顯的佔位符__________________.......hahhaha
7、存儲過程
(1)、存儲過程(Stored Procedure)是在大型數據庫系統中,一組爲了完成特定功能的SQL 語句集,它存儲在數據庫中,一次編譯後永久有效,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象。類似於Java中的方法。
1、創建一個存儲過程
drop procedure if exists po1;
/**創建前要先執行此刪除語句**/
create procedure po1(in newname varchar(10),in newdisplay varchar(300),out count int)
begin
insert into tsinger(sname,sdisplay) values(newname,newdisplay);
set count = (select count(*) from tsinger);
end;
/**set count=...., 此處設置count的值爲表裏的記錄數**/
2、調用存儲過程,需要傳參
call po1('韓磊','向天再借五百年',@count);
select @count;
(2)、創建一個存儲過程,實現根據傳入的參數,在後面添加數據到10行
drop procedure if exists pro2;
create procedure pro2(in num int)
begin
declare newname varchar(10);
declare newdisply varchar(300);
while num<=10 do
set newname = substring(uuid(),1,10);
set newdisply = uuid();
insert into tsinger(sname,sdisplay) values(newname,newdisply);
set num = num+1;
end while;
end;
/**declare 關鍵字:聲明一個變量**/
call pro2(8);/**調用存儲過程**/
8、存儲函數
(1)、存儲函數: 是一個特殊的存儲過程,類似於Java中的方法;很遺憾,新版本MySQL(親測5.7和8.0版本都不可以)不支持在function裏寫動態的DML語句;存儲函數裏都是入參,'in'關鍵字可以省略不寫。
1、設計一個函數,傳入參數爲歌手的名字和display,然後新增一個歌手的到數據庫,同時刪除名字爲10個長度的歌手,如果都成功,則提交,如果某操作失敗,則回滾
drop function if exists fun1;
create function fun1(newname varchar(10),newdisplay varchar(300))
returns int reads sql data
begin
/**聲明一個返回值變量**/
declare count int;
/**定義一個變量,此句類似於Java裏的 int flag = 0; **/
declare flag int default 0;
/**定義一個sql異常的句柄/監視器**/
declare continue handler for sqlexception set flag = 1;
/**開啓事務**/
start transaction;
/**新增數據**/
insert into tsinger(sname,sdisplay) values(newname,newdisplay);
/**刪除所有名字長度爲10的數據**/
delete from tsinger where sname like '__________';
/****/
set count = (select count(sid) from tsinger);
/**異常提交或回滾**/
if flag!=1 then commit;
else rollback;
end if;
return count;
end;
/**很遺憾,寫完後發現MySQL不支持在function,裏寫動態DML語句,因此這個存儲函數創建失敗**/
(2)、可以創建的存儲函數(裏面不包含動態DML語句)
1、傳如一個id,輸出id小於這個參數的歌手數量
drop function if exists fun2;
create function fun2(id int(11))
returns int reads sql data
begin
/**聲明一個返回值變量**/
declare count int;
/**查詢語句**/
set count = (select count(sid) from tsinger where sid<id);
/**返回數據**/
return count;
end;
select fun2(1010);
/**調用這個存儲函數**/
(3)、帶事物的存儲過程
1、向tsinger表裏插入一條指定名字和描述的數據,刪除一條名字裏含有指定的參數數據,返回最後表裏有多少條記錄
drop procedure if exists protrans;
create procedure protrans(in newname varchar(10),in newdisplay varchar(300),in str varchar(3),out count int)
begin
/**定義一個標誌變量**/
declare flag int default 0;
/**定義如果出現sql異常,就設置flag爲1**/
declare continue handler for sqlexception set flag=1;
/**開啓事務**/
start transaction;
/**新增一條記錄**/
insert into tsinger(sname,sdisplay) values(newname,newdisplay);
/**刪除一條數據**/
delete from tsinger where sname like concat('%',str,'%');
/**提交或回滾判斷**/
if flag != 1 then commit;
else rollback;
end if;
/**查詢總記錄數,用來返回**/
set count = (select count(sid) from tsinger);
end;
call protrans('那英','茉莉花','-7',@count);
select @count;
call protrans('ny','茉莉花','-7',@count);
select @count;
/**這次調用時因爲有異常,所以會回滾,刪除失敗,因爲sdisplay字段是撿了唯一索引的**/
9、遊標
(1)、遊標,類似於Java裏的iterator迭代器。遊標實際上是一種能從包括多條數據記錄的結果集中每次提取一條記錄的機制。遊標充當指針的作用。儘管遊標能遍歷結果集中的所有行,但是它一次只能指向一行。
(2)、概括來講,SQL的遊標是一種臨時的數據庫對象,既可以用來存放在數據庫表中的數據行副本,也可以指向存儲在數據庫中的數據行的指針。遊標提供了在逐行的基礎上操作表中數據的方法。
(3)、遊標的一個常見用途就是保存查詢結果,以便以後使用。遊標的結果集是由select語句產生,如果處理過程需要重複使用一個記錄集,那麼創建一次遊標而重複使用若干次,比重複查詢數據庫要快的多。
(4)、大部分數據庫設計語言都能使用遊標來檢索SQL數據庫中的數據,在程序中嵌入遊標和在程序中嵌入SQL語句相同。
從mysql V5.5開始,進行了一次大的改變,就是將InnoDB作爲默認的存儲引擎。InnoDB支持事務,而且擁有相關的RDBMS特性:ACID事務支持,數據完整性(支持外鍵),災難恢復能力等等。
1、用遊標的方式計算ssalary列的和(用遊標每次從ssalary字段拿到一個數據,若不爲空,則將它們依次累加)
drop procedure if exists sums;
create procedure sums(out salas decimal(8,2))
begin
/**用變量c來接收每一次從遊標裏讀取的數據**/
declare c decimal(7,2) default 0;
declare flag int default 0;
/**聲明一個遊標,遊標是來自查詢tsinger表裏所有ssalary這一列的**/
declare cur1 cursor for select ssalary from tsinger;
/**聲明一個繼續監控的handler,監控遊標循環到最後找不到數據了**/
declare continue handler for not found set flag=1;
set salas = 1;
/**開啓遊標**/
open cur1;
/**取一條遊標裏的數據到一個變量c中**/
fetch cur1 into c;
/**當flag還不是1的時候,說明遊標還沒有遍歷完**/
while flag!=1 do
if c is not null then set salas = salas+c;
end if;
/**繼續向下一行遊標索要數據**/
fetch cur1 into c;
end while;
/**關閉遊標**/
close cur1;
end;
call sums(@sal);
select @sal;
10、觸發器
(1)、觸發器(trigger)是個特殊的存儲過程,它的執行不是由程序調用,也不是手工啓動,而是由事件來觸發,當對一個表進行增、刪、改操作時就會觸發,或者更改表結構時也會觸發。觸發器經常用於加強數據的完整性約束以及業務規則等。綜上所述:觸發器是一種與表操作有關的數據庫對象,當觸發器所在的表上發生指定事件時,將會調用該對象,即表的操作事件觸發表上觸發器的執行。
(2)、觸發器分爲三類:DML觸發器,DDL觸發器,登錄觸發器。我們重點來看一下DML觸發器和DDL觸發器。DML觸發器是指在數據庫中發生DML操作時將會觸發的事件。DDL觸發器是指在數據庫中發DDL操作時將會觸發的事件。
(3)、觸發器的作用:
- 安全性:可以基於數據庫的值使用戶具有操作數據庫的某種權利。可以基於時間限制用戶操作,例如不允許節假日或下班時間對數據庫操作。可以基於數據庫中的數據限制用戶的操作,例如不允許股票的價格一次上浮10%。
- 審計:可以跟蹤用戶對數據庫的操作。例如:審計用戶操作數據庫的語句;例如:把用戶對某些關鍵表的操作寫入到審計表中。
- 實現複雜的數據完整性規則。例如:實現非標準的數據完整性檢查和約束。觸發器可產生比規則更爲複雜的限制。與規則不同,觸發器可以引用列或數據庫對象。例如,觸發器可回退任何企圖喫進超過自己保證金的期貨。
- 實現複雜的非標準的數據庫相關完整性規則。觸發器可以對數據庫相關的表進行連環更新,例如在某個表上的刪除觸發器可以導致相應的刪除與之關聯的其他表的數據或更改某列的值。
- 同步的實時複製表中的數據。
- 自動計算數據值,如果某個表中的某列字段值達到了一定的要求,則進行特定的處理
(4)、創建觸發器的SQL語法如下:
create trigger trigger_name trigger_time trigger_event on table_name for each row
觸發器是與表操作相關的數據庫對象,所以觸發的命名與表相關,在創建觸發器時需要指定表名table_name,表爲永久性的表,所以觸發器不能與臨時表和視圖建立關聯。
trigger:創建觸發器的關鍵字,定義觸發器名稱。
trigger_name:觸發器的名稱。
trigger_time:觸發器的執行時間,它的值爲before或者after,是指在激活它的語句之前還是之後執行。一般情況下是在激活它的語句運行完成後再執行觸發器。
trigger_event:觸發事件,它的值可以使insert、update、delete。在這個三個動作上我們需要了解數據庫裏兩個臨時的虛擬表:deleted、inserted,在mysql中使用old和new關鍵字來表示。
動作 |
deleted表 |
inserted表 |
insert |
不存儲記錄 |
存儲新插入的記錄 |
update |
存放之前的記錄 |
存放更新後的記錄 |
delete |
存放被刪除的記錄 |
不存儲記錄 |
1、案例:設計一個觸發器來記錄tsinger表裏哪個記錄發生了修改,並記住原來的名字和新名字,以及修改時間
/**先創建一個用來記錄這些信息的數據表**/
create table myrecord(
rid varchar(36) primary key ,
sid int,
oldname varchar(20),
newname varchar(20),
updatetime datetime
);
/**創建一個觸發器,名字是rec,監視的事件是 修改,時間之後**/
drop trigger if exists rec;
create trigger rec after update on tsinger for each row
begin
insert into myrecord values(uuid(),old.sid,old.sname,new.sname,now());
end;
/**觸發器在設定的時間和時間符合時自動調用**/
update tsinger set sname='張三' where sname='那英';
/**執行完這句後,myrecord表裏會自動記錄好一條數據**/
11、綜合練習題
(1)、設計一存儲過程. 在向tsinger表中插入數據時, 如果 ssalary 沒給值 就賦值爲0.00,如果sbirthday字段沒給值,就賦值爲 當前日期。
MySQL
(2)、設計一存儲過程. 帶事務,修改 tsinger表 指定id的那條記錄的sdisplay爲一個新傳入的新描述。修改不成功!!!!
修改表中數據,月薪小於1萬的就乘以3,月薪大於1萬的就乘以1.1,修改完畢後,返回 表中月薪大於1萬的歌手總數。
MySQL