InnoDB加鎖分析

InnoDB加鎖分析

在事務(wù)的并發(fā)控制帮非,MySQL使用MVCC來支持快照讀和使用加鎖來支持鎖定讀兩種方式,鎖定通過行鎖和間隙鎖锋边。

鎖定表:

. RU RC RR S+
select 讀最新 RV:每次都生成 RV:第一次時(shí)生成 轉(zhuǎn)為selectS
selectS recordLock recordLock recordLock+gapLock recordLock+gapLock
selectX recordLock recordLock recordLock+gapLock recordLock+gapLock
delete recordLock+H recordLock+H recordLock+gapLock+H recordLock+gapLock
update recordLock+H recordLock+H recordLock+gapLock+H recordLock+gapLock
insert H H H H

鎖定規(guī)則:

  1. MySQL的行鎖(包括recordLock, gapLock, nextKeyLock)是鎖定在索引上的,加鎖是在使用索引掃描數(shù)據(jù)時(shí)加的刨摩。
  2. 如果掃描的是聚簇索引,則直接在聚簇索引上加record+gap鎖,如果掃描的是二級索引,則先在二級索引上加record+gap鎖有缆,然后在聚簇索引上加record鎖。
  3. 當(dāng)掃描索引時(shí)温亲,在RR級別會(huì)加recordLock和gapLock棚壁,在RU/RC級別只會(huì)加recordLock,recordLock用于鎖定對已存在的記錄的讀取和寫入栈虚,gapLock用于鎖定對索引區(qū)間的插入袖外。
  4. 記錄的前一gap鎖和本條記錄的record會(huì)合并成nextKeyLock。
  5. 如果是唯一索引魂务,且任一側(cè)查詢條件的邊界匹配到了記錄曼验,可將該側(cè)的gap鎖去除。
  6. mysql可能通過講gap鎖升級nextKey鎖來減少鎖的數(shù)量粘姜。
  7. 同一個(gè)查詢?nèi)绻褂貌煌乃饕拚眨赡苕i定的范圍不通!
  8. 對于delete相艇,where條件中的加鎖和selectX一致,對于所有的二級索引纯陨,加隱式鎖坛芽。
  9. 對于update留储,where條件中的加鎖和selectX一致,對于涉及到的二級索引咙轩,加隱式鎖获讳。
  10. 對于insert,加隱式鎖活喊。
  11. 隱式鎖: 通過比較索引記錄的trx_id是否是當(dāng)前活躍的事務(wù)丐膝,如果是,則說明此時(shí)有事務(wù)(記為1)正在寫該記錄钾菊,當(dāng)其他事務(wù)(記為2)想要獲取該記錄的鎖時(shí)帅矗,則先為事務(wù)1獲取X鎖,再為事務(wù)2獲取對應(yīng)的鎖且等待煞烫。

加鎖流程

測試數(shù)據(jù)

CREATE TABLE `test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL DEFAULT '',
  `country` int(10) unsigned NOT NULL DEFAULT '0',
  `status` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`),
  KEY `idx_country` (`country`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

數(shù)據(jù):
INSERT INTO `test` (`id`, `name`, `country`)
VALUES
    (1, 'a', 1, 1),
    (3, 'c', 3, 1),
    (5, 'e', 5, 0),
    (7, 'g', 5, 0),
    (9, 'i', 7, 0);

索引:
id: 1,3,5,7,9
name: a,c,e,g,i
country: 1,3,5,5,7

無腦分析MySQL鎖定范圍

步驟0-8為二級索引的全步驟加鎖分析浑此,9為聚簇索引的加鎖分析,10為update語句的加鎖分析滞详,11為delete語句的加鎖分析凛俱。

  1. 準(zhǔn)備表格,填入待分析語句
分析語句:select * from test where `name`>"c" and `name`<="g" for update;
隔離級別:
使用索引:
索引排列:
    二級索引:
    聚簇索引:
二級索引:
    gap:
    record:
    最終lock:
聚簇索引:
    gap:
    record:
    最終lock:
  1. 檢查隔離級別
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+

分析語句:select * from test where `name`>"c" and `name`<="g" for update;
隔離級別:REPEATABLE-READ
掃描索引:
索引排列:
    二級索引:
    聚簇索引:
二級索引:
    gap:
    record:
    最終lock:
聚簇索引:
    gap:
    record:
    最終lock:
  1. 通過使用explain或者optimizer_trace查看使用的索引料饥,使用show create tabel檢查索引類型蒲犬;
mysql> explain select * from test where `name`>"c" and `name`<="g" for update;
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | test  | NULL       | range | idx_name      | idx_name | 98      | NULL |    2 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+

分析語句:select * from test where `name`="e" for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:
    聚簇索引:
二級索引:
    gap:
    record:
    最終lock:
聚簇索引:
    gap:
    record:
    最終lock:
  1. 通過構(gòu)造索引排列,可以幫助我們更好的理解鎖定范圍岸啡,掃描的索引是二級非唯一索引原叮,()表示間隙
分析語句:select * from test where `name`>"c" and `name`<="g" for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:() a () c () e () g () i ()
    聚簇索引:() 1 () 3 () 5 () 7 () 9 ()
二級索引:
    gap:
    record:
    最終lock:
聚簇索引:
    gap:
    record:
    最終lock:
  1. 確定二級索引掃描到的記錄范圍,使用''表示
分析語句:select * from test where `name`>"c" and `name`<="g" for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:() a () c () 'e () g' () i ()
    聚簇索引:() 1 () 3 () 5 () 7 () 9 ()
二級索引:
    gap: 
    record: 
    最終lock: 
聚簇索引:
    gap:
    record:
    最終lock:
  1. 確定二級索引鎖定范圍:
    • record鎖:
      • RU或者RC級別凰狞,則在''中間的所有匹配的記錄加recordLock篇裁,即記錄e,g
      • RR級別,則在''中間的所有記錄加recordLock赡若,即記錄e,g
    • gap鎖:
      • RU或者RC級別达布,不用填寫
      • RR級別,如果是二級非唯一索引逾冬,在''中間及兩側(cè)的所有記錄加gap鎖黍聂,即e兩側(cè)的間隙,我們使用(c,e)和(e,g)表示身腻,如果是唯一索引产还,且任一側(cè)查詢條件的邊界匹配到了記錄,可將該側(cè)的gap鎖去除
分析語句:select * from test where `name`>"c" and `name`<="g" for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:() a () c () 'e () g' () i ()
    聚簇索引:() 1 () 3 () 5 () 7 () 9 ()
二級索引:
    gap: (c,e),(e,g),(g,i)
    record: e,g
    最終lock: 
聚簇索引:
    gap:
    record:
    最終lock: 
  1. 確定聚簇索引鎖定范圍:
    • 找到二級索引中的鎖定的所有記錄嘀趟,對聚簇索引中的響應(yīng)記錄加record鎖
分析語句:select * from test where `name`>"c" and `name`<="g" for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:() a () c () 'e () g' () i ()
    聚簇索引:() 1 () 3 () 5 () 7 () 9 ()
二級索引:
    gap: (c,e),(e,g),(g,i)
    record: e,g
    最終lock: 
聚簇索引:
    gap:
    record: 5,7
    最終lock: 
  1. 合并鎖區(qū)間
    • 將record鎖和gap進(jìn)行合并脐区,使用(c,e]表示
    • 同一事務(wù)同一個(gè)頁同一類型同一狀態(tài)的鎖可以被存儲(chǔ)在同一個(gè)內(nèi)存結(jié)構(gòu)中從而節(jié)約存儲(chǔ)空間,mysql可能通過講gap鎖升級nextKey鎖來減少鎖的數(shù)量她按,會(huì)擴(kuò)大鎖定范圍牛隅,但是可以節(jié)約空間
分析語句:select * from test where `name`>"c" and `name`<="g" for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:() a () c () 'e () g' () i ()
    聚簇索引:() 1 () 3 () 5 () 7 () 9 ()
二級索引:
    gap: (c,e),(e,g),(g,i)
    record: e,g
    最終lock: (c,e],(e,g],(g,i) -> (c,e],(e,g],(g,i]
聚簇索引:
    gap:
    record: 5,7
    最終lock: 5,7
  1. 驗(yàn)證:8.0以后可以通過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 | 140312364539208:1208:140312627602512    |                 76590 |        58 |       58 | expert        | test        | NULL           | NULL              | NULL       |       140312627602512 | TABLE     | IX            | GRANTED     | NULL      |
| INNODB | 140312364539208:226:5:4:140312639144480 |                 76590 |        58 |       58 | expert        | test        | NULL           | NULL              | idx_name   |       140312639144480 | RECORD    | X             | GRANTED     | 'e', 5    |
| INNODB | 140312364539208:226:5:5:140312639144480 |                 76590 |        58 |       58 | expert        | test        | NULL           | NULL              | idx_name   |       140312639144480 | RECORD    | X             | GRANTED     | 'g', 7    |
| INNODB | 140312364539208:226:5:6:140312639144480 |                 76590 |        58 |       58 | expert        | test        | NULL           | NULL              | idx_name   |       140312639144480 | RECORD    | X             | GRANTED     | 'i', 9    |
| INNODB | 140312364539208:226:4:4:140312639144824 |                 76590 |        58 |       58 | expert        | test        | NULL           | NULL              | PRIMARY    |       140312639144824 | RECORD    | X,REC_NOT_GAP | GRANTED     | 5         |
| INNODB | 140312364539208:226:4:5:140312639144824 |                 76590 |        58 |       58 | expert        | test        | NULL           | NULL              | PRIMARY    |       140312639144824 | RECORD    | X,REC_NOT_GAP | GRANTED     | 7         |
+--------+-----------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+    
  1. 聚簇索引:掃描索引為聚簇索引炕柔,則該索引的分析同二級唯一索引
    • 確定掃描范圍
    • 為掃描范圍中的記錄加gap鎖和record鎖,同二級唯一索引
    • 將record鎖和gap進(jìn)行合并
分析語句:select * from test where `id`>=3 and `id`<6 for update;
隔離級別:REPEATABLE-READ
掃描索引:聚簇索引
索引排列:
    二級索引:
    聚簇索引:() 1 () '3 () 5 ( ' ) 7 () 9 ()
二級索引:
    gap鎖:
    record鎖:
    最終lock: 
聚簇索引:
    gap鎖:  (3,5), (5,7)
    record鎖: 3媒佣,5
    最終lock: 3, (3,5], (5,7)
  1. 刪除語句:顯式鎖同selectX匕累,在所有二級索引上加隱式鎖
分析語句:delete from test where `id`>=3 and `id`<6;
隔離級別:REPEATABLE-READ
掃描索引:聚簇索引
索引排列:
    二級索引:
    聚簇索引:() 1 () '3 () 5 ( ' ) 7 () 9 ()
二級索引:
    gap鎖:
    record鎖:
    最終lock: 
聚簇索引:
    gap鎖:  (3,5), (5,7)
    record鎖: 3,5
    最終lock: 3, (3,5], (5,7)
隱式:
    idx_name: c,e
    idx_country: 3,5
  1. 更新語句:顯式鎖同selectX默伍,在涉及的二級索引上加隱式鎖
分析語句:update test set `name`="t" where `id`>=3 and `id`<6;
隔離級別:REPEATABLE-READ
掃描索引:聚簇索引
索引排列:
    二級索引:
    聚簇索引:() 1 () '3 () 5 ( ' ) 7 () 9 ()
二級索引:
    gap鎖:
    record鎖:
    最終lock: 
聚簇索引:
    gap鎖:  (3,5), (5,7)
    record鎖: 3欢嘿,5
    最終lock: 3, (3,5], (5,7)
隱式:
    idx_name隱式: c,e,t
  1. 插入語句:顯式鎖同selectX,在所有二級索引上加隱式鎖
分析語句:insert test value(4,"d", 1, 0);
隔離級別:REPEATABLE-READ
掃描索引:聚簇索引
索引排列:
    二級索引:
    聚簇索引:() 1 () '3 () 4 () 5 ( ' ) 7 () 9 ()
二級索引:
    gap鎖:
    record鎖:
    最終lock: 
聚簇索引:
    gap鎖:
    record鎖:
    最終lock:
隱式:
    idx_name: d
    idx_country: 1

更多例子

  1. 使用主鍵鎖定一個(gè)已存在的記錄:
分析語句:select * from test where `id`=5 for update;
隔離級別:REPEATABLE-READ
掃描索引:聚簇索引
索引排列:
    二級索引:
    聚簇索引:() 1 () 3 () '5' () 7 () 9 ()
二級索引:
    gap鎖:
    record鎖: 
    最終lock:
聚簇索引:
    gap鎖:
    record鎖:5
    最終lock:5
  1. 使用主鍵鎖定一個(gè)不存在的記錄
分析語句:select * from test where `id`=4 for update;
隔離級別:REPEATABLE-READ
掃描索引:聚簇索引
索引排列:
    二級索引:
    聚簇索引:() 1 () 3 ( '' ) 5 () 7 () 9 ()
二級索引:
    gap鎖:
    record鎖: 
    最終lock:
聚簇索引:
    gap鎖:(3,5)
    record鎖:
    最終lock:(3,5)
  1. 使用主鍵鎖定范圍并條件過濾:
    為什么在RR級別下id=5的記錄加了record鎖也糊,但是在RC級別下沒有加record鎖炼蹦?
    因?yàn)榇藭r(shí)如果不對id=5的記錄加record鎖,則其他事務(wù)可能通過update語句將id=5的status修改為1显设,當(dāng)前事務(wù)再次讀取將會(huì)產(chǎn)生幻讀框弛。
分析語句:select * from test where `id`>=3 and `id`<6 and `status`= 1 for update;
隔離級別:REPEATABLE-READ
掃描索引:聚簇索引
索引排列:
    二級索引:
    聚簇索引:() 1 () '3 () 5 ( ' ) 7 () 9 ()
二級索引:
    gap鎖:
    record鎖: 
聚簇索引:
    gap鎖:(1,3), (3,5), (5,7)
    record鎖:3,5
    最終lock:3, (3,5], (5,7) 
    
分析語句:select * from test where `id`>=3 and `id`<6 and `status`= 1 for update;
隔離級別:READ-COMMITTED
掃描索引:聚簇索引
索引排列:
    二級索引:
    聚簇索引:() 1 () '3 () 5 ( ' ) 7 () 9 ()
二級索引:
    gap鎖:
    record鎖: 
聚簇索引:
    gap鎖:
    record鎖:3
    最終lock:3 
  1. 使用二級索引掃描無數(shù)據(jù)的區(qū)間:
分析語句:select * from test where `name`="f" for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:() a () c () e ('') g () i ()
    聚簇索引:() 1 () 3 () 5 (  ) 7 () 9 ()
二級索引:
    gap鎖: (e,g)
    record鎖: 
    最終lock: (e,g)
聚簇索引:
    gap鎖:
    record鎖:
    最終lock:
  1. 使用二級索引掃描一個(gè)范圍并過濾部分記錄:
分析語句:select * from test where `name`>"c" and `name`<="g" and status=0 for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:() a () c ( ' ) e () g' () i ()
    聚簇索引:() 1 () 3  ()   5 () 7  () 9 ()
二級索引:
    gap鎖:(c,e),(e,g),(g,i)
    record鎖: e,g
    最終lock:
聚簇索引:
    gap鎖:
    record鎖:3,5
    最終lock:3,5
  1. 相同的條件捕捂,不同的索引瑟枫,不同的鎖定范圍
分析語句:select * from test force index(`idx_name`) where `name`="e" and `country`=5 for update;
隔離級別:REPEATABLE-READ
掃描索引:idx_name/二級非唯一索引
索引排列:
    二級索引:() a () c () 'e' () g () i ()
    聚簇索引:() 1 () 3 ()  5  () 7  () 9 ()
二級索引:
    gap鎖:(c,e),(e,g)
    record鎖: e
    最終lock:(c,e],(e,g)
聚簇索引:
    gap鎖:
    record鎖:5
    最終lock:5

分析語句:select * from test force index(`idx_country`) where `name`="e" and `country`=5 for update;;
隔離級別:REPEATABLE-READ
掃描索引:idx_country/二級非唯一索引
索引排列:
    二級索引:() 1 () 3 () '5 () 5' () 7 ()
    聚簇索引:() 1 () 3 ()  5 () 7  () 9 ()
二級索引:
    gap鎖:(3,5),(5,5),(5,7)
    record鎖: 5,5
    最終lock:(3,5],(5,5],(5,7)
聚簇索引:
    gap鎖:
    record鎖:5,7
    最終lock:5,7

鎖的內(nèi)存結(jié)構(gòu)

以下條件相同的公用同一個(gè)鎖結(jié)構(gòu):

  • 在同一個(gè)事務(wù)中進(jìn)行加鎖操作
  • 被加鎖的記錄在同一個(gè)頁面中
  • 加鎖的類型是一樣的
  • 等待狀態(tài)是一樣的
type Lock struct {
    TxInfo // 事務(wù)信息
    IndexInfo // 索引信息
    TableOrRecordInfo // 表鎖信息或者行鎖信息
    TypeMode // 鎖類型
    Others   // 其他信息
    Bits
}

type RecordInfo struct {
    SpaceID int // 表空間
    PageNumber int // 頁號
    Nbits // Bits占用位數(shù),每個(gè)索引記錄占用1位
}

type TypeMode struct {
    recLockType [24]bit // 僅行鎖時(shí)有意義指攒,nextKey鎖慷妙,record鎖,gap鎖允悦,插入意向鎖 ... 是否正在等待
    lockType [4]bit // 表鎖膝擂、行鎖
    lockMode [4]bit // 0:IS 1:IX 2:S 3:X 4:AutoInc
}

該如何理解Mysql加鎖的邏輯

數(shù)據(jù)結(jié)構(gòu)

我們從數(shù)據(jù)結(jié)構(gòu)的角度來理解MySQL,則MySQL的數(shù)據(jù)結(jié)構(gòu)如圖所示

  • 一個(gè)表是由多個(gè)索引組成的隙弛,每一個(gè)索引都是一個(gè)有序鏈表
  • 每一個(gè)索引有兩種類型的節(jié)點(diǎn)組成架馋,分別是Gap節(jié)點(diǎn)和Record節(jié)點(diǎn)
  • 對于Record類型的節(jié)點(diǎn),有三種鎖定狀態(tài)全闷,未鎖叉寂,X鎖和S鎖,對應(yīng)為讀寫
  • 對于Gap類型的節(jié)點(diǎn)总珠,也有三種鎖定狀態(tài)屏鳍,未鎖,X鎖和S鎖局服,對應(yīng)為讀寫钓瞭,只有獲取到了X鎖才能對節(jié)點(diǎn)進(jìn)行操作
  • MySQL將Gap節(jié)點(diǎn)和Record節(jié)點(diǎn)放在了一起來進(jìn)行表示,每一個(gè)Gap節(jié)點(diǎn)被合并到了后繼的Record節(jié)點(diǎn)中來進(jìn)行表示淫奔。
  • 對于這個(gè)數(shù)據(jù)結(jié)構(gòu)山涡,MySQL提供了在掃描時(shí)的多種鎖定范圍:
    • 鎖定整個(gè)數(shù)據(jù)結(jié)構(gòu),即表鎖定,通過表鎖實(shí)現(xiàn)
    • 鎖定一個(gè)索引中的多行記錄鸭丛,即行鎖定霍殴,通過Record鎖實(shí)現(xiàn),用于實(shí)現(xiàn)RU/RC的鎖定讀系吩。
    • 鎖定一個(gè)索引中的一個(gè)范圍,通過Record鎖和Gap鎖實(shí)現(xiàn)妒蔚,用于實(shí)現(xiàn)RR/S+的鎖定讀穿挨。


      InnoLock

操作

Select操作

  • 如果是對直接對主索引進(jìn)行掃描,則鎖只需要加在主索引上
  • 如果需要對二級索引加鎖肴盏,則還要為對對應(yīng)的主索引記錄加Record鎖科盛。

Insert操作

當(dāng)插入一個(gè)節(jié)點(diǎn)時(shí),需要在主索引記錄和所有二級索引記錄上插入該數(shù)據(jù):

  • 獲取新插入的數(shù)據(jù)的X鎖
  • 獲取插入位置所在的Gap的X鎖菜皂,然后將一個(gè)Gap分裂為兩個(gè)Gap贞绵,并獲取這兩個(gè)Gap的X鎖

但是,MySQL取了個(gè)巧恍飘,這個(gè)技巧叫做隱式鎖榨崩,可以減少加鎖的操作。

  • 在插入時(shí)章母,不獲取任何鎖
  • 在其他事務(wù)掃描時(shí)母蛛,判斷這個(gè)記錄是否正在被其他是否修改(索引記錄的trx_id對應(yīng)的事務(wù)是否正在活躍),如果是乳怎,則這時(shí)候再為插入記錄的事務(wù)獲取應(yīng)有的X鎖彩郊。

Delete操作

當(dāng)刪除一個(gè)節(jié)點(diǎn)時(shí),需要在主索引記錄和所有二級索引記錄上刪除該數(shù)據(jù):

  • 獲取刪除的數(shù)據(jù)的X鎖
  • 獲取待刪除數(shù)據(jù)周圍的兩個(gè)Gap的X鎖蚪缀,然后將兩個(gè)Gap合并為一個(gè)Gap秫逝,并獲取X鎖

但是,MySQL仍然可以使用隱式鎖询枚。

Update操作

當(dāng)更新一個(gè)節(jié)點(diǎn)時(shí)违帆,需要在主索引記錄和所有涉及到的二級索引記錄上更新該數(shù)據(jù):
如果新的記錄更新后存儲(chǔ)空間和位置都不變,則可以進(jìn)行原地更新:

  • 獲取更新的記錄的X鎖
    否則哩盲,則
  • 將原記錄進(jìn)行Delete前方,并Insert一條新的記錄
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市廉油,隨后出現(xiàn)的幾起案子惠险,更是在濱河造成了極大的恐慌,老刑警劉巖抒线,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件班巩,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)抱慌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門逊桦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人抑进,你說我怎么就攤上這事强经。” “怎么了寺渗?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵匿情,是天一觀的道長。 經(jīng)常有香客問我信殊,道長炬称,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任涡拘,我火速辦了婚禮玲躯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鳄乏。我一直安慰自己跷车,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布橱野。 她就那樣靜靜地躺著姓赤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仲吏。 梳的紋絲不亂的頭發(fā)上不铆,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天,我揣著相機(jī)與錄音裹唆,去河邊找鬼誓斥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛许帐,可吹牛的內(nèi)容都是我干的劳坑。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼成畦,長吁一口氣:“原來是場噩夢啊……” “哼距芬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起循帐,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤框仔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拄养,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體离斩,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了跛梗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寻馏。...
    茶點(diǎn)故事閱讀 40,742評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖核偿,靈堂內(nèi)的尸體忽然破棺而出诚欠,到底是詐尸還是另有隱情,我是刑警寧澤漾岳,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布聂薪,位于F島的核電站,受9級特大地震影響蝗羊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜仁锯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一耀找、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧业崖,春花似錦野芒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至妇斤,卻和暖如春摇锋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背站超。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工荸恕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人死相。 一個(gè)月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓融求,卻偏偏與公主長得像,于是被迫代替她去往敵國和親算撮。 傳聞我的和親對象是個(gè)殘疾皇子生宛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容