全網(wǎng)最牛X的!!翔始! MySQL兩階段提交串講

[TOC]


一、吹個(gè)牛

面試官的一句:“了解MySQL的兩階段提交嗎里伯?” 不知道問涼了多少人城瞎!

這篇文章白日夢(mèng)就和大家分享什么是MySQL的兩階提交到底是怎么回事!不管你原來曉不曉得兩階段提交疾瓮,相信我脖镀!這篇文章中你一定能get到新的知識(shí)!

在說兩階段提交之前狼电,白日夢(mèng)用了大量的篇幅再講undo-log蜒灰、redo-log弦蹂、binlog。

先了解它們强窖,才能更好的理解什么是兩階段提交凸椿,如果你如果還沒有看,推薦你去翻一翻前面的文章翅溺。


二脑漫、事務(wù)及它的特性

在說兩階段提交事物之前,我們先來說說事務(wù)咙崎。

一般當(dāng)我們的功能函數(shù)中有批量的增刪改時(shí)优幸,我們會(huì)添加一個(gè)事物包裹這一系列的操作,要么這一組操作全部執(zhí)行成功褪猛,只要有一條SQL執(zhí)行失敗了我們就全部回滾网杆。相信你一定聽說過這個(gè)比較經(jīng)典的轉(zhuǎn)賬的Case。有一定工作經(jīng)驗(yàn)的同學(xué)都知道握爷,這么做其實(shí)是保護(hù)我們的數(shù)據(jù)庫中不出現(xiàn)臟數(shù)據(jù)跛璧。整體數(shù)據(jù)會(huì)變的可控。

對(duì)MySQL來說你可以通過下面的命令顯示的開啟新啼、提交追城、回滾事務(wù)

# 開啟事務(wù)
begin;

# 或者下面這條命令
start transaction;

# 提交
commit;

# 回滾
rollback;

但是日常開發(fā)中大家普遍使用編程語言操作數(shù)據(jù)庫。比如Java燥撞、Golang... 在使用這種具體編程語言持久層的框架時(shí)座柱,它們一般都支持事務(wù)操作,比如:在Spring中你可以對(duì)一個(gè)方法添加注解@Transctional顯示的開啟事務(wù)物舒。Golang的beego中也提供了讓你可以顯示的開啟事務(wù)的函數(shù)色洞。

<p style="color:red">有一點(diǎn)不太好的地方是:大家在享受這種編程框架帶來的便利的同時(shí),它也屏蔽了你對(duì)MySQL事務(wù)認(rèn)知冠胯。讓人們懶得去往細(xì)了看事務(wù)

<p style="color:blue">你可以往看我下面這個(gè)很簡(jiǎn)單的Case火诸。

我有一張數(shù)據(jù)表

CREATE TABLE `test_backup` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后我往這個(gè)表中insert幾條數(shù)據(jù)

mysql> insert into test_backup values(1,'tom');
mysql> insert into test_backup values(2,'jerry');
mysql> insert into test_backup values(1,'herry');

再去查看binlog。

image

<p style="color:green">你會(huì)不會(huì)詫異荠察?我上面明明沒有顯示的添加begin置蜀、commit命令,但是MySQL實(shí)際執(zhí)行我的SQL時(shí)悉盆,竟然為我添加上了盯荤!

原因很簡(jiǎn)單:跟大家分享一個(gè)參數(shù)如下:

image

一般大家的線上庫都會(huì)將這個(gè)參數(shù)置為ON,你的SQL會(huì)自動(dòng)的開啟一個(gè)事物焕盟,并且MySQL會(huì)自動(dòng)的幫你把它提交秋秤。

也就是說: 當(dāng)這個(gè)參數(shù)為ON時(shí),你使用的DAO持久層框架發(fā)送給數(shù)據(jù)庫的SQL其實(shí)都會(huì)被放在一個(gè)事物中執(zhí)行,然后這個(gè)事物被自動(dòng)提交灼卢,而我們對(duì)這個(gè)過程是無感知的绍哎。 具體一點(diǎn),比如你使用某框架的@Transctional注解芥玉,或者在golang中可以像下面的方式獲得一個(gè)事物:

db := mysql.Client
ops := &sql.TxOptions{
        Isolation: 0,
        ReadOnly:  false,
    }
tx, err := db.BeginTx(ctx, ops)
// todo with tx

然后你所有的操作都放在這個(gè)事物中執(zhí)行蛇摸。

<p style="color:red">這時(shí)你使用的持久層框架肯定會(huì)向MySQL發(fā)送一條命令:begin;或者是start transcation;來保證你這一組SQL中執(zhí)行一條SQL后,開啟的事物不會(huì)被MySQL自動(dòng)幫你提交了灿巧。

其實(shí)還是推薦將這個(gè)參數(shù)設(shè)置成ON的,當(dāng)然你也可以像下面這樣將它關(guān)閉

mysql> set autocommit = 0;

但是關(guān)閉它之后揽涮,MySQL不會(huì)幫你自動(dòng)提交事物抠藕,全靠研發(fā)同學(xué)自己來維護(hù)就容易會(huì)出現(xiàn)長(zhǎng)事物,在內(nèi)存中產(chǎn)生一個(gè)極其長(zhǎng)的undo log鏈條蒋困。壞處多多盾似。

todo 關(guān)于長(zhǎng)事物,你可以看白日夢(mèng)的這篇筆記:


三雪标、簡(jiǎn)單看下兩階段提交的流程

了解了什么是事物零院,再來看下什么是兩階段提交。其實(shí)所謂的兩階段就是把一個(gè)事物分成兩個(gè)階段來提交村刨。就像下圖這樣告抄。

image

上圖為兩階段提交的時(shí)序圖。

你可以粗略的觀察一下上圖嵌牺,MySQL想要準(zhǔn)備事務(wù)的時(shí)候會(huì)先寫redolog打洼、binlog分成兩個(gè)階段。

兩階段提交的第一階段 (prepare階段):寫rodo-log 并將其標(biāo)記為prepare狀態(tài)逆粹。

緊接著寫binlog

兩階段提交的第二階段(commit階段):寫bin-log 并將其標(biāo)記為commit狀態(tài)募疮。

不了解這些日志是什么有啥用也沒關(guān)系,你可以先去看我之前的系列文章僻弹。


四阿浓、兩階段寫日志用意?

你有沒有想過這樣一件事蹋绽,binlog默認(rèn)都是不開啟的狀態(tài)芭毙!

也就是說,如果你根本不需要binlog帶給你的特性(比如數(shù)據(jù)備份恢復(fù)蟋字、搭建MySQL主從集群)稿蹲,那你根本就用不著讓MySQL寫binlog,也用不著什么兩階段提交鹊奖。

只用一個(gè)redolog就夠了苛聘。無論你的數(shù)據(jù)庫如何crash,redolog中記錄的內(nèi)容總能讓你MySQL內(nèi)存中的數(shù)據(jù)恢復(fù)成crash之前的狀態(tài)。

<p style="color:blue">所以說设哗,兩階段提交的主要用意是:為了保證redolog和binlog數(shù)據(jù)的安全一致性唱捣。只有在這兩個(gè)日志文件邏輯上高度一致了。你才能放心的使用redolog幫你將數(shù)據(jù)庫中的狀態(tài)恢復(fù)成crash之前的狀態(tài)网梢,使用binlog實(shí)現(xiàn)數(shù)據(jù)備份震缭、恢復(fù)、以及主從復(fù)制战虏。而兩階段提交的機(jī)制可以保證這兩個(gè)日志文件的邏輯是高度一致的拣宰。沒有錯(cuò)誤、沒有沖突烦感。

當(dāng)然巡社,兩階段提交能做到足夠的安全還需要你合理的設(shè)置redolog和binlog的fsync的時(shí)機(jī),而這塊知識(shí)點(diǎn)所涉及到的參數(shù)前幾篇文章已經(jīng)說過手趣。如果不記得晌该,可以去看下。


五绿渣、加餐:sync_binlog = 1 問題

<p style="color:red">如果你看懂了我下面說的這些話朝群,能幫你更好的理解兩階段提交哦!純干貨中符!

白日夢(mèng)在前面的分享binlog的文章中有跟大家提到過一個(gè)參數(shù)sync_binlog=1姜胖。這個(gè)參數(shù)控制binlog的落盤時(shí)機(jī),并且白日夢(mèng)也知道你們公司線上數(shù)據(jù)庫的該參數(shù)一定被設(shè)置成了1舟茶。

我在那篇binlog文章之前谭期,就計(jì)劃好寫這篇文章了。白日夢(mèng)的MySQL在動(dòng)筆之前已經(jīng)列好了大綱吧凉,從簡(jiǎn)單到復(fù)雜隧出,從0到1開始更新,歡迎小伙伴們關(guān)注我阀捅,持續(xù)更新中~

<p style="color:blue">NoticeU偷伞!饲鄙! 這個(gè)參數(shù)為1時(shí)凄诞,表示當(dāng)事物提交時(shí)會(huì)將binlog落盤。

現(xiàn)在你用15s中的時(shí)間忍级,思考一下帆谍,藍(lán)色句子中說的事物提交時(shí)會(huì)將binlog落盤,這個(gè)提交時(shí)轴咱,是下圖中的step1時(shí)刻呢汛蝙?還是step2時(shí)刻呢烈涮?

image

<p style="color:blue">答案是:step1時(shí)刻!

知道這個(gè)知識(shí)點(diǎn)很重要窖剑,下面我來描述這樣一個(gè)場(chǎng)景坚洽。

假如要執(zhí)行一條update語句,那你肯定知道西土,先寫redolog(便于后續(xù)對(duì)update事務(wù)的回滾)讶舰。然后你的update邏輯將Buffer Pool中的緩存頁修改成了臟頁。

當(dāng)你準(zhǔn)備提交事物時(shí)(也就是step1階段)需了,會(huì)寫redolog跳昼,并將其標(biāo)記為prepare階段。然后再寫binlog肋乍,并將binlog落盤庐舟。

然后發(fā)生了意外,MySQL宕機(jī)了住拭。

<p style="color:blue">那我問你,當(dāng)你重啟MySQL后历帚,update對(duì)BufferPool中做出的修改是會(huì)被回滾還是會(huì)被提交呢滔岳?

答案是:會(huì)根據(jù)redolog將修改后的recovery出來,然后提交挽牢。

<p style="color:blue">那為什么會(huì)這樣做呢谱煤?

其實(shí)總的來說,不論mysql什么時(shí)刻crash禽拔,最終是commit還是rollback完全取決于MySQL能不能判斷出binlog和redolog在邏輯上是否達(dá)成了一致刘离。只要邏輯上達(dá)成了一致就可以commit,否則只能rollback睹栖。

比如還是上面描述的場(chǎng)景硫惕,binlog已經(jīng)寫了,但是MySQL最終選擇了回滾野来。那代表你的binlog比BufferPool(或者Disk)中的真實(shí)數(shù)據(jù)多出一條更新恼除,日后你用這份binlog做數(shù)據(jù)恢復(fù),是不是結(jié)果一定是錯(cuò)誤的曼氛?


六豁辉、如何判斷binlog和redolog是否達(dá)成了一致

<p style="color:red">這個(gè)知識(shí)點(diǎn)可是純干貨!

<p style="color:green">當(dāng)MySQL寫完redolog并將它標(biāo)記為prepare狀態(tài)時(shí)舀患,并且會(huì)在redolog中記錄一個(gè)XID徽级,它全局唯一的標(biāo)識(shí)著這個(gè)事務(wù)。而當(dāng)你設(shè)置sync_binlog=1時(shí)聊浅,做完了上面第一階段寫redolog后餐抢,mysql就會(huì)對(duì)應(yīng)binlog并且會(huì)直接將其刷新到磁盤中现使。

<p style="color:green">下圖就是磁盤上的row格式的binlog記錄。binlog結(jié)束的位置上也有一個(gè)XID弹澎。

<p style="color:green">只要這個(gè)XID和redolog中記錄的XID是一致的朴下,MySQL就會(huì)認(rèn)為binlog和redolog邏輯上一致。就上面的場(chǎng)景來說就會(huì)commit苦蒿,而如果僅僅是rodolog中記錄了XID殴胧,binlog中沒有,MySQL就會(huì)RollBack

image


七佩迟、兩階段提交設(shè)計(jì)的初衷 - 分布式事務(wù)

其實(shí)兩階段提交更多的被使用在分布式事務(wù)的場(chǎng)景团滥。

我用大白話描述一個(gè)這樣的場(chǎng)景,大家自行腦補(bǔ)一下:

MySQL單機(jī)本來是支持事務(wù)的报强,但是這里所謂的分布式事務(wù)實(shí)際上指的是跨數(shù)據(jù)庫灸姊、跨集群的事務(wù)。比如說你公司的業(yè)務(wù)太火爆了秉溉,每天都產(chǎn)生大量的數(shù)據(jù)力惯,這些數(shù)據(jù)不僅單表存不下,甚至單庫都存不下了(已經(jīng)達(dá)到了服務(wù)器硬件存儲(chǔ)的瓶頸)

那你怎么辦召嘶?是不是只能將單庫拆分成多庫父晶?

那你拆分成多庫就會(huì)面臨這樣一個(gè)新的問題。假設(shè)Tom給Jerry轉(zhuǎn)賬弄跌,但是由于你拆分了數(shù)據(jù)庫甲喝,原本在同庫同表上的Tom和Jerry的信息,被你拆分進(jìn)A庫a表和B庫b表铛只。那你再發(fā)起轉(zhuǎn)賬邏輯時(shí)埠胖,萬一失敗了。如何回滾保證數(shù)據(jù)的安全淳玩?這就是分布式事務(wù)的要解決的問題直撤。

通常各大公司都有自己的支持分布式事務(wù)中間件,中間件的作用本質(zhì)上就是處理好各個(gè)數(shù)據(jù)庫節(jié)點(diǎn)之間兩階段提交的問題凯肋。

簡(jiǎn)單來說:就是中間件要協(xié)調(diào)各個(gè)數(shù)據(jù)節(jié)點(diǎn)谊惭。

第一階段:中間件告訴各數(shù)據(jù)庫節(jié)點(diǎn),讓它們開啟XA事務(wù)侮东,然后判斷所有數(shù)據(jù)庫節(jié)點(diǎn)是否已經(jīng)處于prepare狀態(tài)

第二階段:中間件判斷事務(wù)提交還是回滾的階段圈盔。如果所有節(jié)點(diǎn)都prepare那就統(tǒng)一提交。但凡出現(xiàn)一個(gè)失敗的節(jié)點(diǎn)悄雅,統(tǒng)一回滾驱敲。

這里只是稍微提及一下:兩階段提交和分布式事務(wù)的淵源。

白日夢(mèng)后續(xù)計(jì)劃還會(huì)有文章中進(jìn)一步跟大家詳細(xì)的分享分布式事務(wù)話題宽闲。


八众眨、再看MySQL兩階段寫日志

那我們?cè)賹⑺悸防氐組ySQL兩階段寫日志的話題握牧。

其實(shí)說到這里,你大概也能直接想到娩梨,其實(shí)上一篇文章中的兩階段提交沿腰,表面上其實(shí)就是兩階段寫入日志。

通過我前面的描述狈定,你也一定知道了兩份日志文件邏輯對(duì)齊的標(biāo)記是有一份相同的XID颂龙。

就是這種兩階段的機(jī)制保證了兩個(gè)日志(在分布式事務(wù)中就是多個(gè)數(shù)據(jù)節(jié)點(diǎn))在邏輯上能達(dá)到一致的效果。


九纽什、留一個(gè)彩蛋

如果你仔細(xì)想一下措嵌,上面第三部分在分享 sync_binlog=1 加餐時(shí),我所描述的示例場(chǎng)景其實(shí)是適用于單機(jī)MySQL的簡(jiǎn)單場(chǎng)景芦缰。

其實(shí)這個(gè)場(chǎng)景還能再復(fù)雜一些企巢!

串聯(lián)MySQL集群、將同步让蕾、半同步浪规、異步的主從復(fù)制關(guān)系以及這里的兩階段提交、日志的落盤時(shí)機(jī)探孝、幽靈事務(wù)罗丰!結(jié)合成一個(gè)場(chǎng)景效果會(huì)更好。

但是我將它放在《為研發(fā)同學(xué)定制的面試指南》排期的后半部分也就是MySQL集群部分再姑。讓我們從易到難過度過去! 歡迎關(guān)注白日夢(mèng)找御。


十元镀、推薦閱讀(公眾號(hào)首發(fā),歡迎關(guān)注白日夢(mèng))

  1. MySQL的修仙之路霎桅,圖文談?wù)勅绾螌W(xué)MySQL栖疑、如何進(jìn)階!(已發(fā)布)
  2. 面前突擊滔驶!33道數(shù)據(jù)庫高頻面試題遇革,你值得擁有!(已發(fā)布)
  3. 大家常說的基數(shù)是什么揭糕?(已發(fā)布)
  4. 講講什么是慢查萝快!如何監(jiān)控?如何排查著角?(已發(fā)布)
  5. 對(duì)NotNull字段插入Null值有啥現(xiàn)象揪漩?(已發(fā)布)
  6. 能談?wù)?date、datetime吏口、time奄容、timestamp冰更、year的區(qū)別嗎?(已發(fā)布)
  7. 了解數(shù)據(jù)庫的查詢緩存和BufferPool嗎昂勒?談?wù)効矗蜀细。ㄒ寻l(fā)布)
  8. 你知道數(shù)據(jù)庫緩沖池中的LRU-List嗎?(已發(fā)布)
  9. 談?wù)剶?shù)據(jù)庫緩沖池中的Free-List戈盈?(已發(fā)布)
  10. 談?wù)剶?shù)據(jù)庫緩沖池中的Flush-List奠衔?(已發(fā)布)
  11. 了解臟頁刷回磁盤的時(shí)機(jī)嗎?(已發(fā)布)
  12. 用十一張圖講清楚奕谭,當(dāng)你CRUD時(shí)BufferPool中發(fā)生了什么涣觉!以及BufferPool的優(yōu)化!(已發(fā)布)
  13. 聽說過表空間沒血柳?什么是表空間官册?什么是數(shù)據(jù)表?(已發(fā)布)
  14. 談?wù)凪ySQL的:數(shù)據(jù)區(qū)难捌、數(shù)據(jù)段膝宁、數(shù)據(jù)頁、數(shù)據(jù)頁究竟長(zhǎng)什么樣根吁?了解數(shù)據(jù)頁分裂嗎员淫?談?wù)効矗?已發(fā)布)
  15. 談?wù)凪ySQL的行記錄是什么?長(zhǎng)啥樣击敌?(已發(fā)布)
  16. 了解MySQL的行溢出機(jī)制嗎介返?(已發(fā)布)
  17. 說說fsync這個(gè)系統(tǒng)調(diào)用吧! (已發(fā)布)
  18. 簡(jiǎn)述undo log、truncate沃斤、以及undo log如何幫你回滾事物! (已發(fā)布)
  19. 我勸圣蝎!這位年輕人不講MVCC,耗子尾汁衡瓶! (已發(fā)布)
  20. MySQL的崩潰恢復(fù)到底是怎么回事徘公? (已發(fā)布)
  21. MySQL的binlog有啥用?誰寫的哮针?在哪里关面?怎么配置 (已發(fā)布)
  22. MySQL的bin log的寫入機(jī)制 (已發(fā)布)
  23. 刪庫后!除了跑路還能干什么十厢?(已發(fā)布)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末等太,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蛮放,更是在濱河造成了極大的恐慌澈驼,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筛武,死亡現(xiàn)場(chǎng)離奇詭異缝其,居然都是意外死亡挎塌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門内边,熙熙樓的掌柜王于貴愁眉苦臉地迎上來榴都,“玉大人,你說我怎么就攤上這事漠其∽旄撸” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵和屎,是天一觀的道長(zhǎng)拴驮。 經(jīng)常有香客問我,道長(zhǎng)柴信,這世上最難降的妖魔是什么套啤? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮随常,結(jié)果婚禮上潜沦,老公的妹妹穿的比我還像新娘。我一直安慰自己绪氛,他們只是感情好唆鸡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著枣察,像睡著了一般争占。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上序目,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天燃乍,我揣著相機(jī)與錄音,去河邊找鬼宛琅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛逗旁,可吹牛的內(nèi)容都是我干的嘿辟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼片效,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼红伦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起淀衣,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤昙读,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后膨桥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛮浑,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唠叛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沮稚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艺沼。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蕴掏,靈堂內(nèi)的尸體忽然破棺而出障般,到底是詐尸還是另有隱情,我是刑警寧澤盛杰,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布挽荡,位于F島的核電站,受9級(jí)特大地震影響即供,放射性物質(zhì)發(fā)生泄漏定拟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一募狂、第九天 我趴在偏房一處隱蔽的房頂上張望办素。 院中可真熱鬧,春花似錦祸穷、人聲如沸性穿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽需曾。三九已至,卻和暖如春祈远,著一層夾襖步出監(jiān)牢的瞬間呆万,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工车份, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谋减,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓扫沼,卻偏偏與公主長(zhǎng)得像出爹,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缎除,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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