2 s锁是什么_innodb存储引擎读书笔记:锁
myisam引擎的鎖是表鎖,在并發插入時性能較差。
innodb實現了兩種行級鎖:
共享鎖(S lock)
排他鎖(X lock)
當一個事務獲取了行r的共享鎖是,其他的事務也可以獲取行r的共享鎖,如果其他事務想獲取行r的排他鎖,必須等待共享鎖釋放。
innodb允許行級鎖和表級鎖同時存在。
innodb實現了意向鎖,意向鎖是表級鎖。意向鎖有兩種:
意向共享鎖(IS lock):表示事務想獲取表中某幾行的共享鎖
意向排他鎖(IX lock):表示事務想獲取表中某幾行的排他鎖
意向鎖不會阻塞除全表掃描之外的任何請求。
information_schema.INNODB_TRX表的字段有:
trx_id:innodb引擎內部唯一的事務id
trx_state:事務的當前狀態
trx_started:事務的開始時間
trx_request_lock_id:如果trx_state為LOCK WAIT,則此字段的值表示事務等待的鎖的id;如果trx_state不為LOCK WAIT,則此字段為null
trx_wait_started:事務開始等待的時間點
trx_weight:事務的權重,反映了一個事務修改和鎖住的行數。當發生死鎖需要回滾的時候,innodb會選擇權重最小的事務進行回滾。
trx_mysql_thread_id:事務對應的線程的id
trx_query:事務中的sql
information_schema.innodb_locks表的字段有:
lock_id:鎖的id
lock_trx_id:獲取了鎖的事務的id
lock_mode:鎖的模式
lock_type:鎖的類型,表鎖還是行鎖
lock_table:對哪個表加了鎖
lock_index:對哪個索引加了鎖
lock_space:表空間的id
lock_page:被鎖住的頁的數量,lock_type為表鎖時該字段為null
lock_rec:被鎖住的行的數量,lock_type為表鎖時該字段為null
lock_data:被鎖住的行的主鍵,lock_type為表鎖時該字段為null
information_schema.innodb_lock_waits的字段有:
requesting_trx_id:申請鎖的事務的id
requesting_lock_id:申請的鎖的id
blocking_trx_id:哪個事務阻塞了requesting_trx_id
blocking_lock_id:哪個鎖阻塞了requesting_lock_id
示例如下(為什么blocking_lock_id和requested_lock_id不是同一個鎖?導致當前事務阻塞的鎖竟然不是當前事務正在請求的鎖?確實不一樣,事務730FEE對行記錄加了X鎖,而事務7311F4要對該行記錄加S鎖。):
一致性的非鎖定讀:innodb通過多版本控制讀取當前時刻數據庫中的行記錄。如果讀取的行記錄正在被delete、update,讀取操作不等待行上鎖的釋放,而會去讀取該行的一個快照。這個快照實際上是undo段。一致性的非鎖定讀是innodb默認的讀取方式。
多版本并發控制MVCC:multi version concurrency controll。
多版本指的是快照有多個版本。
在repeatable read(innodb默認的事務隔離級別)和read committed下,innodb使用一致性非鎖定讀,但是對快照的定義不同。
read committed下,一致性非鎖定讀總是讀取最新的快照。
repeatable read下,一致性非鎖定讀總是讀取事務開始時的行數據版本。
(突然想到的一個疑問:事務內的每一次對行記錄的操作,是否會操作完就釋放鎖?還是說會等到事務提交之后一起釋放?
驗證:
先在事務A中獲取行記錄上的S鎖:
再在事務B中獲取該行記錄上的X鎖:
可以看到事務B阻塞了。查看INNODB_TRX表也可以看到如下信息:
因此說明了事務中獲取的S鎖要等到事務結束后再釋放,X鎖也是如此。這個特性與事務的隔離級別無關。
)
查看事務隔離級別:
select @@tx_isolation;
設置事務隔離級別:
set [global | session] transaction isolation level Read uncommitted | Read committed | Repeatable Read | Serializable;
如果選擇global,則隔離級別將應用于之后新建的session,而當前已經存在的session(包括當前session)不受影響。
如果選擇session,則隔離級別將應用于當前session內之后的所有事務,其他已經存在的session和之后新創建的session均不受影響。
如果事務隔離級別為repeatable read,則session A中的三次讀都會讀到id=1的記錄。如果事務隔離級別為read committed,則session A中的前兩次讀都會讀到id=1的記錄,但是第三次讀會返回空集。(已驗證)
innodb中select操作默認使用一致性非鎖定讀。
如果到對select操作加鎖:
??? select ... for update:對讀取的行記錄加X鎖,其他事務如果要在該行上加任何鎖都會被阻塞。
??? select ... in share mode:對讀取的行記錄加S鎖,其他事務可以對該行加S鎖,但是要加X鎖就會被阻塞。
注意:
1. select操作加鎖后,其他事務仍然可以執行一致性非鎖定讀select操作。
2. 事務提交后select上的鎖才會被釋放。默認情況下,執行一條語句就是一次事務,所以select ... for update和select ... in share mode執行完后鎖就被釋放。
AUTO-INC Locking:在執行插入操作時,自增長列(一般就是指主鍵)的值由自增長計數器確定。從自增長計數器中取值時,需要先上鎖。
這種鎖是表級鎖,但是卻不會在事務完成之后才釋放,而是在完成插入操作后立即釋放。
參數innodb_autoinc_lock_mode:
取0時表示上文所提的加鎖方式;
取1(默認值)時表示在進行simple inserts(插入前就能確定插入的行數)時采用互斥量對計數器進行累加,在進行bulk inserts(插入前不能確定插入的行數)時采用上文提到的加鎖方式。
取2時表示對于所有的insert操作都采用互斥量。
innodb中,如果一個表中定義了自增長列,則該列上必須建索引,如果聯合索引中包含該列,則該列必須是第一列。
innodb中,外鍵列會自動被加上一個索引,避免表鎖。
插入或更新外鍵列時,首先會select父表,為保證數據一致,會使用select ... lock in share mode,而不是一致性非鎖定讀。
innodb中行鎖分類:
record lock:行記錄上的鎖
gap lock:間隙鎖,鎖定一個范圍,但不包含記錄本身
next-key lock:等價于record lock + gap lock。
innodb中,默認的事務隔離級別是repeatable read。這種隔離級別下,next-key lock是默認的行記錄鎖定算法。
repeatable read隔離級別下,先在事務A中執行select * from t where a < 6 lock in share mode,再在事務B中執行insert into t select 5或insert into t select 6,事務B會阻塞住。如果在事務B中執行insert into t select 9,則會直接執行成功。事務A中的select會被加上next-key share lock。
repeatable read隔離級別下,先在事務A中執行select * from t where a = 7 lock in share mode,再在事務B中執行insert into t select 5或insert into t select 6,則會直接執行成功。事務A中的select會被加上record share lock。
lost update:
場景(時間線順序):
事務1查詢一行記錄
事務2也查詢該行記錄
事務1更新該行記錄
事務2更新該行記錄
結果是事務1的更新被覆蓋了。
如何避免?
事務在查詢時就加上排他鎖。
臟數據:已被修改但還未被提交的數據。
臟讀:一個事務讀到另一個事務中的臟數據。
隔離級別為read uncommitted時就會出現臟讀。
不可重復讀:同一個事務內,多次讀同一行記錄,讀到的數據不同。原因是,在該事務內的兩次select操作之間,其他事務修改了該行記錄,并提交了。
隔離級別為read committed時會出現不可重復讀。
事務之間可能會因鎖的問題產生阻塞。
innodb_lock_wait_timeout:超時時間,可以在運行時修改。默認是50s。
innodb_rollback_on_timeout:超時是是否對事務進行回滾,不可在運行時修改。默認是OFF。
mysql中,事務中拋出異常時,mysql一般不會對事務進行回滾,而是等待用戶決定是要提交還是回滾。但是發生死鎖時,innodb會自動對其中一個事務進行回滾。
總結
以上是生活随笔為你收集整理的2 s锁是什么_innodb存储引擎读书笔记:锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: catia过载属性使用方法_CATIA-
- 下一篇: ffmpeg 怎么处理udp音频_STR