《Oracle 事務探索與實例》

 數據庫版本sql

SYS@LEO1>select* from v$version;數據庫

BANNERsession

--------------------------------------------------------------------------------oracle

Oracle Database 11g Enterprise EditionRelease 11.2.0.1.0 - 64bit Production網站

PL/SQLRelease 11.2.0.1.0 - Production.net

CORE    11.2.0.1.0      Production設計

TNS forLinux: Version 11.2.0.1.0 - Production日誌

NLSRTLVersion 11.2.0.1.0 - Production事件

 

 事務那些事兒事務

1.什麼是事務:事務是一組操做序列,這些操做要麼都完成,要麼都不完成,它是一個不可分割的操做單元。關係型數據庫最核心的價值體現。說白了爲了完成一件事而作的n個步驟,這n個步驟是有先後順序的,必須按照A->B->C->D的邏輯順序來執行,事務是數據庫維護數據一致性的單位,例如多個會話同時讀取同一數據的問題。

關係型數據庫中,一個事務能夠是一條SQL語句,一組SQL語句或整個程序。

場景:銀行轉帳 結算購物 訂票系統

非關係型數據庫中,一個事務能夠是一個操做,但操做之間沒有關係,相互獨立的。

好比:推薦系統  日誌分析  網站搜索

 

 用例子說明事務的四個屬性和自動提交功能

事務的屬性ACID

原子性(Atomicity):一個事務是一個不可分割的總體,事務中的操做要麼都完成,要麼都失敗。

實例

SYS@LEO1>conn leo1/leo1

Connected.

LEO1@LEO1>drop table leo1 purge;                  清理環境

Table dropped.

LEO1@LEO1>create table leo1 (x number,ynumber);     建立表

Table created.

LEO1@LEO1>insert into leo1 values(1,1);               執行DML操做

1 row created.

LEO1@LEO1>update leo1 set x=2 where x=1;

1 row updated.

LEO1@LEO1>delete from leo1 where y=1;

1 row deleted.

LEO1@LEO1>commit;

Commit complete.

上面咱們執行了三條sql語句,都屬於一個事務,當commit的時候表示事務完成,這三條sql所有生效,若是rollback這三條sql所有失敗,不存在有的完成有的失敗,由於它們是一個不可再分割的總體。

一致性(Consistency):指數據庫的一種狀態的一致性,具體來講不可違反約束,不可違反規則,所謂的一致性就是一種人爲規則,例如定義一個主鍵,插入2條同樣的數據就違反了一致性條件。

實例

LEO1@LEO1>drop table leo2 purge;                                            清理環境

Table dropped.

LEO1@LEO1>create table leo2 (x number,ynumber,constraint pk_leo2 primary key(x));  x列有主鍵

Table created.

LEO1@LEO1>insert into leo2 values(1,1);

1 row created.

LEO1@LEO1>insert into leo2 values(1,2);                     當插入的值同樣時違反了一致性

insert into leo2 values(1,2)

*

ERROR at line 1:

ORA-00001: unique constraint (LEO1.PK_LEO2)violated

隔離性(isolation):未提交的事務其餘會話不可見。

實例

會話一

LEO1@LEO1>select * from leo2;               表裏只有1條記錄

        X          Y

---------- ------------------- ----------

        1          1

LEO1@LEO1>insert into leo2 values(2,2);        新插入一條

1 row created.

LEO1@LEO1>select * from leo2;               此時表裏有2條記錄,但未有提交

        X          Y

---------- ------------------- ----------

        1          1

        2          2

會話二

[oracle@leonarding1 flashback_area]$sqlplus leo1/leo1    鏈接新會話

LEO1@LEO1>select * from leo2;      只能看到已提交事務的數據,未提交的事務看不到

        X          Y

---------- ----------

        1          1

持久性(Durability):事務一旦提交就不可更改,永久有效。

實例

LEO1@LEO1>drop table leo3 purge;

Table dropped.

LEO1@LEO1>create table leo3 (x number,ynumber);

Table created.

LEO1@LEO1>insert into leo3 values(1,1);

1 row created.

LEO1@LEO1>commit;

Commit complete.

LEO1@LEO1>select * from leo3;

        X          Y

---------- ----------

        1          1

LEO1@LEO1>rollback;

Rollback complete.

LEO1@LEO1>select * from leo3;

        X          Y

---------- ----------

        1          1

事務一旦commit,你再rollback也是無效的,已經插進去了。

事務是以第一個DML語句做爲開始

如下面其中之一做爲結束

(1)    commit or rollback

(2)    DDL or DCL

(3) 用戶session正常結束  退出sqlplus

(4) 系統正常結束or終止  

事務自動提交,咱們能夠設置oracle自動提交事務

實例

LEO1@LEO1>show autocommit;                  默認是不啓動自動提交的

autocommit OFF

LEO1@LEO1>set autocommit on;                 手工啓動

LEO1@LEO1>show autocommit;

autocommit IMMEDIATE

LEO1@LEO1>insert into leo3 values(2,2);           當插入數據的同時就提交

1 row created.

Commit complete.

LEO1@LEO1>select * from leo3;

        X          Y

---------- ----------

         1         1

        2          2

LEO1@LEO1>rollback;                           此時回滾已無效

Rollback complete.

LEO1@LEO1>select * from leo3;

        X          Y

---------- ----------

        1          1

        2          2

LEO1@LEO1>set autocommit off;                  咱們不建議開啓事務自動提交功能

 

 Oracle下演示Nonrepeatable Read PhantomRead的例子,給出SQL演示過程。

Non-repeatable Read不可重複讀:在一個事務中,一樣的數據被2次讀取,獲得不一樣的結果集

實例

Leo幫tiger一塊兒買2張飛機表去肯尼亞看大象

LEO1@LEO1>drop table leo6 purge;

Table dropped.

LEO1@LEO1>create table leo6 (namevarchar2(10),ticket_type varchar2(20),price number);

Table created.

LEO1@LEO1>insert into leo6values('leo','plane_ticket',100);

1 row created.

LEO1@LEO1>insert into leo6values('tiger','plane_ticket',100);

1 row created.

LEO1@LEO1>commit;

Commit complete.

LEO1@LEO1>select * from leo6;

NAME      TICKET_TYPE               PRICE

---------- -------------------- ----------

leo         plane_ticket                100

tiger        plane_ticket                100

飛機票的價格都是100$,2我的一共200$

Leo查詢的價格

LEO1@LEO1>select sum(price) both_pricefrom leo6;

BOTH_PRICE

------------------

      200

在過行李安檢的時候,發現tiger行李超重,原來tiger很是有愛心,給大象帶了花生+毛豆,根據規定超重行李是要補交託運費的。

機場又加了100元託運費

LEO1@LEO1>update leo6 set price=200where name='tiger';

1 row updated.

LEO1@LEO1>select * from leo6;

NAME      TICKET_TYPE               PRICE

---------- -------------------- ----------

leo        plane_ticket                100

tiger       plane_ticket                200

LEO1@LEO1>commit;

Commit complete.

Leo再次查詢價格時,總價變成300了

LEO1@LEO1>select sum(price) both_pricefrom leo6;

BOTH_PRICE

------------------

      300

不可重複讀在數據庫中是可能出現的,因此要注意一下,上面leo和機場是兩個獨立會話

Phantom Read幻讀:在一個事務中,一樣的sql被2次執行,獲得不一樣的結果集。

實例

翻山越嶺 跋山涉水 終於來到了廣闊的非洲大草原真是大象遍地走 春風吹又生,tiger餚有興致的數起了大象

Tiger 查詢的結果

LEO1@LEO1>drop table leo7 purge;

Table dropped.

LEO1@LEO1>create table leo7 (namevarchar2(10),num number);

Table created.

LEO1@LEO1>insert into leo7values('a',1);

1 row created.

LEO1@LEO1>insert into leo7values('b',1);

1 row created.

LEO1@LEO1>commit;

Commit complete.

LEO1@LEO1>select count(*) from leo7;                    第一天發現了2只

COUNT(*)

-----------------

        2

傍晚有一隻小象跑了過來

LEO1@LEO1>insert into leo7values('c',1);

1 row created.

LEO1@LEO1>commit;

Commit complete.

次日tiger又查詢了一遍,此次發現了3只

LEO1@LEO1>select count(*) from leo7;

COUNT(*)

-----------------

       3

小結:上述兩個生動的例子展示了Non-repeatableRead不可重複讀和Phantom Read幻讀的過程,你們必定要好好體會裏面的含義,理解這兩種不一樣的數據讀取方式。

 

 Oracle設計一個場景,會致使Non-repeatableRead,而後選擇一種事務隔離等級來避免它的發生,給出SQL演示過程。

場景:tiger在遊玩非洲大草原以後,選擇從海路回家,在走到索馬里海岸的時候,有幸被海盜光顧,請他上岸吃海鮮,此次海盜拿出了坐享其成的敬業精神,贖金10000$,三天以內交換人質,一手交錢,一手交貨。因爲從來海盜的誠信記錄並非很光彩照人,咱們模擬了一下可能的突發事件。

首先海盜提出條件,贖金10000$,還爲此特地作了一個排行榜

LEO1@LEO1>create table leo8 (namevarchar2(20),cost int);          排行榜清單

Table created.

LEO1@LEO1>insert into leo8values('tiger',10000);                  插入tiger信息

1 row created.

LEO1@LEO1>commit;

Commit complete.

LEO1@LEO1>select * from leo8 whererownum<=1;                 咱們看到tiger排在第一位

NAME                    COST

---------------------------------------------------------------

tiger                     10000

上面的信息是咱們本身查詢的狀況,忽然海盜得知tiger是中國知名的IT專家,國家的財富和人才。本着生意人的精明頭腦,高價值的人固然換取的條件也水漲船高,海盜偷偷修改了贖金數,變成20000$

海盜

LEO1@LEO1>update leo8 set cost=20000where cost=10000;

1 row updated.

LEO1@LEO1>commit;

Commit complete.

當咱們交錢的時候發現tiger升值了,哎呦我去~ 這不打劫嘛!

LEO1@LEO1>select * from leo8 whererownum<=1;         

NAME                    COST

---------------------------------------------------------------

tiger                     20000

爲了防止這種事情發生,咱們可使用Oracle的Read-only事務隔離等級和Serializable事務隔離等級來避免這種事情發生,這兩種事務隔離等級很是類似,所以咱們選擇較經常使用的Serializable來給你們演示。

Read-only事務隔離等級:只能看到事務開始時全部提交的改變,自身不容許DML操做。

Serializable事務隔離等級:只能看到事務開始時全部提交的改變和自身的改變。

當海盜告知咱們贖金是10000$的時候,咱們先開出了清單

LEO1@LEO1>drop table leo8 purge;

Table dropped.

LEO1@LEO1>create table leo8 (namevarchar2(20),cost int);     tiger清單

Table created.

LEO1@LEO1>insert into leo8values('tiger',10000);

1 row created.

LEO1@LEO1>commit;

Commit complete.

LEO1@LEO1>set transaction isolationlevel serializable;         咱們設置好了隔離等級

Transaction set.

LEO1@LEO1>select * from leo8 whererownum<=1;             沒錯是10000$

NAME                    COST

---------------------------------------------------------------

tiger                     10000

海盜又故伎重演,想把價格提升到20000$,這是另外一個會話

LEO1@LEO1>update leo8 set cost=20000where cost=10000;      已經更新

1 row updated.

LEO1@LEO1>commit;

Commit complete.

到了較贖金的時候,咱們又查詢了一次

LEO1@LEO1>select * from leo8 whererownum<=1;

NAME                    COST

---------------------------------------------------------------

tiger                     10000

good,完美封殺了海盜邪惡企圖,數據沒有變化,但並非說數據沒有被修改,因爲啓動事務隔離策略,其餘事務所作的修改咱們是看不到的。Serializable只對當前事務有效,不對另外事務有效。

小結:Oracle中全部事務隔離等級都是依賴undo實現的。何時使用Serializable隔離等級好呢,當修改操做比較短的事務,事務中存在多條sql須要數據從事務開始時就保持一致,這樣的場景適合。

 

 用示例比較OracleRead committed Serializable 事務隔離等級的區別,給出SQL演示過程。

Read committed讀已提交事務隔離等級:Oracle 默認隔離等級,支持不可重複讀和幻讀。這兩種數據讀寫方式在第四題中已經徹底闡述了,這裏不在重複。

Serializable 事務隔離等級:只能看到事務開始時全部提交的改變和自身的改變,不支持不可重複讀和幻讀,事務開始是什麼樣子,結果就是什麼樣子,其餘用戶影響不了這個事務。

會話A

LEO1@LEO1>create table leo9(x int,yint);                 建立表

Table created.

LEO1@LEO1>insert into leo9values(100,100);              插入一行

1 row created.

LEO1@LEO1>commit;                                  提交

Commit complete.

LEO1@LEO1>set transaction isolationlevel serializable;       啓動Serializable 事務隔離等級

Transaction set.

LEO1@LEO1>select * from leo9;

        X          Y

---------- ----------------- ----------

       100       100

會話B,咱們用另外一個會話無論怎麼修改leo9表,都不會影響會話A事務

LEO1@LEO1>insert into leo9values(200,200);      

1 row created.

LEO1@LEO1>commit;

Commit complete.

LEO1@LEO1>insert into leo9values(300,300);

1 row created.

LEO1@LEO1>commit;

Commit complete.

會話A,仍是一條數據

LEO1@LEO1>select * from leo9;

        X          Y

---------- ----------------- ----------

       100       100

會話A本身修改的內容在事務中是生效的

LEO1@LEO1>insert into leo9values(400,400);          咱們插入一條記錄

1 row created.

LEO1@LEO1>select * from leo9;                     在本事務中是能夠看到的

        X          Y

---------- ----------

      400        400

      100        100

LEO1@LEO1>commit;                              一旦事務結束,Serializable 事務隔離等級就會失效

Commit complete.

會話A,又能夠看到全部的記錄了

LEO1@LEO1>select * from leo9;

        X          Y

---------- ----------

      400        400

      100        100

      200        200

      300        300

兩種事務隔離等級的比較

Read committed                       V.S                      Serializable   Transactions

支持SQL92標準                                               支持SQL92標準

讀取物化視圖 維護語句級一致性                                維護事務級一致性

事務一致性 支持語句級                                        支持事務級

行級鎖 支持                                                  支持

讀鎖定寫 不支持                                              不支持

寫鎖定讀 不支持                                              不支持

非行級鎖 不支持                                              不支持

行級鎖       支持                                                   支持

事務鎖等待 支持                                              支持
 

小結:Serializable事務隔離等級做用域是一個事務,超出這個事務就無效了。

 

事務屬性   Phantom Read   Non-repeatableRead   Read committed   Serializable

相關文章
相關標籤/搜索