<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
RR 支援 gap lock(next-key lock),而RC則沒有gap lock。因為MySQL的RR需要gap lock來解決幻讀問題。而RC隔離級別則是允許存在不可重複讀和幻讀的。所以RC的並行一般要好於RR;
RC 隔離級別,通過 where 條件走非索引列過濾之後,不符合條件的記錄上的行鎖,會釋放掉(雖然這裡破壞了“兩階段加鎖原則”);但是RR隔離級別,通過 where 條件走非索引列過濾之後,即使不符合where條件的記錄,也是會加行鎖。所以從鎖方面來看,RC的並行應該要好於RR;可以減少一部分鎖競爭,減少死鎖和鎖超時的概率。
RC 隔離級別不支援 statement 格式的bin log,因為該格式的複製,會導致主從資料的不一致;只能使用 mixed 或者 row 格式的bin log; 這也是為什麼MySQL預設使用RR隔離級別的原因。複製時,我們最好使用:binlog_format=row
MySQL5.6 的早期版本,RC隔離級別是可以設定成使用statement格式的bin log,後期版本則會直接報錯;
簡單而且,RC隔離級別時,事務中的每一條select語句會讀取到他自己執行時已經提交了的記錄,也就是每一條select都有自己的一致性讀ReadView; 而RR隔離級別時,事務中的一致性讀的ReadView是以第一條select語句的執行時,作為本事務的一致性讀snapshot的建立時間點的。只能讀取該時間點之前已經提交的資料。
讀未提交:在讀未提交這個隔離級別下,即使別的事務所做的修改並未提交,也能看到其修改的資料。當事務的隔離級別處於“讀未提交”時,其並行效能是最強的,但是隔離性與安全性是最差的,會出現髒讀,在生產環境中不使用。
讀已提交:讀取資料的事務允許其他事務繼續存取該行資料,但是未提交的寫事務將會禁止其他事務存取該行。該隔離級別避免了髒讀,但是卻可能出現不可重複讀。例如,事務A事先讀取了資料,事務B緊接著更新並提交了事務,當事務A再次讀取該資料時資料已經發生改變。
可重複讀:是指在一個事務內多次讀同一資料。假設在一個事務還沒結束時,另一個事務也存取同一資料,那麼在第一個事務中的兩次讀資料之間,即使第二個事務對資料進行了修改,第一個事務兩次讀到的資料也是一樣的。這樣在一個事務內兩次讀到的資料就是一樣的,因此稱為可重複讀。讀取資料的事務禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務,這樣即可避免不可重複讀和髒讀,但是有時可能出現幻讀。
序列化:提供嚴格的事務隔離。它要求事務序列化執行,即事務只能一個接著一個地執行,但不能並行執行。僅僅通過“行級鎖”是無法實現事務序列化的,必須通過其他機制保證新插入的資料不會被剛執行查詢操作的事務存取到。序列化是最高的事務隔離級別,同時代價也最高,效能很低,一般很少使用。在該級別下,事務順序執行,不僅可以避免髒讀、不可重複讀、還避免了幻讀
建立測試表:
create table a (id int auto_increment, a varchar(10), b varchar(10), c varchar(10), d varchar(10), primary key(id) ) engine=INNODB default charset=utf8;
插入資料
insert into a(a,b,c,d) values ('1','1','1','1'), ('2','2','2','2'), ('3','3','3','3'), ('4','4','4','4'), ('5','5','5','5'), ('6','6','6','6');
查詢資料:
mysql> select * from a; +----+------+------+------+------+ | id | a | b | c | d | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | | 2 | 2 | 2 | 2 | 2 | | 3 | 3 | 3 | 3 | 3 | | 4 | 4 | 4 | 4 | 4 | | 5 | 5 | 5 | 5 | 5 | | 6 | 6 | 6 | 6 | 6 | +----+------+------+------+------+ 6 rows in set (0.00 sec)
建立索引:
CREATE INDEX index_b_c ON a(b,c);
mysql> show variables like '%iso%'; +-----------------------+-----------------+ | Variable_name | Value | +-----------------------+-----------------+ | transaction_isolation | REPEATABLE-READ | +-----------------------+-----------------+ 1 row in set (0.00 sec)
可以從上圖看出,目前MySQL處於RR的隔離級別(可重複讀)
事務1:
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update a set d='20' where a='1'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0
事務2:
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update a set d='20' where a='2';#一直等待,最後報錯 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
等待時間取決於這個引數:
innodb_lock_wait_timeout
檢視mysql鎖情況:
PS:因為show processlist只會顯示出當前正在執行的語句,有些語句很快就執行完成了,所以有時候是看不全的,需要通過系統表檢視
performance_schema.data_locks
mysql> select * from performance_schema.data_locks; +--------+---------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+-----------+-------------+------------------------+ | ENGINE | ENGINE_LOCK_ID | ENGINE_TRANSACTION_ID | THREAD_ID | EVENT_ID | OBJECT_SCHEMA | OBJECT_NAME | PARTITION_NAME | SUBPARTITION_NAME | INDEX_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA | +--------+---------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+-----------+-------------+------------------------+ | INNODB | 140166601014432:1066:140166526246928 | 14257 | 108 | 11 | test | a | NULL | NULL | NULL | 140166526246928 | TABLE | IX | GRANTED | NULL | | INNODB | 140166601014432:5:4:8:140166526244128 | 14257 | 108 | 11 | test | a | NULL | NULL | PRIMARY | 140166526244128 | RECORD | X | WAITING | 1 | | INNODB | 140166601010392:1066:140166526216544 | 14256 | 76 | 73 | test | a | NULL | NULL | NULL | 140166526216544 | TABLE | IX | GRANTED | NULL | | INNODB | 140166601010392:5:4:1:140166526213552 | 14256 | 76 | 73 | test | a | NULL | NULL | PRIMARY | 140166526213552 | RECORD | X | GRANTED | supremum pseudo-record | | INNODB | 140166601010392:5:4:3:140166526213552 | 14256 | 76 | 73 | test | a | NULL | NULL | PRIMARY | 140166526213552 | RECORD | X | GRANTED | 2 | | INNODB | 140166601010392:5:4:4:140166526213552 | 14256 | 76 | 73 | test | a | NULL | NULL | PRIMARY | 140166526213552 | RECORD | X | GRANTED | 3 | | INNODB | 140166601010392:5:4:5:140166526213552 | 14256 | 76 | 73 | test | a | NULL | NULL | PRIMARY | 140166526213552 | RECORD | X | GRANTED | 4 | | INNODB | 140166601010392:5:4:6:140166526213552 | 14256 | 76 | 73 | test | a | NULL | NULL | PRIMARY | 140166526213552 | RECORD | X | GRANTED | 5 | | INNODB | 140166601010392:5:4:7:140166526213552 | 14256 | 76 | 73 | test | a | NULL | NULL | PRIMARY | 140166526213552 | RECORD | X | GRANTED | 6 | | INNODB | 140166601010392:5:4:8:140166526213552 | 14256 | 76 | 73 | test | a | NULL | NULL | PRIMARY | 140166526213552 | RECORD | X | GRANTED | 1 | +--------+---------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+-----------+-------------+------------------------+ 10 rows in set (0.00 sec)
information_schema.INNODB_TRX
mysql> select * from INNODB_TRXG *************************** 1. row *************************** trx_id: 14257 trx_state: LOCK WAIT trx_started: 2022-04-23 17:09:05 trx_requested_lock_id: 140166601014432:5:4:8:140166526244128 trx_wait_started: 2022-04-23 17:09:05 trx_weight: 2 trx_mysql_thread_id: 51 trx_query: update a set d='20' where a='2' trx_operation_state: starting index read trx_tables_in_use: 1 trx_tables_locked: 1 trx_lock_structs: 2 trx_lock_memory_bytes: 1128 trx_rows_locked: 1 trx_rows_modified: 0 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0 trx_is_read_only: 0 trx_autocommit_non_locking: 0 trx_schedule_weight: 1 *************************** 2. row *************************** trx_id: 14256 trx_state: RUNNING trx_started: 2022-04-23 17:07:20 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 3 trx_mysql_thread_id: 26 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 1 trx_lock_structs: 2 trx_lock_memory_bytes: 1128 trx_rows_locked: 7 trx_rows_modified: 1 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0 trx_is_read_only: 0 trx_autocommit_non_locking: 0 trx_schedule_weight: NULL 2 rows in set (0.00 sec)
從這裡可以看到,事務ID14256正在執行。
performance_schema .data_lock_waits
mysql> select * from data_lock_waitsG *************************** 1. row *************************** ENGINE: INNODB REQUESTING_ENGINE_LOCK_ID: 140166601014432:5:4:8:140166526244128 REQUESTING_ENGINE_TRANSACTION_ID: 14257 REQUESTING_THREAD_ID: 108 REQUESTING_EVENT_ID: 11 REQUESTING_OBJECT_INSTANCE_BEGIN: 140166526244128 BLOCKING_ENGINE_LOCK_ID: 140166601010392:5:4:8:140166526213552 BLOCKING_ENGINE_TRANSACTION_ID: 14256 BLOCKING_THREAD_ID: 76 BLOCKING_EVENT_ID: 73 BLOCKING_OBJECT_INSTANCE_BEGIN: 140166526213552 1 row in set (0.00 sec)
從這裡可以看到,因為14256事務ID阻塞了當前這個事務。
從這三張圖可以看出來,第一個事務正在執行(還沒commit),第二個事務的update處於鎖等待狀態,可能有小夥伴會說,mysql不是行級鎖嗎?為什麼update的不是同一條資料,還是會鎖全表呢?
帶著這個疑問我們來看,下面來看第二個例子:
開啟第一個事務:
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update a set d='20' where b='2'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0
開啟第二個事務:
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update a set d='20' where b='3'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0
思考:為什麼這個語句就可以執行成功呢?
檢視mysql鎖情況:
performance_schema.data_locks mysql> select * from performance_schema.data_locks; +--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-------------+ | ENGINE | ENGINE_LOCK_ID | ENGINE_TRANSACTION_ID | THREAD_ID | EVENT_ID | OBJECT_SCHEMA | OBJECT_NAME | PARTITION_NAME | SUBPARTITION_NAME | INDEX_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA | +--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-------------+ | INNODB | 140166601010392:1066:140166526216544 | 14266 | 110 | 11 | test | a | NULL | NULL | NULL | 140166526216544 | TABLE | IX | GRANTED | NULL | | INNODB | 140166601010392:5:5:3:140166526213552 | 14266 | 110 | 11 | test | a | NULL | NULL | index_b_c | 140166526213552 | RECORD | X | GRANTED | '2', '2', 2 | | INNODB | 140166601010392:5:4:11:140166526213896 | 14266 | 110 | 11 | test | a | NULL | NULL | PRIMARY | 140166526213896 | RECORD | X,REC_NOT_GAP | GRANTED | 2 | | INNODB | 140166601010392:5:5:4:140166526214240 | 14266 | 110 | 11 | test | a | NULL | NULL | index_b_c | 140166526214240 | RECORD | X,GAP | GRANTED | '3', '3', 3 | +--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-------------+ 4 rows in set (0.00 sec)
information_schema.INNODB_TRX
mysql> select * from INNODB_TRXG *************************** 1. row *************************** trx_id: 14267 trx_state: RUNNING trx_started: 2022-04-23 17:35:44 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 5 trx_mysql_thread_id: 51 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 1 trx_lock_structs: 4 trx_lock_memory_bytes: 1128 trx_rows_locked: 3 trx_rows_modified: 1 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0 trx_is_read_only: 0 trx_autocommit_non_locking: 0 trx_schedule_weight: NULL *************************** 2. row *************************** trx_id: 14266 trx_state: RUNNING trx_started: 2022-04-23 17:30:50 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 5 trx_mysql_thread_id: 53 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 1 trx_lock_structs: 4 trx_lock_memory_bytes: 1128 trx_rows_locked: 3 trx_rows_modified: 1 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0 trx_is_read_only: 0 trx_autocommit_non_locking: 0 trx_schedule_weight: NULL 2 rows in set (0.00 sec)
兩個事務都在正常執行,互不干擾。
performance_schema.data_lock_waits
mysql> select * from performance_schema.data_lock_waitsG Empty set (0.00 sec)
鎖不存在
事務1提交:
mysql> commit; Query OK, 0 rows affected (0.01 sec) mysql> select * from a; +----+------+------+------+------+ | id | a | b | c | d | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | | 2 | 2 | 2 | 2 | 20 | | 3 | 3 | 3 | 3 | 3 | | 4 | 4 | 4 | 4 | 4 | | 5 | 5 | 5 | 5 | 5 | | 6 | 6 | 6 | 6 | 6 | +----+------+------+------+------+ 6 rows in set (0.00 sec)
從這裡可以看出,因為事務2並沒有提交,所以b=3的資料並沒有更新
事務2提交:
mysql> commit; Query OK, 0 rows affected (0.01 sec) mysql> select * from a; +----+------+------+------+------+ | id | a | b | c | d | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | | 2 | 2 | 2 | 2 | 20 | | 3 | 3 | 3 | 3 | 20 | | 4 | 4 | 4 | 4 | 4 | | 5 | 5 | 5 | 5 | 5 | | 6 | 6 | 6 | 6 | 6 | +----+------+------+------+------+ 6 rows in set (0.00 sec)
結論
當欄位沒有建立索引的時候,該欄位作為update條件的話,會鎖全表。
設定隔離級別為RC
mysql> set global transaction_isolation='read-committed'
事務1:
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update a set d='10' where a='1'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0
事務2:
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update a set d='20' where a='2'; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select* from a; +----+------+------+------+------+ | id | a | b | c | d | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 1 | | 2 | 2 | 2 | 2 | 20 | | 3 | 3 | 3 | 3 | 3 | | 4 | 4 | 4 | 4 | 4 | | 5 | 5 | 5 | 5 | 5 | | 6 | 6 | 6 | 6 | 6 | +----+------+------+------+------+ #此時事務1執行commit操作 mysql> select * from a; +----+------+------+------+------+ | id | a | b | c | d | +----+------+------+------+------+ | 1 | 1 | 1 | 1 | 10 | | 2 | 2 | 2 | 2 | 20 | | 3 | 3 | 3 | 3 | 3 | | 4 | 4 | 4 | 4 | 4 | | 5 | 5 | 5 | 5 | 5 | | 6 | 6 | 6 | 6 | 6 | +----+------+------+------+------+ 6 rows in set (0.00 sec)
在RC隔離級別下,並沒有鎖表,可以看到,事務1在commit情況下,事務2立刻就可以看到事務1更新的資料,這就是不可重複讀。
mysql> select * from performance_schema.data_locks; +--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+ | ENGINE | ENGINE_LOCK_ID | ENGINE_TRANSACTION_ID | THREAD_ID | EVENT_ID | OBJECT_SCHEMA | OBJECT_NAME | PARTITION_NAME | SUBPARTITION_NAME | INDEX_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA | +--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+ | INNODB | 140166601010392:1067:140166526216544 | 14315 | 112 | 22 | test | a | NULL | NULL | NULL | 140166526216544 | TABLE | IX | GRANTED | NULL | | INNODB | 140166601010392:6:4:10:140166526213552 | 14315 | 112 | 22 | test | a | NULL | NULL | PRIMARY | 140166526213552 | RECORD | X,REC_NOT_GAP | GRANTED | 1 | +--------+----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+ 2 rows in set (0.00 sec)
mysql> select * from INNODB_TRXG *************************** 1. row *************************** trx_id: 14316 trx_state: RUNNING trx_started: 2022-04-23 18:08:55 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 3 trx_mysql_thread_id: 57 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 1 trx_lock_structs: 2 trx_lock_memory_bytes: 1128 trx_rows_locked: 2 trx_rows_modified: 1 trx_concurrency_tickets: 0 trx_isolation_level: READ COMMITTED trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0 trx_is_read_only: 0 trx_autocommit_non_locking: 0 trx_schedule_weight: NULL *************************** 2. row *************************** trx_id: 14315 trx_state: RUNNING trx_started: 2022-04-23 18:08:04 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 3 trx_mysql_thread_id: 55 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 1 trx_lock_structs: 2 trx_lock_memory_bytes: 1128 trx_rows_locked: 1 trx_rows_modified: 1 trx_concurrency_tickets: 0 trx_isolation_level: READ COMMITTED trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 0 trx_is_read_only: 0 trx_autocommit_non_locking: 0 trx_schedule_weight: NULL 2 rows in set (0.00 sec)
兩個事務都正常執行。
mysql> select * from data_lock_waitsG Empty set (0.00 sec)
並沒有鎖表
結論:RC隔離級別下,其實是順序的給每一行都加了鎖的(不是update的資料的話,就馬上解開),但是速度非常快,如果資料量足夠大的話,也是會有lock的。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45