事務是什么?
事務是一系列的數據庫操作,是數據庫應用的基本單位。MySQL 事務主要用於處理操作量大,復雜度高的數據。
事務有哪些特性?
在 MySQL 中只有 InnDB 引擎支持事務,它的四個特性如下:
- 原子性(Atomic):要么全部執行,要么全部不執行;
- 一致性(Consistency):事務的執行使得數據庫從一種正確狀態轉化為另一種正確狀態;
- 隔離性(Isolation):在事務正確提交之前,不允許把該事務對數據的任何改變提供給其他事務;
- 持久性(Durability):事務提交后,其結果永久保存在數據庫中。
MySQL 中有幾種事務隔離級別?分別是什么?
MySQL 中有四種事務隔離級別,它們分別是:
- read uncommited:未提交讀,讀到未提交數據;
- read committed:讀已提交,也叫不可重復讀,兩次讀取到的數據不一致;
- repetable read:可重復讀;
- serializable:串行化,讀寫數據都會鎖住整張表,數據操作不會出錯,但並發性能極低,開發中很少用到。
MySQL 默認使用 REPEATABLE-READ 的事務隔離級別。
幻讀和不可重復讀的區別?
- 不可重復讀的重點是修改:在同一事務中,同樣的條件,第一次讀的數據和第二次讀的數據不一樣。(因為中間有其他事務提交了修改)。
- 幻讀的重點在於新增或者刪除:在同一事務中,同樣的條件,,第一次和第二次讀出來的記錄數不一樣。(因為中間有其他事務提交了插入/刪除)。
並發事務一般有哪些問題?
- 更新丟失(Lost Update):當兩個或多個事務選擇同一行,然后基於最初選定的值更新該行時,由於每個事務都不知道其他事務的存在,就會發生丟失更新問題,最后的更新覆蓋了由其他事務所做的更新。例如,兩個編輯人員制作了同一文檔的電子副本,每個編輯人員獨立地更改其副本,然后保存更改后的副本,這樣就覆蓋了原始文檔。 最后保存其更改副本的編輯人員覆蓋另一個編輯人員所做的更改,如果在前一個編輯人員完成並提交事務之前,另一個編輯人員不能訪問同一文件,則可避免此問題。
- 臟讀(Dirty Reads):一個事務正在對一條記錄做修改,在這個事務完成並提交前, 這條記錄的數據就處於不一致狀態; 這時, 另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些臟數據,並據此做進一步的處理,就會產生未提交的數據依賴關系,這種現象被形象地叫做臟讀。
- 不可重復讀(Non-Repeatable Reads):一個事務在讀取某些數據后的某個時間,再次讀取以前讀過的數據,卻發現其讀出的數據已經發生了改變、或某些記錄已經被刪除了!這種現象就叫做“不可重復讀” 。
- 幻讀(Phantom Reads): 一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就稱為“幻讀” 。
並發事務有什么什么問題?應該如何解決?
並發事務可能造成:臟讀、不可重復讀和幻讀等問題 ,這些問題其實都是數據庫讀一致性問題,必須由數據庫提供一定的事務隔離機制來解決,解決方案如下:
- 加鎖:在讀取數據前,對其加鎖,阻止其他事務對數據進行修改。
- 提供數據多版本並發控制(MultiVersion Concurrency Control,簡稱 MVCC 或 MCC),也稱為多版本數據庫:不用加任何鎖, 通過一定機制生成一個數據請求時間點的一致性數據快照(Snapshot), 並用這個快照來提供一定級別 (語句級或事務級) 的一致性讀取,從用戶的角度來看,好象是數據庫可以提供同一數據的多個版本。
什么是 MVCC?
MVCC 全稱是多版本並發控制系統,InnoDB 和 Falcon 存儲引擎通過多版本並發控制(MVCC,Multiversion Concurrency Control)機制解決幻讀問題。
MVCC 是怎么工作的?
InnoDB 的 MVCC 是通過在每行記錄后面保存兩個隱藏的列來實現,這兩個列一個保存了行的創建時間,一個保存行的過期時間(刪除時間)。當然存儲的並不是真實的時間而是系統版本號(system version number)。每開始一個新的事務,系統版本號都會自動新增,事務開始時刻的系統版本號會作為事務的版本號,用來查詢到每行記錄的版本號進行比較。
REPEATABLE READ(可重讀)隔離級別下 MVCC 如何工作?
- SELECT:InnoDB 會根據以下條件檢查每一行記錄:第一,InnoDB 只查找版本早於當前事務版本的數據行,這樣可以確保事務讀取的行要么是在開始事務之前已經存在要么是事務自身插入或者修改過的。第二,行的刪除版本號要么未定義,要么大於當前事務版本號,這樣可以確保事務讀取到的行在事務開始之前未被刪除。
- INSERT:InnoDB 為新插入的每一行保存當前系統版本號作為行版本號。
- DELETE:InnoDB 為刪除的每一行保存當前系統版本號作為行刪除標識。
- UPDATE:InnoDB 為插入的一行新紀錄保存當前系統版本號作為行版本號,同時保存當前系統版本號到原來的行作為刪除標識保存這兩個版本號,使大多數操作都不用加鎖。它不足之處是每行記錄都需要額外的存儲空間,需要做更多的行檢查工作和一些額外的維護工作。
MySQL 事務實現原理是什么?
事務的實現是基於數據庫的存儲引擎,不同的存儲引擎對事務的支持程度不一樣。MySQL 中支持事務的存儲引擎有InnoDB 和 NDB。 InnoDB 是高版本 MySQL 的默認的存儲引擎,因此就以 InnoDB 的事務實現為例,InnoDB 是通過多版本並發控制(MVCC,Multiversion Concurrency Control )解決不可重復讀問題,加上間隙鎖(也就是並發控制)解決幻讀問題。因此 InnoDB 的 RR 隔離級別其實實現了串行化級別的效果,而且保留了比較好的並發性能。事務的隔離性是通過鎖實現,而事務的原子性、一致性和持久性則是通過事務日志實現。
如何設置 MySQL 的事務隔離級別?
MySQL 事務隔離級別 MySQL.cnf 文件里設置的(默認目錄 /etc/my.cnf),在文件的文末添加配置:
transaction-isolation = REPEATABLE-READ
可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。
InnoDB 默認的事務隔離級別是什么?如何修改?
InnoDB 默認的事務隔離是 repetable read(可重復讀);可以通過 set 作用域 transaction isolation level 事務隔離級別 來修改事務的隔離級別,比如:
MySQL> set global transaction isolation level read committed; // 設置全局事務隔離級別為 read committed
MySQL> set session transaction isolation level read committed; // 設置當前會話事務隔離級別為 read committed
InnoDB 如何開啟手動提交事務?
InnoDB 默認是自動提交事務的,每一次 SQL 操作(非 select 操作)都會自動提交一個事務,如果要手動開啟事務需要設置 set autocommit=0 禁止自動提交事務,相當於開啟手動提交事務。
在 InnoDB 中設置了 autocommit=0,添加一條信息之后沒有手動執行提交操作,請問這條信息可以被查到嗎?
autocommit=0 表示禁止自動事務提交,在添加操作之后沒有進行手動提交,默認情況下其他連接客戶端是查詢不到此條新增數據的。
如何手動操作事務?
使用 begin 開啟事務;rollback 回滾事務;commit 提交事務。具體使用示例如下:
begin;
insert person(uname,age) values('laowang',18);
rollback;
commit;