oraclesql事務
⑴ oracle 資料庫隔離級別學習
oracle
事務隔離級別
事務不同引發的狀況:
臟讀(Dirty
reads)
一個事務讀取另一個事務尚未提交的修改時,產生臟讀
很多資料庫允許臟讀以避免排它鎖的競爭。
不可重復讀(Nonrepeatable
reads)
同一查詢在同一事務中多次進行,由於其他提交事務所做的修改或刪除,每次返回不同的結果集,此時發生非重復讀。
幻讀(Phantom
reads)
同一查詢在同一事務中多次進行,由於其他提交事務所做的插入操作,每次返回不同的結果集,此時發生幻像讀。
資料庫操作的隔離級別
未提交讀(read
uncommitted)
提交讀(read
committed)
重復讀(repeatable
read)
序列化(serializable)
oracle默認隔離級別read
committed
(statement
level
serialization)
每一個語句,在語句開始時,會獲取一個此刻的數據快照。
一個事務有多條語句,如果語句之間存在其它完成的事務,這可能引起不可持續讀和幻讀。
新建一個測試表books:
name,code,price三個欄位
添加兩條測試數據
使用pl/sql和java程序模擬並發
不允許臟讀測試:
程序段首先查詢code是qqq的書的價格
復制代碼
代碼如下:
//獲取連接
省略
pstat
=
conn.prepareStatement("select
price
from
books
where
code='qqq'");
rs
=
pstat.executeQuery();
while(rs.next()){
System.out.println("price:"+rs.getDouble(1));
}
close();
輸出結果:price:15.0
然後pl/sql執行更新
復制代碼
代碼如下:
update
books
set
price=18
where
code='qqq'
!pl/sql設置成手動更新,不自動更新
在執行上面java查詢代碼
輸出仍是price:15.0,說明讀不到pl/sql中未提交的執行結果,即不允許臟讀
pl/sql
執行
commit;
在執行java查詢:
輸出結果:price:18.0
會有不可重復讀何幻讀的現象發生就不用測試了吧,
這兩種現象都是針對提交後事物的讀引起的,read
commited隔離級別是允許對提交後
的事物進行讀的。
隔離級別:重復讀(repeatable
read)
這個不允許臟讀,不可重復讀,但是會有幻讀現象。
這個oracle不支持,不好測試。
理解的話就是如果一條查詢語句查詢的內容有其它事物正在更新的時候,這
查詢處於等待狀態,直到先前事物提交更新後,才會執行本條查詢。也就是
查詢的時候也會有鎖,需要等待並發的事物釋放鎖。然後自己獲取到鎖,執行
自己事物。這樣查詢也加鎖,並發性更低
select
...
for
update
就是這樣可以避免不可重復讀的發生
隔離級別:serializable
這個就更嚴格了,事物執行是一個一個的。一個事務中的語句共享同一個數據快照(在事務開始時存在的數據)。
是事物級別的,臟讀,不可重復讀,幻讀根本就沒有機會發生。
前面像read
committed都是語句級別的,以語句為單元。
比如
read
committed一個事物A有a(select),b(select),c(update)三條語句
當A事物執行a,b的時候,若有B事物執行更新操作,是有可能的
因為a,b是不加鎖的
例子:
復制代碼
代碼如下:
//獲取連接和關閉連接代碼
省略
//不自動提交
conn.setAutoCommit(false);
/**
*
a
查詢
*/
pstat
=
conn.prepareStatement("select
price
from
books
where
code='qqq'");
rs
=
pstat.executeQuery();
while(rs.next()){
//輸出
price:25.0
System.out.println("price:"+rs.getDouble(1));
}
close();
/**
*
暫停一會,用pl/sql執行B事務
*
update
books
set
price=15
where
code='qqq'
*
commit;
*/
Thread.sleep(10000);
/**
*
如果這里再執行a查詢的話,和第一次查詢結果就不一樣,因為中間有B事務的提交更新
*
修改,這也是不可重復讀
*/
//b
更新
pstat
=
conn.prepareStatement("update
books
set
price=price+10
where
code='qqq'");
pstat.executeUpdate();
close();
//c
查詢
pstat
=
conn.prepareStatement("select
price
from
books
where
code='qqq'");
rs
=
pstat.executeQuery();
while(rs.next()){
//輸出
還是price:25.0
,因為B事務的干預
System.out.println("price:"+rs.getDouble(1));
}
close();
//提交事務
conn.commit();
if(conn
!=
null){
conn.close();
}
上面執行的順序,事務B是在A的執行過程中執行的。
以上通過實例介紹了oracle資料庫隔離級別的相關內容,希望對大家有所幫助。
下面是一些補充:
資料庫中的事務基本作用是將資料庫從一致狀態轉換到另一種一致狀態,那麼事務隔離級別就是定義了一個事務對於另外一個事務做出的修改有多「敏感」。也就是不同的隔離級別定義了事務相互影響的程度,下面分別介紹一下幾種不同的隔離級別。
1.
READ
UNCOMMITTED
其實,oracle不支持這種隔離級別。這種隔離級別允許臟讀(也就是可以讀取到用戶未提交的數據),支持這種隔離級別的資料庫主要是為了支持非阻塞讀,但是oracle默認支持非阻塞讀,所以oracle裡面不支持這種隔離級別。下面舉一個例子:
如上圖所示,假設某一家銀行要統計所有賬號總共有多少金額。事務A負責統計,事務A從第一行開始讀取。假設讀取到100行的時候,事務B從賬號123轉了400元到賬戶987(事務B還未提交),支持臟讀的資料庫當事務A讀取到342023行的時候,就會得到500元,從而多加了400元。
2.
READ
COMMITTED
這種隔離級別指的是,事務只能讀取已經提交的數據,(但是支持可重復讀與幻想讀)是oracle資料庫默認的隔離模式。其實這種隔離級別在別的資料庫裡面可能還是會「退化」得像臟讀一樣。就看前面那個例子,假設在事務A讀取到342023行前,事務B提前鎖定了這一行,並將金額由100改成了500。那麼事務A讀取到這一行的時候,發現已經被其他事務鎖定了,於是進行等待,直到事務B提交。但是當事務B提交之後,事務A還是讀取到了500這一個錯誤信息,這樣就和臟讀一樣的了,而且還讓用戶等待這個錯誤的答案。
3.
REPEATABLE
READ
這種隔離級別不支持臟讀,不支持可重復讀,支持幻想讀。主要是為了得到一致性的答案與防止丟失更新。
a.
得到一致性答案
在oracle裡面這個通過多版本機製得到了實現,但是在其他的資料庫需要通過加鎖機制進行控制,就以上一個例子為例,怎樣才能統計出正確的總金額呢,事務A在讀取每一行的時候,給每一行加上共享讀鎖,這樣當事務B執行從賬號123轉400元到賬戶987的時候。先是操作第一行將賬戶123的金額由500修改成100,但是第一行已經被事務A鎖定,於是等待,這樣事務A能夠讀取到正確的數據。但是如果事務B執行的操作是從賬戶987轉50元到賬戶123的時候,事務B先操作第342023行,發現沒有被鎖定,於是鎖定將金額由100修改成50,然後操作第一行,發現鎖定了於是等待。而事務A讀取到342023行的時候,發現這一行已經被事務B鎖定於是等待,這樣就陷入了死鎖。
b.
丟失更新
在採用共享讀鎖的資料庫中,這種隔離級別可以防止丟失更新,比如事務1先讀取了第A行然後修改了這一行的C列(其他列也修改了只是值還和以前一樣,因為程序員都是整行的更新)。這個時候事務2想也想修改A行的時候會被阻塞,防止事務1的更新被覆蓋。
4.
SEAIALIZABLE
不允許臟讀,重復讀與幻想讀,最高的隔離級別。這種隔離級別標明事務A在操作資料庫的時候好像就只有事務A在操作,沒有其他事務在操作資料庫一樣。
Oracle
中是這樣實現
SERIALIZABLE
事務的:原本通常在語句級得到的讀一致性現在可以擴展到事務級。也就是在事務執行的那一刻,將這個事務將要操作的數據拍了一張照片。
從上面的例子我們可以看出,其他資料庫採用共享讀鎖來解決統計總金額問題是沒有oracle多版本機制靈活的,其一嚴重影響了程序的並發性,讀阻塞了寫。其二可能引起死鎖。
⑵ oraclesql執行順序優先順序
Oracle SQL執行順序優先順序為:
1. 解析與編譯階段。
2. 執行計劃生成。
3. 執行階段。
接下來是對這一執行順序的
解析與編譯階段: 這是SQL語句處理的第一個階段。在這一階段,Oracle會檢查語法,識別並驗證SQL語句中的表和列名,同時還會解析使用到的任何函數或過程。此外,還會根據對象定義和數據統計信息生成執行計劃的基礎結構。如果SQL語句被緩存或包含在一個命名塊中,那麼Oracle可能會跳過解析階段,直接使用已編譯的代碼。
執行計劃生成階段: 在解析和編譯之後,Oracle會生成執行計劃,這是根據解析和編譯過程中收集到的數據統計信息和對象定義來決定的。Oracle優化器會考慮多種可能的執行路徑並選擇成本最低的一種。這個計劃詳細說明了如何檢索數據以及如何以最高效的方式執行查詢。
執行階段: 這是最後一個階段,Oracle根據生成的執行計劃開始獲取數據並返回結果。根據計劃中的指示,它會訪問磁碟上的數據或將數據從內存緩存中檢索出來,對數據進行必要的操作並返回結果集。執行階段的具體細節取決於查詢的復雜性以及資料庫的配置和數據分布。
整體上,Oracle SQL的執行過程涉及多個階段和多個復雜的決策過程,從解析和編譯到執行計劃的生成和執行。了解這些階段的順序和每個階段的作用對於有效地編寫和優化SQL查詢至關重要。同時,還需要考慮到資料庫的性能和資源管理等方面的影響。
⑶ 什麼是事務,oracle和sql server 在事務處理上有何不同
事務可以看作是由對資料庫的若干操作組成的一個單元,這些操作要麼都完成,要麼都取消,從而保證數據滿足一致性的要求。事務的一個典型例子是銀行中的轉帳操作,帳戶A把一定數量的款項轉到帳戶B上,這個操作包括兩個步驟,一個是從帳戶A上把存款減去一定數量,二是在帳戶B上把存款加上相同的數量。這兩個步驟顯然要麼都完成,要麼都取消,否則銀行就會受損失。顯然,這個轉帳操作中的兩個步驟就構成一個事務。
資料庫中的事務還有如下ACID特徵。
ACID分別是四個英文單詞的首寫字母,這四個英文單詞是Atomicity、Consistency、Isolation、Durability,分別翻譯為原子性、一致性、隔離性、持久性。
在SQL Server中有三種事務類型,分別是:隱式事務、顯式事務、自動提交事務,預設為自動提交。
在Oracle中沒有SQL Server的這些事務類型,預設情況下任何一個DML語句都會開始一個事務,直到用戶發出Commit或Rollback操作,這個事務才會結束,這與SQL Server的隱式事務模式相似。