數(shù)據(jù)庫(kù)中間件Mycat+SpringBoot完成分庫(kù)分表

作者齐帚,藍(lán)雄威妒牙,叩丁狼教育高級(jí)講師。轉(zhuǎn)載請(qǐng)聯(lián)系作者对妄。

一湘今、背景

隨著時(shí)間和業(yè)務(wù)的發(fā)展,數(shù)據(jù)庫(kù)中的數(shù)據(jù)量增長(zhǎng)是不可控的剪菱,庫(kù)和表中的數(shù)據(jù)會(huì)越來(lái)越大摩瞎,隨之帶來(lái)的是更高的磁盤、IO孝常、系統(tǒng)開銷旗们,甚至性能上的瓶頸,而一臺(tái)服務(wù)的資源終究是有限的构灸,因此需要對(duì)數(shù)據(jù)庫(kù)和表進(jìn)行拆分蚪拦,從而更好的提供數(shù)據(jù)服務(wù)。

當(dāng)用戶表達(dá)到千萬(wàn)級(jí)別冻押,在做很多操作的時(shí)候都會(huì)很吃力驰贷,所以當(dāng)數(shù)據(jù)增長(zhǎng)到1000萬(wàn)以上就需要分庫(kù)分表來(lái)緩解單庫(kù)(表)的壓力。

二洛巢、什么是分庫(kù)分表[1]

簡(jiǎn)單來(lái)說(shuō)括袒,就是指通過某種特定的條件,將我們存放在同一個(gè)數(shù)據(jù)庫(kù)中的數(shù)據(jù)分散存放到多個(gè)數(shù)據(jù)庫(kù)(主機(jī))上面稿茉,以達(dá)到分散單臺(tái)設(shè)備負(fù)載的效果锹锰。

數(shù)據(jù)的切分(Sharding)根據(jù)其切分規(guī)則的類型,可以分為兩種切分模式漓库。一種是按照不同的表(或者Schema)來(lái)切分到不同的數(shù)據(jù)庫(kù)(主機(jī))之上恃慧,這種切可以稱之為數(shù)據(jù)的垂直(縱向)切分;另外一種則是根據(jù)表中的數(shù)據(jù)的邏輯關(guān)系渺蒿,將同一個(gè)表中的數(shù)據(jù)按照某種條件拆分到多臺(tái)數(shù)據(jù)庫(kù)(主機(jī))上面痢士,這種切分稱之為數(shù)
據(jù)的水平(橫向)切分。

垂直切分的最大特點(diǎn)就是規(guī)則簡(jiǎn)單茂装,實(shí)施也更為方便怠蹂,尤其適合各業(yè)務(wù)之間的耦合度非常低善延,相互影響很小,業(yè)務(wù)邏輯非常清晰的系統(tǒng)城侧。在這種系統(tǒng)中易遣,可以很容易做到將不同業(yè)務(wù)模塊所使用的表分拆到不同的數(shù)據(jù)庫(kù)中。根據(jù)不同的表來(lái)進(jìn)行拆分嫌佑,對(duì)應(yīng)用程序的影響也更小豆茫,拆分規(guī)則也會(huì)比較簡(jiǎn)單清晰。

水平切分于垂直切分相比屋摇,相對(duì)來(lái)說(shuō)稍微復(fù)雜一些澜薄。因?yàn)橐獙⑼粋€(gè)表中的不同數(shù)據(jù)拆分到不同的數(shù)據(jù)庫(kù)中,對(duì)于應(yīng)用程序來(lái)說(shuō)摊册,拆分規(guī)則本身就較根據(jù)表名來(lái)拆分更為復(fù)雜肤京,后期的數(shù)據(jù)維護(hù)也會(huì)更為復(fù)雜一些。

三茅特、垂直切分 [1]

個(gè)數(shù)據(jù)庫(kù)由很多表的構(gòu)成忘分,每個(gè)表對(duì)應(yīng)著不同的業(yè)務(wù),垂直切分是指按照業(yè)務(wù)將表進(jìn)行分類白修,分布到不同
的數(shù)據(jù)庫(kù)上面妒峦,這樣也就將數(shù)據(jù)或者說(shuō)壓力分擔(dān)到不同的庫(kù)上面,如下圖:



系統(tǒng)被切分成了兵睛,用戶肯骇,訂單交易,支付幾個(gè)模塊祖很。
一個(gè)架構(gòu)設(shè)計(jì)較好的應(yīng)用系統(tǒng)笛丙,其總體功能肯定是由很多個(gè)功能模塊所組成的,而每一個(gè)功能模塊所需要的數(shù)據(jù)對(duì)應(yīng)到數(shù)據(jù)庫(kù)中就是一個(gè)或者多個(gè)表假颇。而在架構(gòu)設(shè)計(jì)中胚鸯,各個(gè)功能模塊相互之間的交互點(diǎn)越統(tǒng)一越少,系統(tǒng)的耦合度就越低笨鸡,系統(tǒng)各個(gè)模塊的維護(hù)性以及擴(kuò)展性也就越好姜钳。這樣的系統(tǒng),實(shí)現(xiàn)數(shù)據(jù)的垂直切分也就越容易形耗。

但是往往系統(tǒng)之有些表難以做到完全的獨(dú)立哥桥,存在這擴(kuò)庫(kù) join 的情況,對(duì)于這類的表激涤,就需要去做平衡拟糕,是數(shù)據(jù)庫(kù)讓步業(yè)務(wù),共用一個(gè)數(shù)據(jù)源,還是分成多個(gè)庫(kù)已卸,業(yè)務(wù)之間通過接口來(lái)做調(diào)用。在系統(tǒng)初期硼一,數(shù)據(jù)量比較少累澡,或者資源有限的情況下,會(huì)選擇共用數(shù)據(jù)源般贼,但是當(dāng)數(shù)據(jù)發(fā)展到了一定的規(guī)模愧哟,負(fù)載很大的情況,就需
要必須去做分割哼蛆。

一般來(lái)講業(yè)務(wù)存在著復(fù)雜 join 的場(chǎng)景是難以切分的蕊梧,往往業(yè)務(wù)獨(dú)立的易于切分。如何切分腮介,切分到何種
程度是考驗(yàn)技術(shù)架構(gòu)的一個(gè)難題肥矢。
下面來(lái)分析下垂直切分的優(yōu)缺點(diǎn):

優(yōu)點(diǎn)

  • 拆分后業(yè)務(wù)清晰,拆分規(guī)則明確叠洗;
  • 系統(tǒng)之間整合或擴(kuò)展容易甘改;
  • 數(shù)據(jù)維護(hù)簡(jiǎn)單。

缺點(diǎn)

  • 部分業(yè)務(wù)表無(wú)法 join灭抑,只能通過接口方式解決十艾,提高了系統(tǒng)復(fù)雜度;
  • 受每種業(yè)務(wù)不同的限制存在單庫(kù)性能瓶頸腾节,不易數(shù)據(jù)擴(kuò)展跟性能提高忘嫉;
  • 事務(wù)處理復(fù)雜。

由于垂直切分是按照業(yè)務(wù)的分類將表分散到不同的庫(kù)案腺,所以有些業(yè)務(wù)表會(huì)過于龐大庆冕,存在單庫(kù)讀寫與存儲(chǔ)瓶頸,所以就需要水平拆分來(lái)做解決劈榨。

四愧杯、水平切分 [1]

相對(duì)于垂直拆分,水平拆分不是將表做分類鞋既,而是按照某個(gè)字段的某種規(guī)則來(lái)分散到多個(gè)庫(kù)之中力九,每個(gè)表中包含一部分?jǐn)?shù)據(jù)。簡(jiǎn)單來(lái)說(shuō)邑闺,我們可以將數(shù)據(jù)的水平切分理解為是按照數(shù)據(jù)行的切分跌前,就是將表中的某些行切分到一個(gè)數(shù)據(jù)庫(kù),而另外的某些行又切分到其他的數(shù)據(jù)庫(kù)中陡舅,如圖


拆分?jǐn)?shù)據(jù)就需要定義分片規(guī)則抵乓。關(guān)系型數(shù)據(jù)庫(kù)是行列的二維模型,拆分的第一原則是找到拆分維度。比如:
從會(huì)員的角度來(lái)分析灾炭,商戶訂單交易類系統(tǒng)中查詢會(huì)員某天某月某個(gè)訂單茎芋,那么就需要按照會(huì)員結(jié)合日期來(lái)拆分,不同的數(shù)據(jù)按照會(huì)員 ID 做分組蜈出,這樣所有的數(shù)據(jù)查詢 join 都會(huì)在單庫(kù)內(nèi)解決田弥;如果從商戶的角度來(lái)講,要查詢某個(gè)商家某天所有的訂單數(shù)铡原,就需要按照商戶 ID 做拆分偷厦;但是如果系統(tǒng)既想按會(huì)員拆分,又想按商家數(shù)據(jù)燕刻,則會(huì)有一定的困難只泼。如何找到合適的分片規(guī)則需要綜合考慮衡。
幾種典型的分片規(guī)則包括:

  • 按照用戶 ID 求模卵洗,將數(shù)據(jù)分散到不同的數(shù)據(jù)庫(kù)请唱,具有相同數(shù)據(jù)用戶的數(shù)據(jù)都被分散到一個(gè)庫(kù)中;
  • 按照日期过蹂,將不同月甚至日的數(shù)據(jù)分散到不同的庫(kù)中籍滴;
  • 按照某個(gè)特定的字段求摸,或者根據(jù)特定范圍段分散到不同的庫(kù)中榴啸。

如圖孽惰,切分原則都是根據(jù)業(yè)務(wù)找到適合的切分規(guī)則分散到不同的庫(kù),下面用用戶 ID 求模舉


既然數(shù)據(jù)做了拆分有優(yōu)點(diǎn)也就優(yōu)缺點(diǎn)鸥印。
優(yōu)點(diǎn)

  • 拆分規(guī)則抽象好勋功,join 操作基本可以數(shù)據(jù)庫(kù)做;
  • 不存在單庫(kù)大數(shù)據(jù)库说,高并發(fā)的性能瓶頸狂鞋;
  • 應(yīng)用端改造較少;
  • 提高了系統(tǒng)的穩(wěn)定性跟負(fù)載能力潜的。

缺點(diǎn)

  • 拆分規(guī)則難以抽象骚揍;
  • 分片事務(wù)一致性難以解決;
  • 數(shù)據(jù)多次擴(kuò)展難度跟維護(hù)量極大啰挪;
  • 跨庫(kù) join 性能較差

五信不、什么是Mycat

它是一個(gè)開源的分布式數(shù)據(jù)庫(kù)系統(tǒng),是一個(gè)實(shí)現(xiàn)了 MySQL 協(xié)議的的
Server亡呵,前端用戶可以把它看作是一個(gè)數(shù)據(jù)庫(kù)代理抽活,用 MySQL 客戶端工具和命令行訪問,而其后端可以用MySQL 原生(Native)協(xié)議與多個(gè) MySQL 服務(wù)器通信锰什,也可以用 JDBC 協(xié)議與大多數(shù)主流數(shù)據(jù)庫(kù)服務(wù)器通信下硕,其核心功能是分表分庫(kù)丁逝,即將一個(gè)大表水平分割為 N 個(gè)小表,存儲(chǔ)在后端 MySQL 服務(wù)器里或者其他數(shù)據(jù)庫(kù)里梭姓。

常見應(yīng)用場(chǎng)景:
  • 單純的讀寫分離霜幼,此時(shí)配置最為簡(jiǎn)單,支持讀寫分離誉尖,主從切換罪既;
  • 分表分庫(kù),對(duì)于超過 1000 萬(wàn)的表進(jìn)行分片释牺,最大支持 1000 億的單表分片萝衩;
  • 多租戶應(yīng)用回挽,每個(gè)應(yīng)用一個(gè)庫(kù)没咙,但應(yīng)用程序只連接 Mycat,從而不改造程序本身千劈,實(shí)現(xiàn)多租戶化祭刚;
  • 報(bào)表系統(tǒng),借助于 Mycat 的分表能力墙牌,處理大規(guī)模報(bào)表的統(tǒng)計(jì)涡驮;? 替代 Hbase,分析大數(shù)據(jù)喜滨;
  • 作為海量數(shù)據(jù)實(shí)時(shí)查詢的一種簡(jiǎn)單有效方案捉捅,比如 100 億條頻繁查詢的記錄需要在 3 秒內(nèi)查詢出來(lái)結(jié)果,除了基于主鍵的查詢虽风,還可能存在范圍查詢或其他屬性查詢棒口,此時(shí) Mycat 可能是最簡(jiǎn)單有效的選

六、SpringBoot+Mycat+MySQL實(shí)現(xiàn)分表分庫(kù)案例

關(guān)于分庫(kù)分表辜膝,Mycat已經(jīng)幫我們?cè)趦?nèi)部實(shí)現(xiàn)了路由的功能无牵,我們只需要在Mycat中配置以下切分規(guī)則即可,對(duì)于開發(fā)者來(lái)說(shuō)厂抖,我們就可以把Mycat看做是一個(gè)數(shù)據(jù)庫(kù)茎毁,接下來(lái)我們開始搭建環(huán)境:

步驟一:

Mycat是使用java寫的數(shù)據(jù)庫(kù)中間件,所以要運(yùn)行Mycat前要準(zhǔn)備要jdk的環(huán)境忱辅,要求是jdk1.7以上的環(huán)境七蜘。所以需要在系統(tǒng)中配置JAVA_HOME的環(huán)境變量.

步驟二:

從官網(wǎng)下載Mycat,http://dl.mycat.io/1.6-RELEASE/ 我們是基于CentOS7來(lái)搭建Mycat環(huán)境的墙懂,所以下載版本:
Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz

步驟三:

將下載好的安裝包上傳到服務(wù)器上并解壓.解壓之后目錄結(jié)構(gòu)如下:


步驟四:

配置切分規(guī)則:
將如下配置復(fù)制粘貼覆蓋mycat/conf/schema.xml的內(nèi)容崔梗。

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">

    <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
            <table name="user" primaryKey="id" dataNode="dn01,dn02" rule="rule1" />  
    </schema>
    
    <!-- 設(shè)置dataNode 對(duì)應(yīng)的數(shù)據(jù)庫(kù),及 mycat 連接的地址dataHost -->  
    <dataNode name="dn01" dataHost="dh01" database="db01" />  
    <dataNode name="dn02" dataHost="dh01" database="db02" />   
    
    <!-- mycat 邏輯主機(jī)dataHost對(duì)應(yīng)的物理主機(jī).其中也設(shè)置對(duì)應(yīng)的mysql登陸信息 -->  
    <dataHost name="dh01" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native">  
            <heartbeat>select user()</heartbeat>  
            <writeHost host="server1" url="127.0.0.1:3306" user="root" password="WolfCode_2017"/>  
    </dataHost> 
</mycat:schema>

<schema>:表示的是在mycat中的邏輯庫(kù)配置,邏輯庫(kù)名稱為:TESTDB

<table>:表示在mycat中的邏輯表配置垒在,邏輯表名稱為:user,映射到兩個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)dataNode中,切分規(guī)則為:rule1(在rule.xml配置)

<dataNode>:表示數(shù)據(jù)庫(kù)節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)不一定是單節(jié)點(diǎn)蒜魄,可以配置成讀寫分離.

<dataHost>:真實(shí)的數(shù)據(jù)庫(kù)的地址配置

<heartbeat>:用戶心跳檢測(cè)

<writeHost>:寫庫(kù)的配置

將如下配置復(fù)制粘貼覆蓋mycat/conf/rule.xml的內(nèi)容扔亥。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mycat:rule SYSTEM "rule.dtd">
<mycat:rule xmlns:mycat="http://io.mycat/">
    <tableRule name="rule1">
        <rule>
            <columns>id</columns>
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!-- how many data nodes -->
        <property name="count">2</property>
    </function>
</mycat:rule>

這里定義的是切分規(guī)則,是按照id列進(jìn)行切分谈为,切分規(guī)則是采取取模的方式,
<property name="count">2</property>:這里配置了我們有拆分了多個(gè)庫(kù)(表)旅挤,需要和前面配置
<table name="user" primaryKey="id" dataNode="dn01,dn02" rule="rule1" />
中的dataNode個(gè)數(shù)一致,否則會(huì)出錯(cuò).

步驟五:

在數(shù)據(jù)庫(kù)中創(chuàng)建兩個(gè)數(shù)據(jù)庫(kù)db01,db02.
每個(gè)庫(kù)中執(zhí)行如下建表語(yǔ)句:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

步驟六:

啟動(dòng)mycat,執(zhí)行mycat/bin/startup_nowrap.sh

步驟七:

項(xiàng)目已經(jīng)上傳到github
https://github.com/javalanxiongwei/springboot-mycat
搭建SpringBoot環(huán)境伞鲫,執(zhí)行插入語(yǔ)句.
application.properties配置如下:

#配置數(shù)據(jù)源
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
#這里配置的是Mycat中server.xml中配置賬號(hào)密碼粘茄,不是數(shù)據(jù)庫(kù)的密碼。
spring.datasource.druid.username=root
spring.datasource.druid.password=123456
#mycat的邏輯庫(kù) 端口也是mycat的
spring.datasource.druid.url=jdbc:mysql://192.168.142.129:8066/TESTDB

UserMapper.java代碼如下:

@Mapper
public interface UserMapper {
    @Insert("insert into user(id,name) value (#{id},#{name})")
    int insert(User user);
    @Select("select * from user")
    List<User> selectAll();
}

UserController.java代碼如下:

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserMapper userMapper;
    @RequestMapping("/save")
    public String save(User user){
        userMapper.insert(user);
        return "保存成功";
    }
    @RequestMapping("/list")
    public List<User> list(){
        return userMapper.selectAll();
    }
}
步驟八:

測(cè)試:
在地址欄輸入:
http://localhost:8080/user/save?id=1&name=tom
http://localhost:8080/user/save?id=2&name=jack
查看數(shù)據(jù)庫(kù)發(fā)現(xiàn):
id為1的數(shù)據(jù)插入到數(shù)據(jù)庫(kù)db02中的user表秕脓。
id為2的數(shù)據(jù)插入到數(shù)據(jù)庫(kù)db01中的user表柒瓣。
在地址欄輸入:
http://localhost:8080/user/list
是可以看到剛剛插入的兩條記錄.

好到這一步我們就已經(jīng)完成了分表分庫(kù)了.


  1. 參考mycat-definitive-guide.pdf。 ? ? ?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吠架,一起剝皮案震驚了整個(gè)濱河市芙贫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌傍药,老刑警劉巖磺平,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拐辽,居然都是意外死亡拣挪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門俱诸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)菠劝,“玉大人,你說(shuō)我怎么就攤上這事睁搭「险铮” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵介袜,是天一觀的道長(zhǎng)甫何。 經(jīng)常有香客問我,道長(zhǎng)遇伞,這世上最難降的妖魔是什么辙喂? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鸠珠,結(jié)果婚禮上巍耗,老公的妹妹穿的比我還像新娘。我一直安慰自己渐排,他們只是感情好炬太,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著驯耻,像睡著了一般亲族。 火紅的嫁衣襯著肌膚如雪炒考。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天霎迫,我揣著相機(jī)與錄音斋枢,去河邊找鬼。 笑死知给,一個(gè)胖子當(dāng)著我的面吹牛瓤帚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涩赢,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼戈次,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了筒扒?” 一聲冷哼從身側(cè)響起怯邪,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎霎肯,沒想到半個(gè)月后擎颖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體榛斯,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡观游,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驮俗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片懂缕。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖王凑,靈堂內(nèi)的尸體忽然破棺而出搪柑,到底是詐尸還是另有隱情,我是刑警寧澤索烹,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布工碾,位于F島的核電站,受9級(jí)特大地震影響百姓,放射性物質(zhì)發(fā)生泄漏渊额。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一垒拢、第九天 我趴在偏房一處隱蔽的房頂上張望旬迹。 院中可真熱鬧,春花似錦求类、人聲如沸奔垦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)椿猎。三九已至惶岭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間犯眠,已是汗流浹背俗他。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留阔逼,地道東北人兆衅。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嗜浮,于是被迫代替她去往敵國(guó)和親羡亩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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