數(shù)據(jù)庫并發(fā)處理-鎖

數(shù)據(jù)并發(fā)處理主要有兩種方式樂觀鎖悲觀鎖祖凫。
樂觀鎖 : 是假設(shè)并發(fā)事務(wù)處理時(shí)彼此不會(huì)相互影響莫绣,各種事務(wù)能在不產(chǎn)生鎖的情況下處理各自影響的那一部分?jǐn)?shù)據(jù)流妻;數(shù)據(jù)在更新時(shí)對(duì)數(shù)據(jù)進(jìn)行檢查,其他事務(wù)是否更新了該數(shù)據(jù)幕帆,如果更新過則回退,如果沒有更新則正常更新虑粥。所以樂觀鎖是一種數(shù)據(jù)并發(fā)處理方法如孝,沒有利用數(shù)據(jù)庫提供的鎖機(jī)制,需要業(yè)務(wù)實(shí)現(xiàn)控制數(shù)據(jù)并發(fā)處理娩贷。(樂觀鎖比較適合讀場(chǎng)景比較多第晰,寫操作比較少的場(chǎng)景)

樂觀鎖的實(shí)現(xiàn)一般有以下兩種方式:
1、 數(shù)據(jù)創(chuàng)建時(shí)添加一個(gè)version字段

  # 創(chuàng)建表
  create table student_info(id int primary key, name varchar(10), age int, version int);

 # 邏輯操作
 # 1彬祖、 讀取數(shù)據(jù)
 select id, name, age, version from student_info where id=${id}

 # 2茁瘦、更新數(shù)據(jù) 如果其他事務(wù)沒有修改數(shù)據(jù),則修改成功储笑,否則修改失敗
 update student_info set name=${name}, age=${age} , version=version+1 where id=${id} and version=${version}

2甜熔、 數(shù)據(jù)庫創(chuàng)建時(shí)添加update_time(精確到毫秒)字段,處理邏輯與上面邏輯大致相同

悲觀鎖 : 在數(shù)據(jù)并發(fā)處理時(shí),利用數(shù)據(jù)庫提供的鎖機(jī)制對(duì)數(shù)據(jù)加鎖突倍,阻止其他事務(wù)對(duì)其進(jìn)行修改腔稀,只有當(dāng)該事務(wù)釋放該鎖之后其他事務(wù)才能繼續(xù)數(shù)據(jù)處理。

MySQL數(shù)據(jù)庫一般提供兩種鎖羽历,讀鎖(共享鎖)焊虏、寫鎖(排它鎖):

  • 讀鎖(共享鎖): A事務(wù)獲取了表A'的共享鎖,則其他的事務(wù)依然可以讀取該數(shù)據(jù)(即獲取表A的共享鎖)秕磷,但是不能對(duì)該數(shù)據(jù)進(jìn)行修改(即獲取表A的排它鎖)

  • 寫鎖(排它鎖): A事務(wù)獲取了表A'的寫鎖之后诵闭,其他事務(wù)不能對(duì)表A'做任何鎖操作。
    說明:讀鎖會(huì)阻塞其他事務(wù)的寫操作澎嚣,但不阻塞讀操作疏尿; 寫鎖會(huì)阻塞其他事務(wù)的讀寫操作

行鎖和表鎖
行鎖(Record Lock): 針對(duì)某行數(shù)據(jù)加鎖, 加鎖方式select * from test where id=1 for update/lock in share mode 釋放鎖commit易桃、rollback褥琐、kill阻塞進(jìn)程
Mysql中InnoDB引擎支持行鎖,MyISAM引擎不支持行鎖颈抚。
經(jīng)過測(cè)試無論查詢條件是否使用聚族索引踩衩,外面很多資料說不使用聚族索引就加表鎖的說法是錯(cuò)誤的。

表鎖(Table Lock): 針對(duì)某一個(gè)表加鎖,加鎖方式lock table test write/read;贩汉,釋放鎖unlock tables; unlock table test
** 在一個(gè)事務(wù)中不會(huì)同時(shí)持有兩個(gè)表鎖,在授予第二個(gè)表鎖的時(shí)候锚赤,隱式釋放已經(jīng)持有的表鎖匹舞。

行鎖的實(shí)現(xiàn)方式有三種Record Lock、Gap Lock线脚、 Next-Key Lock三種
行鎖(Record Lock):直接對(duì)某一行數(shù)據(jù)加鎖就叫行鎖(例如: select * from test where id=1就是對(duì)ID=1的記錄添加了行鎖)

間隙鎖(Gap Lock): 是為了防止事務(wù)級(jí)別在可重復(fù)讀(read-repeat)的情況下赐稽,出現(xiàn)幻讀問題叫榕。

Next-Key Lock: 是存儲(chǔ)引擎innoDB在事務(wù)級(jí)別可重復(fù)讀(read-repeat)的情況下的數(shù)據(jù)庫鎖,是行鎖和間隙鎖的組合姊舵,

下面演示一下這三種鎖是如何工作的晰绎,所有操作均基于假設(shè)存在如下數(shù)據(jù),并且隔離等級(jí)是repeatable-read.

CREATE TABLE `gap_table` (
  `id` varchar(2) NOT NULL,
  `count` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `gap_table_index` (`count`)
) ENGINE=InnoDB DEFAULT

insert into gap_table(id, count) values('a', 1);
insert into gap_table(id, count) values('d', 4);
insert into gap_table(id, count) values('g', 10);

主鍵查詢(聚族索引)鎖

1、 主鍵等值查詢括丁,數(shù)據(jù)存在時(shí)荞下,會(huì)對(duì)該主鍵的值加行鎖

# session A
begin
select * from gap_table where id='a' for update;,

select OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+---------------+-------------+------------+-----------+---------------+-------------+-----------+
| OBJECT_SCHEMA | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+---------------+-------------+------------+-----------+---------------+-------------+-----------+
| lock_test     | gap_table   | NULL       | TABLE     | IX            | GRANTED     | NULL      |
| lock_test     | gap_table   | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 'a'       |
+---------------+-------------+------------+-----------+---------------+-------------+-----------+

對(duì)表gap_table添加意向排它鎖(IX)史飞,對(duì)數(shù)據(jù)a添加行鎖(X,REC_NOT_GAP

2尖昏、 主鍵等值查詢,數(shù)據(jù)不存在時(shí)构资,對(duì)該間隙加鎖

#session A
begin;
select * from gap_table where id='c' for update;

select OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+---------------+-------------+------------+-----------+-----------+-------------+-----------+
| OBJECT_SCHEMA | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA |
+---------------+-------------+------------+-----------+-----------+-------------+-----------+
| lock_test     | gap_table   | NULL       | TABLE     | IX        | GRANTED     | NULL      |
| lock_test     | gap_table   | PRIMARY    | RECORD    | X,GAP     | GRANTED     | 'd'       |
+---------------+-------------+------------+-----------+-----------+-------------+-----------+

對(duì)表gap_table添加意向排它鎖(IX)抽诉,對(duì)數(shù)據(jù)(a~d)添加間隙鎖(X,GAP

3、 主鍵區(qū)間查詢,比較復(fù)雜吐绵,這里以8.18版本以后版本說明

begin;
select * from gap_table where id between 'e' and 'f' for update;

select OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+---------------+-------------+------------+-----------+-----------+-------------+-----------+
| OBJECT_SCHEMA | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA |
+---------------+-------------+------------+-----------+-----------+-------------+-----------+
| lock_test     | gap_table   | NULL       | TABLE     | IX        | GRANTED     | NULL      |
| lock_test     | gap_table   | PRIMARY    | RECORD    | X,GAP     | GRANTED     | 'g'       |
+---------------+-------------+------------+-----------+-----------+-------------+-----------+

對(duì)(d,g)間隙加鎖(X,GAP

select * from gap_table where id between 'e' and 'g' for update;

select OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+---------------+-------------+------------+-----------+-----------+-------------+------------------------+
| OBJECT_SCHEMA | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA              |
+---------------+-------------+------------+-----------+-----------+-------------+------------------------+
| lock_test     | gap_table   | NULL       | TABLE     | IX        | GRANTED     | NULL                   |
| lock_test     | gap_table   | PRIMARY    | RECORD    | X         | GRANTED     | supremum pseudo-record |
| lock_test     | gap_table   | PRIMARY    | RECORD    | X         | GRANTED     | 'g'                    |
+---------------+-------------+------------+-----------+-----------+-------------+------------------------+

select * from gap_table where id > 'e' for update;  

select OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+---------------+-------------+------------+-----------+-----------+-------------+------------------------+
| OBJECT_SCHEMA | OBJECT_NAME | INDEX_NAME | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA              |
+---------------+-------------+------------+-----------+-----------+-------------+------------------------+
| lock_test     | gap_table   | NULL       | TABLE     | IX        | GRANTED     | NULL                   |
| lock_test     | gap_table   | PRIMARY    | RECORD    | X         | GRANTED     | supremum pseudo-record |
| lock_test     | gap_table   | PRIMARY    | RECORD    | X         | GRANTED     | 'g'                    |
+---------------+-------------+------------+-----------+-----------+-------------+------------------------+

對(duì)gap_table表的主鍵加了一個(gè)(supremum pseudo-record)鎖(個(gè)人理解是最大值以上的開區(qū)間鎖)迹淌,對(duì)數(shù)據(jù)(d, g]加行鎖nextkey-lock(X);
但是經(jīng)過測(cè)試對(duì)(d, +∞)區(qū)間都加鎖

select * from gap_table where id < 'f' for update; 

select OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+---------------+-------------+-----------------+-----------+---------------+-------------+------------------------+
| OBJECT_SCHEMA | OBJECT_NAME | INDEX_NAME      | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA              |
+---------------+-------------+-----------------+-----------+---------------+-------------+------------------------+
| lock_test     | gap_table   | NULL            | TABLE     | IX            | GRANTED     | NULL                   |
| lock_test     | gap_table   | gap_table_index | RECORD    | X             | GRANTED     | supremum pseudo-record |
| lock_test     | gap_table   | gap_table_index | RECORD    | X             | GRANTED     | 4, 'd'                 |
| lock_test     | gap_table   | gap_table_index | RECORD    | X             | GRANTED     | 10, 'g'                |
| lock_test     | gap_table   | gap_table_index | RECORD    | X             | GRANTED     | 12, 'a'                |
| lock_test     | gap_table   | PRIMARY         | RECORD    | X,REC_NOT_GAP | GRANTED     | 'a'                    |
| lock_test     | gap_table   | PRIMARY         | RECORD    | X,REC_NOT_GAP | GRANTED     | 'd'                    |
| lock_test     | gap_table   | PRIMARY         | RECORD    | X,REC_NOT_GAP | GRANTED     | 'g'                    |
+---------------+-------------+-----------------+-----------+---------------+-------------+------------------------+

首先對(duì)標(biāo)中的數(shù)據(jù)a d g都加了行鎖,其次在gap_table_index 所以中加NextKey-Lock(相當(dāng)于鎖住了整個(gè)gap_table_index 索引的所有區(qū)間)

非主鍵(輔助索引)鎖

添加如下數(shù)據(jù)

create table secondary_index_lock(id int primary key, no int unique, name varchar(2), age int);

insert into secondary_index_lock(id, no, name, age) values(1, 10, 'z1', 10), (2, 20, 'z2', 20), (3, 30, 'z3', 30), (4, 40, 'z4', 40),(9,90, 'z9',90);

1己单、 非主鍵唯一索引等值查詢巍沙,數(shù)據(jù)存在,for update 在主鍵加鎖荷鼠,for share僅僅在自己索引上加鎖

select * from secondary_index_lock where no=20 for update/ lock in share mode;

 select ENGINE_TRANSACTION_ID, OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+-----------------------+---------------+----------------------+------------+-----------+---------------+-------------+-----------+
| ENGINE_TRANSACTION_ID | OBJECT_SCHEMA | OBJECT_NAME          | INDEX_NAME | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+-----------------------+---------------+----------------------+------------+-----------+---------------+-------------+-----------+
|                  2007 | lock_test     | secondary_index_lock | NULL       | TABLE     | IX            | GRANTED     | NULL      |
|                  2007 | lock_test     | secondary_index_lock | no         | RECORD    | X,REC_NOT_GAP | GRANTED     | 20, 2     |
|                  2007 | lock_test     | secondary_index_lock | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 2         |
+-----------------------+---------------+----------------------+------------+-----------+---------------+-------------+-----------+

在主鍵索引和唯一索引上對(duì)該數(shù)據(jù)加行鎖(排他/共享)

2句携、 非主鍵索引等值查詢,數(shù)據(jù)不存在允乐,無論是否索引覆蓋矮嫉,相當(dāng)于一個(gè)范圍查詢,僅僅會(huì)在非主鍵索引上加間隙鎖

select * from secondary_index_lock where name = 'z5' for update;

select ENGINE_TRANSACTION_ID, OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+-----------------------+---------------+----------------------+------------+-----------+-----------+-------------+-----------+
| ENGINE_TRANSACTION_ID | OBJECT_SCHEMA | OBJECT_NAME          | INDEX_NAME | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA |
+-----------------------+---------------+----------------------+------------+-----------+-----------+-------------+-----------+
|                  2027 | lock_test     | secondary_index_lock | NULL       | TABLE     | IX        | GRANTED     | NULL      |
|                  2027 | lock_test     | secondary_index_lock | name_index | RECORD    | X,GAP     | GRANTED     | 'z9', 9  |
+-----------------------+---------------+----------------------+------------+-----------+-----------+-------------+-----------+

3牍疏、非主鍵唯一索引范圍查詢時(shí)蠢笋,不是覆蓋索引的時(shí)候,會(huì)對(duì)相應(yīng)范圍內(nèi)加間隙鎖鳞陨,并且如果存在數(shù)據(jù)昨寞,會(huì)對(duì)對(duì)應(yīng)的主鍵加鎖

select * from secondary_index_lock where no=25 for update;

select ENGINE_TRANSACTION_ID, OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+-----------------------+---------------+----------------------+------------+-----------+-----------+-------------+-----------+
| ENGINE_TRANSACTION_ID | OBJECT_SCHEMA | OBJECT_NAME          | INDEX_NAME | LOCK_TYPE | LOCK_MODE | LOCK_STATUS | LOCK_DATA |
+-----------------------+---------------+----------------------+------------+-----------+-----------+-------------+-----------+
|                  2008 | lock_test     | secondary_index_lock | NULL       | TABLE     | IX        | GRANTED     | NULL      |
|                  2008 | lock_test     | secondary_index_lock | no         | RECORD    | X,GAP     | GRANTED     | 30, 3     |
+-----------------------+---------------+----------------------+------------+-----------+-----------+-------------+-----------+

在no索引上加間隙鎖 (20, 30)

4厦滤、 非主鍵唯一索引范圍查詢時(shí)援岩,如果是覆蓋索引時(shí),會(huì)對(duì)所有的后閉區(qū)間對(duì)應(yīng)的主鍵加行鎖

select * from secondary_index_lock where no > 25 for update;

select ENGINE_TRANSACTION_ID, OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS, LOCK_DATA from performance_schema.data_locks;
+-----------------------+---------------+----------------------+------------+-----------+---------------+-------------+------------------------+
| ENGINE_TRANSACTION_ID | OBJECT_SCHEMA | OBJECT_NAME          | INDEX_NAME | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA              |
+-----------------------+---------------+----------------------+------------+-----------+---------------+-------------+------------------------+
|                  2029 | lock_test     | secondary_index_lock | NULL       | TABLE     | IX            | GRANTED     | NULL                   |
|                  2029 | lock_test     | secondary_index_lock | no         | RECORD    | X             | GRANTED     | supremum pseudo-record |
|                  2029 | lock_test     | secondary_index_lock | no         | RECORD    | X             | GRANTED     | 30, 3                  |
|                  2029 | lock_test     | secondary_index_lock | no         | RECORD    | X             | GRANTED     | 40, 4                  |
|                  2029 | lock_test     | secondary_index_lock | no         | RECORD    | X             | GRANTED     | 100, 10                |
|                  2029 | lock_test     | secondary_index_lock | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 3                      |
|                  2029 | lock_test     | secondary_index_lock | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 4                      |
|                  2029 | lock_test     | secondary_index_lock | PRIMARY    | RECORD    | X,REC_NOT_GAP | GRANTED     | 10                     |
+-----------------------+---------------+----------------------+------------+-----------+---------------+-------------+------------------------+
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掏导,一起剝皮案震驚了整個(gè)濱河市享怀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌趟咆,老刑警劉巖添瓷,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梅屉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鳞贷,警方通過查閱死者的電腦和手機(jī)坯汤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搀愧,“玉大人惰聂,你說我怎么就攤上這事÷栝希” “怎么了庶近?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)眷蚓。 經(jīng)常有香客問我鼻种,道長(zhǎng),這世上最難降的妖魔是什么沙热? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任叉钥,我火速辦了婚禮,結(jié)果婚禮上篙贸,老公的妹妹穿的比我還像新娘投队。我一直安慰自己,他們只是感情好爵川,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布敷鸦。 她就那樣靜靜地躺著,像睡著了一般寝贡。 火紅的嫁衣襯著肌膚如雪扒披。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天圃泡,我揣著相機(jī)與錄音碟案,去河邊找鬼。 笑死颇蜡,一個(gè)胖子當(dāng)著我的面吹牛价说,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播风秤,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼鳖目,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了唁情?” 一聲冷哼從身側(cè)響起疑苔,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎甸鸟,沒想到半個(gè)月后惦费,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抢韭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年薪贫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刻恭。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瞧省,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鳍贾,到底是詐尸還是另有隱情鞍匾,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布骑科,位于F島的核電站橡淑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏咆爽。R本人自食惡果不足惜梁棠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斗埂。 院中可真熱鬧符糊,春花似錦、人聲如沸呛凶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漾稀。三九已至模闲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間县好,已是汗流浹背围橡。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缕贡,地道東北人登馒。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像瑞侮,于是被迫代替她去往敵國和親鞋既。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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