第三節 事務和視圖
3.1事務
事務是用來維護數據庫完整性的,它能夠保證一系列的MySQL操作要么全部執行,要么全不執行。舉一個例子來進行說明,例如轉賬操作:A賬戶要轉賬給B賬戶,那么A賬戶上減少的錢數和B賬戶上增加的錢數必須一致,也就是說A賬戶的轉出操作和B賬戶的轉入操作要么全部執行,要么全不執行;如果其中一個操作出現異常而沒有執行的話,就會導致賬戶A和賬戶B的轉入轉出金額不一致的情況,為而事實上這種情況是不允許發生的,所以為了防止這種情況的發生,需要使用事務處理。
1. 事務的概念
事務(Transaction)指的是一個操作序列,該操作序列中的多個操作要么都做,要么都不做,是一個不可分割的工作單位,是數據庫環境中的邏輯工作單位,由DBMS中的事務管理子系統負責事務的處理。
目前常用的存儲引擎有InnoDB(MySQL5.5以后默認的存儲引擎)和MyISAM(MySQL5.5之前默認的存儲引擎),其中InnoDB支持事務處理機制,而MyISAM不支持。
2. 事務的特性
事務處理可以確保除非事務性序列內的所有操作都成功完成,否則不會永久更新面向數據的資源。通過將一組相關操作組合為一個要么全部成功要么全部失敗的序列,可以簡化錯誤恢復并使應用程序更加可靠。
但并不是所有的操作序列都可以稱為事務,這是因為一個操作序列要成為事務,必須滿足事務的原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)和持久性(Durability)。這四個特性簡稱為ACID特性。
1) 原子性
原子是自然界最小的顆粒,具有不可再分的特性。事務中的所有操作可以看做一個原子,事務是應用中不可再分的最小的邏輯執行體。
使用事務對數據進行修改的操作序列,要么全部執行,要么全不執行。通常,某個事務中的操作都具有共同的目標,并且是相互依賴的。如果數據庫系統只執行這些操作中的一部分,則可能會破壞事務的總體目標,而原子性消除了系統只處理部分操作的可能性。
2) 一致性
一致性是指事務執行的結果必須使數據庫從一個一致性狀態,變到另一個一致性狀態。當數據庫中只包含事務成功提交的結果時,數據庫處于一致性狀態。一致性是通過原子性來保證的。
例如:在轉賬時,只有保證轉出和轉入的金額一致才能構成事務。也就是說事務發生前和發生后,數據的總額依然匹配。
3) 隔離性
隔離性是指各個事務的執行互不干擾,任意一個事務的內部操作對其他并發的事務,都是隔離的。也就是說:并發執行的事務之間既不能看到對方的中間狀態,也不能相互影響。
例如:在轉賬時,只有當A賬戶中的轉出和B賬戶中轉入操作都執行成功后才能看到A賬戶中的金額減少以及B賬戶中的金額增多。并且其他的事務對于轉賬操作的事務是不能產生任何影響的。
4) 持久性
持久性指事務一旦提交,對數據所做的任何改變,都要記錄到永久存儲器中,通常是保存進物理數據庫,即使數據庫出現故障,提交的數據也應該能夠恢復。但如果是由于外部原因導致的數據庫故障,如硬盤被損壞,那么之前提交的數據則有可能會丟失。
【示例8】使用事務保證轉賬安全
-- 創建account賬戶表
create table account(
id int primary key auto_increment,
username varchar(30) not null,
balance double
);
-- 為account賬戶表同時插入兩條數據
insert into account (username, balance) values('張三', 2000),('李四', 2000);
-- 查看account賬戶表中的數據
select * from account;
-- 開啟轉賬事務
start transaction;
update account set balance=balance-200 where username='張三';
update account set balance=balance1+200 where username='李四';
select * from account;
-- 當我們關閉數據庫重新打開后,張三和李四的賬戶余額并沒發生任何變化。
-- 這是因為當我們使用“START TRANSACTION”開啟一個事務后,該事務的提交方式不再是自動的,
-- 而是需要手動提交,而在這里,我們并沒有使用事務提交語句COMMIT,
-- 所以對account表中數據的修改并沒有永久的保存到數據庫中,也就是說我們的轉賬事務并沒有執行成功
-- 提交轉賬事務
commit;
-- 事務的回滾也可以看做是結束事務的標記,但是回滾的事務并沒有執行成功,而是讓數據庫恢復到了執行事務操作前的初始狀態。
-- 需要注意的是事務的回滾必須在事務提交之前,因為事務一旦提交就不能再進行回滾操作。
rollback;
3. 事務的并發問題
臟讀(Dirty read)
當一個事務正在訪問數據并且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時另外一個事務也訪問了這個數據,然后使用了這個數據。因為這個數據是還沒有提交的數據,那么另外一個事務讀到的這個數據是“臟數據”,依據“臟數據”所做的操作可能是不正確的。
不可重復讀
(Unrepeatableread): 指在一個事務內多次讀同一數據。在這個事務還沒有結束時,另一個事務也訪問該數據。那么,在第一個事務中的兩次讀數據之間,由于第二個事務的修改導致第一個事務兩次讀取的數據可能不太一樣。這就發生了在一個事務內兩次讀到的數據是不一樣的情況,因此稱為不可重復讀。
幻讀
(Phantom read): 幻讀與不可重復讀類似。它發生在一個事務(T1)讀取了幾行數據,接著另一個并發事務(T2)插入了一些數據時。在隨后的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄,就好像發生了幻覺一樣,所以稱為幻讀。
不可重復度和幻讀區別:
不可重復讀的重點是修改,幻讀的重點在于新增或者刪除。
解決不可重復讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表
例1(同樣的條件, 你讀取過的數據, 再次讀取出來發現值不一樣了 ):事務1中的A先生讀取自己的工資為 1000的操作還沒完成,事務2中的B先生就修改了A的工資為2000,導 致A再讀自己的工資時工資變為 2000;這就是不可重復讀。
例2(同樣的條件, 第1次和第2次讀出來的記錄數不一樣 ):假某工資單表中工資大于3000的有4人,事務1讀取了所有工資大于3000的人,共查到4條記錄,這時事務2 又插入了一條工資大于3000的記錄,事務1再次讀取時查到的記錄就變為了5條,這樣就導致了幻讀
4. 事務的隔離級別
事務的隔離級別用于決定如何控制并發用戶讀寫數據的操作。數據庫是允許多用戶并發訪問的,如果多個用戶同時開啟事務并對同一數據進行讀寫操作的話,有可能會出現臟讀、不可重復讀和幻讀問題,所以MySQL中提供了四種隔離級別來解決上述問題。
事務的隔離級別從低到高依次為READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ以及SERIALIZABLE,隔離級別越低,越能支持高并發的數據庫操作。
【示例9】事務的隔離級別
-- 查看默認的事務隔離級別 MySQL默認的是repeatable read
select @@transaction_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;
3.2 視圖 view
1. 視圖的概念
視圖是一個從單張或多張基礎數據表或其他視圖中構建出來的虛擬表。同基礎表一樣,視圖中也包含了一系列帶有名稱的列和行數據,但是數據庫中只是存放視圖的定義,也就是動態檢索數據的查詢語句,而并不存放視圖中的數據,這些數據依舊存放于構建視圖的基礎表中,只有當用戶使用視圖時才去數據庫請求相對應的數據,即視圖中的數據是在引用視圖時動態生成的。因此視圖中的數據依賴于構建視圖的基礎表,如果基本表中的數據發生了變化,視圖中相應的數據也會跟著改變。
2. 視圖的好處
簡化用戶操作:視圖可以使用戶將注意力集中在所關心地數據上,而不需要關心數據表的結構、與其他表的關聯條件以及查詢條件等。
對機密數據提供安全保護:有了視圖,就可以在設計數據庫應用系統時,對不同的用戶定義不同的視圖,避免機密數據(如,敏感字段“salary”)出現在不應該看到這些數據的用戶視圖上。這樣視圖就自動提供了對機密數據的安全保護功能
【示例9】視圖練習1
-- 創建或替換單表視圖
create or replace view myview1
as
select empno, ename, job, mgr, hiredate, deptno
from emp
where hiredate < '1981-09-23'
with check option
-- 使用視圖
desc myview1;
select * from myview1;
insert into myview1 values(9998,'9999','clerk',7839,'1980-12-23',20);
select * from emp
-- 刪除視圖
drop view myview1;
-- 多表視圖
create or replace view myview2
as
select e.empno,e.ename,e.sal,d.deptno,d.dname
from dept d
join emp e on d.deptno = e.deptno
where sal >2500
select * from myview2
【示例10】視圖練習2
--統計視圖
create or replace view myview3
as
select d.deptno 部門編號,dname 部門名稱,avg(sal) 平均工資,max(sal) 最高工資,count(*)人數
from emp e
join dept d
using(deptno)
where deptno is not null
group by deptno
order by avg(sal)
--基于視圖的視圖
create or replace view myview4
as
select * from myview3
where 最高工資>3000
-- 查看視圖列表
show tables;
本節作業
1. 事務的概念和特征
2. 并發問題及其事務的隔離級別
3. 視圖的定義和優點
4. 完成示例9,示例10視圖操作
本知乎號每日更新2篇java基礎視頻貼,以及2-4篇java基礎技術文章,有興趣的同學可以關注學習。