天天看點

Oracle 與 MySQL 的差異分析(9):事務

Oracle 與 MySQL 的差異分析(9):事務

1 自動送出

1.1Oracle

預設不會自動送出,需要顯式的送出或復原。如果斷開連接配接時有未送出事務,用戶端工具一般可以配置自動送出或復原。

1.2 MySQL

InnoDB支援事務,預設是自動送出的。

關閉自動送出的方法:

(1)會話級關閉:

set autocommit = 0; // 1表示開啟

檢查是否關閉:

show variables like “autocommit”;

結果:autocommit OFF

(2)全局關閉:

set global autocommit = 0 或者把 autocommit=0 加到參數檔案中。

注:在開啟自動送出情況下,可以用starttransaction; 開啟一個事務,然後就不會自動送出了。

2 鎖級别

2.1Oracle

DML語句産生行鎖,鎖資訊儲存在資料塊上,隻有被更新的資料會被鎖定。

2.2 MySQL

不同引擎使用不同的鎖級别,InnoDB預設也是行鎖,但是它鎖定的是索引條目,這一點與Oracle顯著不同,如果沒有通過索引來更新資料的話,那麼就會鎖定整個表。需要注意:

(1)雖然查詢列上有索引,但是優化器仍然可能選擇全表掃描,由于沒有通過索引通路資料,此時仍然是表鎖(鎖定所有資料)。

(2)通過A索引查出的資料,雖然被B條件過濾掉了,但是該資料仍然會被鎖定。比如,userid = 1and username = ‘a’ 如果是走了userid的索引,雖然沒有更新username = ‘b’的資料,但是試圖通過userid = 1and username = ‘b’ 更新資料時也會被阻塞。

(3)如果通過userid > 1 來更新資料,并且走userid的索引,那麼會鎖定所有userid >1 的資料,包括未插入的資料,是以此時insert一條userid = 100 的資料時也會被阻塞。這一點與Oracle很不同,Oracle的insert語句一般不會被阻塞。

3 事務隔離級别

SQL标準中定義的隔離級别,隔離級别越高,并發性越差。

(1)Read Uncommitted:

B會話可以看到A會話未送出事務修改的資料(髒資料)。

(2)Read Commited:

A會話的事務送出了,B會話就可以看到修改的資料。

可以避免髒讀(讀到未送出的資料)。

(3)Repeatable:

A會話的一個事務内查詢同一個表的資料不會變化,即使B會話修改了資料并且已經送出。

可以避免不可重複讀問題(同一個SQL第二次發現資料已變化)。

(4)Serializable:

事務好像是串行的,它是在每個讀的資料上加上共享鎖。select相當于select ... from update。

可以避免幻影讀問題(同一個SQL第二次讀/寫不會看到新的資料)。

3.1Oracle

預設隔離級别是Read Commited,支援Serializable,不過一般不用。

3.2 MySQL

InnoDB預設事務隔離級别是Repeatable,其它幾種也支援。

查詢事務隔離級别:

select @@tx-isolation;

結果:REPEATABLE-READ

修改方法:

set session|global tx-isolation = ‘serializable’;

4 鎖逾時時間

4.1Oracle

如果A會話鎖定了某條資料,那麼B會話試圖更新這條資料時會被阻塞,并且會一直等待。

4.2 MySQL

MySQL資料庫參數:innodb_lock_wait_timeout設定鎖等待的時間是50s,一旦資料庫鎖超過這個時間就會報逾時錯誤。

預設值有些小,建議改大些,代碼需要考慮這個特性,鎖定資料有失敗的風險,需要捕獲異常,這一點與Oracle不同。