固然有的人用begin /begin work .推薦用START TRANSACTION 是SQL-99標準啓動一個事務。mysql
start transaction #開始一個事務 操做 savepoint sp1 #保存點名稱 操做 ROLLBACK ROLLBACK To sp1 #回退到 sp1點 commit
當用set autocommit = 0 的時候,你之後全部的sql都將做爲事務處理,直到你用commit確認或 rollback結束,注意當你結束這個事務的同時也開啓了新的事務!mysql 默認 autocommit=1,是自動提交的。算法
SQL標準定義的四個隔離級別爲:sql
1.讀未提交(Read Uncommitted):在READ COMMITED的事務隔離級別下,除了惟一性的約束檢查以及外鍵約束的檢查須要Gap Lock,InnoDB存儲引擎不會使用Gap Lock的鎖算法。這種隔離級別可讓當前事務讀取到其它事物尚未提交的數據。這種讀取應該是在回滾段中完成的。經過上面的分析,這種隔離級別是最低的,會致使引起髒讀,不可重複讀,和幻讀。
2.讀已提交(Read Committed):這種隔離級別可讓當前事務讀取到其它事物已經提交的數據。經過上面的分析,這種隔離級別會致使引起不可重複讀,和幻讀。
3.可重複讀取(Repeatable Read):這種隔離級別能夠保證在一個事物中屢次讀取特定記錄的時候都是同樣的。經過上面的分析,這種隔離級別會致使引起幻讀。
4.串行(Serializable):在SERIALIZBLE的事務隔離級別,InnoDB存儲引擎會對每一個SELECT語句後自動加上LOCK IN SHARE MODE,即給每一個讀取操做加一個共享鎖,所以在這個事務隔離級別下,讀佔用鎖了,一致性的非鎖定讀再也不予以支持,通常再也不本地事務中使用SERIALIZBLE的隔離級別,SERIALIZABLE的事務隔離級別主要用於InnoDB存儲引擎的分佈式事務。數據庫
查看當前會話的事務隔離級別安全
mysql> select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.03 sec)
查看全局事務隔離級別併發
mysql> select @@global.tx_isolation; +-----------------------+ | @@global.tx_isolation | +-----------------------+ | REPEATABLE-READ | +-----------------------+ 1 row in set (0.04 sec)
經過XA事務能夠來支持分佈式事務的實現,在使用分佈式事務時,InnoDB存儲引擎必須使用SERIALIZABLE的隔離級別,查看是否啓用了XA事務支持(默認開啓)分佈式
mysql> show variables like 'innodb_support_xa'; +-------------------+-------+ | Variable_name | Value | +-------------------+-------+ | innodb_support_xa | ON | +-------------------+-------+
悲觀鎖,正如其名,它指的是對數據被外界(包括本系統當前的其餘事務,以及來自外部系統的事務處理)修改持保守態度,所以,在整個數據處理過程當中,將數據處於鎖定狀態。悲觀鎖的實現,每每依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,不然,即便在本系統中實現了加鎖機制,也沒法保證外部系統不會修改數據)。高併發
MySQL SELECT ... FOR UPDATE 的Row Lock 與Table Lock性能
舉個例子:測試
使用場景:機器池resource表中有一個字段 status,status=0表明機器未被使用,status =job_id(!=0)表示機器已被某個job使用,那麼分配機器時就要確保該機器 status=0。
若是不採用鎖,那麼操做方法以下:
1.查詢出機器信息:select resource_id from resource where status=0 limit 1; 2.將該機器分配給該 job:update resource set status=<job_id> where resource_id =<剛查出的>;
上面這種場景在高併發訪問的狀況下極可能會出現問題:在A鏈接查出 status=0的任務時,當咱們執行到第二步時 update時,可能有B 鏈接已經先把該 resource 的status更新爲該 job_id,當 A 鏈接再更新時,會將 B 的更新覆蓋掉。因此說這種方式是不安全的
因此應該使用鎖機制,當咱們在查詢出goods信息後就把當前的數據鎖定,直到咱們修改完畢後再解鎖。
設置MySQL爲非autocommit模式: set autocommit=0; 設置完autocommit後,咱們就能夠執行咱們的正常業務了。具體以下: //0.開始事務 begin;/begin work;/start transaction; (三者選一就能夠,推薦start transaction) //1.查詢出商品信息 select resource_id from resource where status=0 limit 1 for update; //2.修改商品status爲2 update resource set status=<job_id> where resource_id=<resource_id>; //4.提交事務 commit;/commit work;
假設有個表單products ,裏面有id 跟name 二個欄位,id 是主鍵。
例1: (明確指定主鍵,而且有此數據,row lock)
SELECT * FROM products WHERE id='3' FOR UPDATE;
例2: (明確指定主鍵,若查無此數據,無lock)
SELECT * FROM products WHERE id='-1' FOR UPDATE;
例2: (無主鍵,table lock)
SELECT * FROM products WHERE name='Mouse' FOR UPDATE;
例3: (主鍵不明確,table lock)
SELECT * FROM products WHERE id<>'3' FOR UPDATE;
例4: (主鍵不明確,table lock)
SELECT * FROM products WHERE id LIKE '3' FOR UPDATE;
注1: FOR UPDATE 僅適用於InnoDB,且必須在事務區塊(start sta/COMMIT)中才能生效。
注2: 要測試鎖定的情況,能夠利用MySQL 的Command Mode ,開二個視窗來作測試。
以上就是關於數據庫主鍵對MySQL鎖級別的影響實例,須要注意的是,除了主鍵外,使用索引也會影響數據庫的鎖定級別
由於悲觀鎖大多數狀況下依靠數據庫的鎖機制實現,以保證操做最大程度的獨佔性。若是加鎖的時間過長,其餘用戶長時間沒法訪問,影響了程序的併發訪問性,同時這樣對數據庫性能開銷影響也很大,特別是對長事務而言,這樣的開銷每每沒法承受。因此與悲觀鎖相對的,咱們有了樂觀鎖,具體參見下面介紹:
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認爲數據通常狀況下不會形成衝突,因此在數據進行提交更新的時候,纔會正式對數據的衝突與否進行檢測,若是發現衝突了,則讓返回用戶錯誤的信息,讓用戶決定如何去作。那麼咱們如何實現樂觀鎖呢,通常來講有如下2種方式:
1.使用數據版本(Version)記錄機制實現,這是樂觀鎖最經常使用的一種實現方式。何謂數據版本?即爲數據增長一個版本標識,通常是經過爲數據庫表增長一個數字類型的 「version」 字段來實現。當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當咱們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的version值進行比對,若是數據庫表當前版本號與第一次取出來的version值相等,則予以更新,不然認爲是過時數據。用下面的一張圖來講明:
舉例:
仍是機器池資源表 resource ,除了resource_id,machine_name,status,再增長 version字段,
1.查詢出機器信息: select resource_id,version from resource where status=0 limit 1; 2.將該機器分配給該 job: update resource set status=<job_id> where resource_id =<剛查出的> and version=<剛查出 version+1>;
這樣就實現了樂觀鎖。