Oracle数据库之事务
Oracle數(shù)據(jù)庫之事務(wù)
1. 什么是事務(wù)
在數(shù)據(jù)庫中事務(wù)是工作的邏輯單元,一個(gè)事務(wù)是由一個(gè)或多個(gè)完成一組的相關(guān)行為的SQL語句組成,通過事務(wù)機(jī)制確保這一組SQL語句所作的操作要么都成功執(zhí)行,完成整個(gè)工作單元操作,要么一個(gè)也不執(zhí)行。
如:網(wǎng)上轉(zhuǎn)帳就是典型的要用事務(wù)來處理,用以保證數(shù)據(jù)的一致性。
2. 事務(wù)特性
SQL92標(biāo)準(zhǔn)定義了數(shù)據(jù)庫事務(wù)的四個(gè)特點(diǎn):
- 原子性(Atomicity):一個(gè)事務(wù)里面所有包含的SQL語句是一個(gè)執(zhí)行整體,不可分割,要么都做,要么都不做。
- 一致性(Consistency):事務(wù)開始時(shí),數(shù)據(jù)庫中的數(shù)據(jù)是一致的,事務(wù)結(jié)束時(shí),數(shù)據(jù)庫的數(shù)據(jù)也應(yīng)該是一致的。
- 隔離性(Isolation):是指數(shù)據(jù)庫允許多個(gè)并發(fā)事務(wù)同時(shí)對(duì)其中的數(shù)據(jù)進(jìn)行讀寫和修改的能力,隔離性可以防止事務(wù)的并發(fā)執(zhí)行時(shí),由于他們的操作命令交叉執(zhí)行而導(dǎo)致的數(shù)據(jù)不一致狀態(tài)。
- 持久性 (Durability) : 是指當(dāng)事務(wù)結(jié)束后,它對(duì)數(shù)據(jù)庫中的影響是永久的,即便系統(tǒng)遇到故障的情況下,數(shù)據(jù)也不會(huì)丟失。
一組SQL語句操作要成為事務(wù),數(shù)據(jù)庫管理系統(tǒng)必須保證這組操作的原子性(Atomicity)、一致性(consistency)、隔離性(Isolation)和持久性(Durability),這就是ACID特性。
3. 數(shù)據(jù)異常
因?yàn)镺racle中支持多個(gè)事務(wù)并發(fā)執(zhí)行,所以會(huì)出現(xiàn)下面的數(shù)據(jù)異常。
3.1 臟讀
當(dāng)一個(gè)事務(wù)修改數(shù)據(jù)時(shí),另一事務(wù)讀取了該數(shù)據(jù),但是第一個(gè)事務(wù)由于某種原因取消對(duì)數(shù)據(jù)修改,使數(shù)據(jù)返回了原狀態(tài),這是第二個(gè)事務(wù)讀取的數(shù)據(jù)與數(shù)據(jù)庫中數(shù)據(jù)不一致,這就叫臟讀。
如:事務(wù)T1修改了一條數(shù)據(jù),但是還未提交,事務(wù)T2恰好讀取到了這條修改后了的數(shù)據(jù),此時(shí)T1將事務(wù)回滾,這個(gè)時(shí)候T2讀取到的數(shù)據(jù)就是臟數(shù)據(jù)。
3.2 不可重復(fù)讀
是指一個(gè)事務(wù)讀取數(shù)據(jù)庫中的數(shù)據(jù)后,另一個(gè)事務(wù)則更新了數(shù)據(jù),當(dāng)?shù)谝粋€(gè)事務(wù)再次讀取其中的數(shù)據(jù)時(shí),就會(huì)發(fā)現(xiàn)數(shù)據(jù)已經(jīng)發(fā)生了改變,這就是不可重復(fù)讀取。不可重復(fù)讀取所導(dǎo)致的結(jié)果就是一個(gè)事務(wù)前后兩次讀取的數(shù)據(jù)不相同。
如:事務(wù)T1讀取一行記錄,緊接著事務(wù)T2修改了T1剛剛讀取的記錄,然后T1再次查詢,發(fā)現(xiàn)與第一次讀取的記錄不同。
3.3 幻讀
如果一個(gè)事務(wù)基于某個(gè)條件讀取數(shù)據(jù)后,另一個(gè)事務(wù)則更新了同一個(gè)表中的數(shù)據(jù),這時(shí)第一個(gè)事務(wù)再次讀取數(shù)據(jù)時(shí),根據(jù)搜索的條件返回了不同的行,這就是幻讀。
如:事務(wù)T1讀取一條指定where條件的語句,返回結(jié)果集。此時(shí)事務(wù)T2插入一行新記錄,恰好滿足T1的where條件。然后T1使用相同的條件再次查詢,結(jié)果集中可以看到T2插入的記錄,這條新紀(jì)錄就是幻讀。
事務(wù)中遇到的這些異常與事務(wù)的隔離性設(shè)置有關(guān),事務(wù)的隔離性設(shè)置越多,異常就出現(xiàn)的越少,但并發(fā)效果就越低,事務(wù)的隔離性設(shè)置越少,異常出現(xiàn)的越多,并發(fā)效果越高。
4. 事務(wù)隔離級(jí)別
針對(duì)讀取數(shù)據(jù)時(shí)可能產(chǎn)生的不一致現(xiàn)象,在SQL92標(biāo)準(zhǔn)中定義了4個(gè)事務(wù)的隔離級(jí)別:
| Read uncommitted(讀未提交) | 是 | 是 | 是 |
| Read committed(讀已提交) | 否 | 是 | 是 |
| Repeatable read(可重復(fù)讀) | 否 | 否 | 是 |
| Serializable(串行讀) | 否 | 否 | 否 |
Oracle默認(rèn)的隔離級(jí)別是read committed。
Oracle支持上述四種隔離級(jí)別中的兩種:read committed 和serializable。除此之外,Oralce中還定義Read only和Read write隔離級(jí)別。
Read only:事務(wù)中不能有任何修改數(shù)據(jù)庫中數(shù)據(jù)的操作語句,是Serializable的一個(gè)子集。
Read write:它是默認(rèn)設(shè)置,該選項(xiàng)表示在事務(wù)中可以有訪問語句、修改語句,但不經(jīng)常使用。
設(shè)置隔離級(jí)別
設(shè)置一個(gè)事務(wù)的隔離級(jí)別:
- SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
- SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
- SET TRANSACTION READ ONLY;
- SET TRANSACTION READ WRITE;
注意:這些語句是互斥的,不能同時(shí)設(shè)置兩個(gè)或兩個(gè)以上的選項(xiàng)。
設(shè)置單個(gè)會(huì)話的隔離級(jí)別:
- ALTER SESSION SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
- ALTER SESSION SET TRANSACTION ISOLATION SERIALIZABLE;
5. 事務(wù)控制命令
5.1 提交事務(wù)
在執(zhí)行使用COMMIT語句可以提交事務(wù),當(dāng)執(zhí)行了COMMIT語句后,會(huì)確認(rèn)事務(wù)的變化,結(jié)束事務(wù),刪除保存點(diǎn),釋放鎖。當(dāng)使用COMMIT語句結(jié)束事務(wù)之后,其他會(huì)話將可以查看到事務(wù)變化后的新數(shù)據(jù)。
5.2 回滾事務(wù)
保存點(diǎn)(savepoint):是事務(wù)中的一點(diǎn),用于取消部分事務(wù),當(dāng)結(jié)束事務(wù)時(shí),會(huì)自動(dòng)的刪除該事務(wù)所定義的所有保存點(diǎn)。當(dāng)執(zhí)行ROLLBACK時(shí),通過指定保存點(diǎn)可以回退到指定的點(diǎn)。
設(shè)置保存點(diǎn):
sql> Savepoint a;刪除保存點(diǎn):
sql> Release Savepoint a;回滾部分事務(wù):
sql> Rollback To a;回滾全部事務(wù):
sql> Rollback;6. 數(shù)據(jù)庫鎖
數(shù)據(jù)庫是一個(gè)多用戶使用的共享資源。當(dāng)多個(gè)用戶并發(fā)地存取數(shù)據(jù)時(shí),在數(shù)據(jù)庫中就會(huì)產(chǎn)生多個(gè)事務(wù)同時(shí)存取同一數(shù)據(jù)的情況。若對(duì)并發(fā)操作不加控制就可能會(huì)讀取和存儲(chǔ)不正確的數(shù)據(jù),破壞數(shù)據(jù)庫的一致性。
在數(shù)據(jù)庫中有兩種基本的鎖類型:排它鎖(Exclusive Locks,即X鎖)和共享鎖(Share Locks,即S鎖)。當(dāng)數(shù)據(jù)對(duì)象被加上排它鎖時(shí),其他的事務(wù)不能對(duì)它讀取和修改;加了共享鎖的數(shù)據(jù)對(duì)象可以被其他事務(wù)讀取,但不能修改。
6.1 鎖分類
根據(jù)保護(hù)對(duì)象的不同,Oracle數(shù)據(jù)庫鎖可分為:
- DML lock(data locks,數(shù)據(jù)鎖):用于保護(hù)數(shù)據(jù)的完整性。
- DDL lock(dictionary locks,字典鎖):用于保護(hù)數(shù)據(jù)庫對(duì)象的結(jié)構(gòu)(例如表、視圖、索引的結(jié)構(gòu)定義)。
- Internal locks 和latches(內(nèi)部鎖與閂):保護(hù)內(nèi)部數(shù)據(jù)庫結(jié)構(gòu)。
- Distributed locks(分布式鎖):用于OPS(并行服務(wù)器)中。
- PCM locks(并行高速緩存管理鎖):用于OPS(并行服務(wù)器)中。
在Oracle中最主要的鎖是DML鎖,DML鎖的目的在于保證并發(fā)情況下的數(shù)據(jù)完整性。在Oracle數(shù)據(jù)庫中,DML鎖主要包括TM鎖和TX鎖,其中TM鎖稱為表級(jí)鎖,TX鎖稱為事務(wù)鎖或行級(jí)鎖。
鎖出現(xiàn)在數(shù)據(jù)共享的場(chǎng)合,用來保證數(shù)據(jù)的一致性。當(dāng)多個(gè)會(huì)話同時(shí)修改一個(gè)表時(shí),需要對(duì)數(shù)據(jù)進(jìn)行相應(yīng)的鎖定。
鎖有“共享鎖”、“排它鎖”,“共享排它鎖”等多種類型,而且每種類型又有“行級(jí)鎖” (一次鎖住一條記錄),“頁級(jí)鎖” (一次鎖住一頁,即數(shù)據(jù)庫中存儲(chǔ)記錄的最小可分配單元),“表級(jí)鎖” (鎖住整個(gè)表)。
6.2 共享鎖(S鎖)
可通過lock table in share mode命令添加該S鎖。在該鎖定模式下,不允許任何用戶更新表。但是允許其他用戶發(fā)出select …from for update命令對(duì)表添加RS鎖。
6.3 排他鎖(X鎖)
可通過lock table in exclusive mode命令添加X鎖。在該鎖定模式下,其他用戶不能對(duì)表進(jìn)行任何的DML和DDL操作,該表上只能進(jìn)行查詢。
6.4 行級(jí)共享鎖(RS鎖)
通常是通過select … from for update語句添加的,同時(shí)該方法也是我們用來手工鎖定某些記錄的主要方法。比如,當(dāng)我們?cè)诓樵兡承┯涗浀倪^程中,不希望其他用戶對(duì)查詢的記錄進(jìn)行更新操作,則可以發(fā)出這樣的語句。當(dāng)數(shù)據(jù)使用完畢以后,直接發(fā)出rollback命令將鎖定解除。當(dāng)表上添加了RS鎖定以后,不允許其他事務(wù)對(duì)相同的表添加排他鎖,但是允許其他的事務(wù)通過DML語句或lock命令鎖定相同表里的其他數(shù)據(jù)行。
6.5 行級(jí)排他鎖(RX鎖)
當(dāng)進(jìn)行DML操作時(shí)會(huì)自動(dòng)在被更新的表上添加RX鎖,或者也可以通過執(zhí)行l(wèi)ock命令顯式的在表上添加RX鎖。在該鎖定模式下,允許其他的事務(wù)通過DML語句修改相同表里的其他數(shù)據(jù)行,或通過lock命令對(duì)相同表添加RX鎖定,但是不允許其他事務(wù)對(duì)相同的表添加排他鎖(X鎖)。
6.6 共享行級(jí)排他鎖(SRX鎖)
通過lock table in share row exclusive mode命令添加SRX鎖。該鎖定模式比行級(jí)排他鎖和共享鎖的級(jí)別都要高,這時(shí)不能對(duì)相同的表進(jìn)行DML操作,也不能添加共享鎖。
上述幾種鎖模式中,RS鎖是限制最少的鎖,X鎖是限制最多的鎖。它們的兼容關(guān)系如下:
基本上所有的鎖都可以由Oracle內(nèi)部自動(dòng)創(chuàng)建和釋放,但是其中的DDL和DML鎖是可以通過命令進(jìn)行管理的,命令語法:
LOCK table_name IN [row share][row exclusive][share][share row exclusive][exclusive] MODE [NOWAIT];下圖列出產(chǎn)生鎖定模式的SQL語句:
當(dāng)程序?qū)λ龅男薷倪M(jìn)行提交(Commit)或回滾(Rollback)后,鎖住的資源便會(huì)得到釋放,從而允許其他用戶進(jìn)行操作。如果兩個(gè)事務(wù),分別鎖定一部分?jǐn)?shù)據(jù),而都在等待對(duì)方釋放鎖才能完成事務(wù)操作,這種情況下就會(huì)發(fā)生死鎖
7. 數(shù)據(jù)庫事務(wù)實(shí)現(xiàn)機(jī)制
幾乎所有的數(shù)據(jù)庫管理系統(tǒng)中,事務(wù)管理的機(jī)制都是通過使用日志文件來實(shí)現(xiàn)的,我們來簡(jiǎn)單介紹一下日志的工作方式。
當(dāng)用戶執(zhí)行一條修改數(shù)據(jù)庫的DML語句時(shí),DBMS自動(dòng)在日志文件中寫一條記錄,顯示被這條語句影響的每一條記錄的兩個(gè)副本。一個(gè)副本顯示變化前的記錄,另一個(gè)副本顯示變化后的記錄。當(dāng)日志寫完之后,DBMS才實(shí)際對(duì)磁盤中的記錄進(jìn)行修改。
如果用戶隨后執(zhí)行COMMIT語句,事務(wù)結(jié)束也被記錄在事務(wù)日志中。如果用戶執(zhí)行ROLLBACK語句,DBMS檢查日志,找出自事務(wù)開始以來被修改的記錄“以前”的樣子,然后使用這些信息恢復(fù)它們以前的狀態(tài),有效地撤銷事務(wù)期間對(duì)數(shù)據(jù)庫所做的修改。
如果系統(tǒng)出錯(cuò),系統(tǒng)操作員通常通過運(yùn)行DBMS提供的特殊恢復(fù)程序來復(fù)原數(shù)據(jù)庫。恢復(fù)程序檢查到事務(wù)日志末尾,查找故障之前沒有被提交的事務(wù)?;謴?fù)程序回滾沒有完全完成的事務(wù),以便僅有被提交的事務(wù)反映到數(shù)據(jù)庫中,而故障中正處理的事務(wù)被回滾。
事務(wù)日志的使用明顯增加了更新數(shù)據(jù)庫的開銷。在實(shí)際中,主流商用DBMS產(chǎn)品使用的日志技術(shù)比上述描述的方案更復(fù)雜,用以減小這種開銷。此外,事務(wù)日志通常被存儲(chǔ)在高速磁盤驅(qū)動(dòng)器中,不同于存儲(chǔ)數(shù)據(jù)庫的磁盤,以減小磁盤訪問競(jìng)爭(zhēng)。某些個(gè)人計(jì)算機(jī)DBMS產(chǎn)品允許關(guān)閉事務(wù)日志性能,以提高DBMS的性能。
8. 示例
銀行轉(zhuǎn)帳的例子是最經(jīng)典的事務(wù)示例:
用戶把錢從一個(gè)銀行賬號(hào)轉(zhuǎn)賬至另一個(gè)銀行賬號(hào),需要將資金從一個(gè)銀行賬號(hào)中取出,然后再存入另一個(gè)銀行賬號(hào)中。理想來說,這兩次操作都應(yīng)該成功。但是,如果有錯(cuò)誤發(fā)生,則兩次操作都應(yīng)該失敗,否則的話,操作之后其中一個(gè)賬號(hào)中的金額將會(huì)是錯(cuò)誤的,整個(gè)操作過程應(yīng)該是原子性的,兩個(gè)操作都是一個(gè)原子事務(wù)操作的一部分。
示例:
-- 從賬戶一向賬戶二轉(zhuǎn)賬 DECLAREv_money NUMBER(8, 2); -- 轉(zhuǎn)賬金額v_balance account.balance%TYPE; -- 賬戶余額 BEGINv_money := &轉(zhuǎn)賬金額; -- 輸入轉(zhuǎn)賬金額-- 從賬戶一減錢 UPDATE account SET balance = balance - v_money WHERE id=&轉(zhuǎn)出賬戶RETURNING balance INTO v_balance;IF SQL%NOTFOUND THENRAISE_APPLICATION_ERROR(-20001, '沒有該賬戶:'||&轉(zhuǎn)出賬戶);END IF;IF v_balance < 0 THENRAISE_APPLICATION_ERROR(-20002, '賬戶余額不足');END IF;-- 向賬戶二加錢UPDATE account SET balance = balance + v_money WHERE id=&轉(zhuǎn)入賬戶;IF SQL%NOTFOUND THENRAISE_APPLICATION_ERROR(-20001, '沒有該賬戶:'||&轉(zhuǎn)入賬戶);END IF;-- 如果沒有異常,則提交事務(wù)COMMIT;DBMS_OUTPUT.PUT_LINE('轉(zhuǎn)賬成功');EXCEPTIONWHEN OTHERS THEN ROLLBACK; -- 出現(xiàn)異常則回滾事務(wù)DBMS_OUTPUT.PUT_LINE('轉(zhuǎn)賬失敗:');DBMS_OUTPUT.PUT_LINE(SQLERRM); END;?
轉(zhuǎn)載于:https://www.cnblogs.com/zf29506564/p/5772380.html
總結(jié)
以上是生活随笔為你收集整理的Oracle数据库之事务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开源微信支付SDK
- 下一篇: SQL大圣之路笔记——SQL 创建索引