是一系列的數據庫操做,是數據庫應用的基本邏輯單位以及併發控制的基本單位。所謂的事務,它是一個操做序列,這些操做要麼都執行,要麼都不執行,它是一個不可分割的工做單位。數據庫
要將有組語句做爲事務考慮,就須要經過ACID測試,即原子性,一致性,隔離性和持久性。session
原子性、一致性或可串性、隔離性、持久性併發
▶ 原子性Atomic:即不可分割性,事務要麼所有被執行,要麼就所有不被執行。oracle
▶ 一致性或可串性Consistency:事務的執行使得數據庫從一種正確狀態轉換成另外一種正確狀態。ide
▶隔離性Isolation:事務容許多個用戶對同一個數據進行併發訪問,而不破壞數據的正確性和完整性。同時,並行事務的修改必須與其餘並行事務的修改相互獨立。在事務正確提交以前,不容許把該事務對數據的任何改變提供給任何其餘事測試
▶ 持久性Durability:事務正確提交後,其結果將永久保存在數據庫中,即便在事務提交後有了其餘故障,事務的處理結果也會獲得保存。ui
▶ 開始事物:begin transactionspa
▶ 提交事物:commit transaction3d
▶ 回滾事務:rollback transactionrest
用戶在事務(transaction)內能夠聲明(declare)被稱爲保存點(savepoint)的標記。保存點將一個大事務劃分爲較小的片段。
▶ save transaction 保存點名稱 --自定義保存點的名稱和位置
▶ rollback transaction 保存點名稱 --回滾到自定義的保存點
用戶可使用保存點(savepoint)在事務(transaction)內的任意位置做標記。以後用戶在對事務進行回滾操做(rolling back)時,就能夠選擇從當前執行位置回滾到事務內的任意一個保存點。
① 建立一張表以做示例
1 -- 建表 2 3 create table student( 4 id varchar2(4), 5 name varchar2(100), --姓名 6 sex varchar2(1), --性別 1 男 2 女 0 未知 7 score integer default 0 8 ); 9 10 select * from student; 11 12 -- 插入數據 13 14 insert into student (id, name, sex)values ('0001', '大王', '2'); 15 insert into student (id, name, sex)values ('0002', '劉一', '1'); 16 insert into student (id, name, sex)values ('0003', '陳二', '2'); 17 insert into student (id, name, sex)values ('0004', '張三', '0'); 18 insert into student (id, name, sex)values ('0005', '李四', '1'); 19 insert into student (id, name, sex)values ('0006', '王五', '0'); 20 insert into student (id, name, sex)values ('0007', '趙六', '1'); 21 insert into student (id, name, sex)values ('0008', '孫七', '2'); 22 insert into student (id, name, sex)values ('0009', '周八', '2'); 23 insert into student (id, name, sex)values ('0010', '吳九', '1'); 24 insert into student (id, name, sex)values ('0011', '鄭十', '1'); 25 commit;
② 以上表爲基礎的一個事務示例
1 CREATE OR REPLACE PROCEDURE p_transaction_test(p_error_no out int, --錯誤編號 2 p_error_info out varchar2 --錯誤信息 3 ) as 4 5 begin 6 /* 7 wangrui 事務commit測試 8 ①處commit:第一條更新成功,第二條更新失敗,回滾;因爲第二條失敗時,第一條已經提交。 9 ②處commit;第一條更新失敗,第二條更新失敗;因爲沒有提交,第二條失敗,語句還沒到②commit處已經回滾,兩條均未更新。 10 ③處commit;在此,跟②處的結果是同樣的,是對事物最後的提交。 11 12 Ⅰ處savepoint會使事務回滾到A爲止,若是此時①處有commit,會致使Ⅰ保存點失效,報錯,可是事務會回滾到①提交處 13 Ⅱ處savepoint會使事務回滾到B位置 14 注意:roll rollback to savepoint以後須要commit。不然事務回到savepoint以後,savepoint以前的得到的鎖並未被釋放 15 16 通常使用commit提交便可,不使用savepoint。 17 …… 18 */ 19 20 p_error_no := 0; 21 p_error_info := ' '; 22 begin 23 24 --Ⅰ 25 --savepoint save1; 26 27 update student set sex = '1' where id = '0001'; --一條會成功更新的SQL語句 28 29 --① 30 commit; 31 --Ⅱ 32 --savepoint save1; 33 34 update student set sex = '11' where id = '0002'; --一條語句超長,更新失敗的SQL語句 35 36 --② 37 --commit; 38 39 exception 40 when others then 41 rollback --to savepoint save1;commit 42 ; 43 p_error_no := -1; 44 p_error_info := '失敗:' || SQLERRM; 45 return; 46 end; 47 48 --③提交事務 49 commit; 50 51 end;
▶ 髒讀:若是一個事務讀取的記錄是另外一個未完成事務的一部分,就發生了髒讀。若是第一個事務正常完成,就沒有什麼問題。可是,若是前一個事務回滾了,那將從數據庫從未發生的事務中獲取了信息。
▶ 不可重複讀取:很容易將不可重複性讀取和髒讀混淆。若是一個事務中兩次讀取記錄,而另外一個事務在這期間改變了數據,就會發生不可重複性讀取。
▶ 幻讀:若是一個事務讀取一個記錄,返回結果集,此時,另外一個事務插入一條記錄並提交
只讀模式:只讀事務只能看到事務執行前就已經提交的數據,且事務中不能執執行 INSERT , UPDATE ,及 DELETE 語句
已提交讀取:Oracle 默認使用的事務隔離級別。事務內執行的查詢只能看到查詢執行前(而非事務開始前)就已經提交的數據。Oracle 的查詢永遠不會讀取髒數據(未提交的數據)。
Oracle 不會阻止一個事務修改另外一事務中的查詢正在訪問的數據,所以在一個事務內的兩個查詢的執行間歇期間,數據有可能被其餘事務修改。舉例來講,若是一個事務內同一查詢執行兩次,可能會遇到不可重複讀取或不存在讀取的現象。
串行化:串行化隔離的事務只能看到事務執行前就已經提交的數據,以及事務內 INSERT , UPDATE ,及 DELETE 語句對數據的修改。串行化隔離的事務不會出現不可重複讀取或不存在讀取的現象。
1 --只容許select操做,不容許有任何修改數據庫(包括 insert、update、delete)中數據的操做語句,容許建立語句create 2 set transaction read only; 3 --默認設置,表示在事務中能夠有訪問語句、修改語句(包括insert、delete、update),容許建立語句create,同read committed 4 set transaction read write; 5 --同read write; 6 set transaction isolation level read committed; 7 --serialzable能夠執行DML操做 8 set transaction isolation level serializable;
3.1 read only
新建一個事務以下
set transaction read only;
① 執行
select * from student;
② 執行
update student set score = 100 where id = '0002';
① 新建一個事務以下
set transaction read write;
② 執行
select * from student;
② 執行
update student set score = 100 where id = '0002';
select * from student;
結論:容許讀寫(包括insert、delete、update)
新建兩個事務以下
① 新建事務T1
set transaction read write;
select * from student;
② 新建事務T2
set transaction isolation level read committed;
select * from student;
③ 在事務T1中修改ID=002的記錄並commit;
update student set score = 100 where id = '0002';--未commit狀態下在T2事務中並未看到更新
commit;
④ 在事務T2 中查看commit後的結果以下(commit狀態下看到更新結果)
select * from student;
⑤ 在事務T1中刪除ID=003的記錄, 並commit;
delete from student where id='0003';--未commit時在T2中還能夠看到該條記錄
commit;
⑥ 在事務T2 中查看commit後的結果以下(commit以後看不到該條記錄)
⑦ 在事務T1中插入ID=0006的記錄,並commit;
insert into student (id, name, sex)values ('0006', '王五', '0');--未commit以前在T2中看不到該條記錄
commit;
⑧ 在事務T2 中查看commit後的結果以下(commit以後看到該條記錄已經添加)
結論:①-⑥ 說明事務隔離級別爲isolation level read committed時,容許可重複讀。
⑦-⑧ 說明事務隔離級別爲 isolation level read committed, 容許幻想讀
建立了兩個事務以下
① 新建事務T1
set transaction read write;
select * from student;
② 新建事務T2
set transaction isolation level serializable;
select * from student;
③ 在事務T1中修改ID=002的記錄並commit;
update student set score = 100 where id = '0002';--未commit狀態下在T2事務中並未看到更新
commit;
④ 在在事務T2 中查看commit後的結果以下(commit狀態下也沒有看到更新)
⑤ 在事務T1中刪除ID=003的記錄, 並commit;
delete from student where id='0003';--未commit時在T2中還能夠看到該條記錄
commit;
⑥ 在事務T2 中查看commit後的結果以下(commit狀態下依然能夠看到該條記錄)
⑦ 在事務T1中插入ID=0006的記錄,並commit;
insert into student (id, name, sex)values ('0006', '王五', '0');--未commit以前在T2中看不到該條記錄
commit;
⑧ 在事務T2 中查看commit後的結果以下(commit狀態下依然看不到該條記錄)
結論:①-⑥ 說明事務隔離級別爲isolation level serializable時,不支持可重複讀。
⑦-⑧ 說明事務隔離級別爲 isolation level serializable 時, 不支持幻想讀
鎖是一種機制,多個事務同時訪問一個數據庫對象時,該機制能夠實現對併發的控制
ORCLE 多事務併發可能存在的問題
丟失更新:丟失更新發生在一個更新成功寫入數據庫後,而又意外地被另外一個事務重寫時。這是怎麼發生的呢?若是有兩個事務讀取整個記錄,而後其中一個向記錄寫入了更新信息,而另外一個事務也向該記錄寫入更新信息,這是就會出現丟失更新。
① DML鎖(data locks,數據鎖),用於保護數據的完整性。oracle自動的施加和釋放。
② DDL鎖(dictionary locks,字典鎖),用於保護數據庫對象的結構,如表、索引等的結構定義. 事務開始時施加,使用Commit後者Rollback被釋放。
③ 內部鎖和閂(internal locks and latches),保護數據庫的內部結構。由oracle本身管理以保護內部數據庫結構。
① 行級鎖(TX):阻止該行上的DML操做,直到Commit或者Rollback。
② 表級鎖(TM):
③ 數據庫級鎖::
eg:將數據庫鎖定爲只讀模式 alter database open read only;
eg:將數據庫設置爲限制模式(導入導出數據庫時使用):alter system enable restricted session;
1 lock table student in row share mode; 2 lock table student in row exclusive mode; --用於行的修改 3 lock table student in share mode; --阻止其餘DML操做 4 lock table student in share row exclusive mode; --阻止其餘事務操做 5 lock table student in exclusive mode; --獨立訪問使用
① 建立一個事務,執行
update student set score=888 WHERE ID='0004';
② 執行
select * from v$locked_object; --object_id爲表名
③ 執行
1 select s.sid, s.serial#, s.username, s.schemaname, s.osuser, s.process, s.machine, s.terminal, s.logon_time, l.type, l.lmode 2 from v$session s, v$lock l 3 where s.sid = l.sid 4 and s.sid= '3231' 5 order by sid;
如圖,DML操做,得到一個TM鎖,還得到一個TX鎖,還有一個……,故而其餘事務能夠對該表的其餘行進行編輯,可是0004行不容許其餘事務有任何操做。
咱們能夠認爲Oracle 6種MODE的鎖,根據鎖定的對象不一樣而有不一樣的名稱,如6號的X鎖,既能夠是用於鎖表的TM鎖,也能夠是TX鎖,也能夠是DDL鎖。
若是一個鎖因爲另外一個鎖佔有資源而不能完成應該作的工做,就會致使死鎖;反之亦然。
① Mutual exclusion(互斥):資源不能被共享,只能由一個進程使用。
② Hold and wait(請求並保持):已經獲得資源的進程能夠再次申請新的資源。
③ No pre-emption(不可剝奪):已經分配的資源不能從相應的進程中被強制地剝奪。
④ Circular wait(循環等待條件):系統中若干進程組成環路,該環路中每一個進程都在等待相鄰進程正佔用的資源。
① 查看錶內容
select * from student;
② 新建一個事務T1,執行
update student set score=111 WHERE ID='0002';
未提交狀態下提示一行被更新
③ 新建一個事務T2,執行
update student set score=333 WHERE ID='0003';
未提交狀態下提示一行被更新
④ 在事務T1中執行
update student set score=222 WHERE ID='0003';
顯示「正在執行……」表示等待中
⑤ 在事務T2中執行
update student set score=444 WHERE ID='0002';
此時,事務T2顯示「正在執行……」表示等待,T1事務是提交或者回滾狀態
⑥ commit 事務T1
顯示事務T1只更新了0002,0003並未更新成功。
⑦ commit 事務T2,而後查看結果
顯示事務T2更新了0002,0003,至關於事務T1的結果丟失了。
在沒有執行⑥⑦操做的狀況下
新⑥ 執行
select sid,serial#,username from v$session where sid in (select blocking_session from v$session);
alter system kill session '1522,42255';
第一行代碼找到sid='1522,serial#=42255'
第二行代碼殺掉這個堵塞的進程
新⑦ 此時,提交進程事務T1,結果顯示。
新⑧ 提交事務T2,顯示提交成功,查看結果
顯示事務T2更新了0002,0003,至關於事務T1的結果丟失了。
結論:oracle在死鎖狀況下,會保存後面一個事務的更新結果。
① 避免應用不運行長事務。
② 常常提交以免長時間鎖定行。
③ 避免使用LOCK命令鎖定表。
⑤ 在高峯期間執行DDL操做,在非高峯期間執行長時間運行的查詢或事務。