Mybatis之旅(序)

序中序

? ? 本系列旨在探討mybatis底層邏輯,順便以源碼出發(fā),探究Java語言的若干機制禀挫。

? ? 同時,此系列采取工程代碼開發(fā)中敏捷的原則拓颓,不會像以往一樣動輒寫數(shù)千字语婴,而是以“小步快跑”的形式,快速對自己所學(xué)的知識作出反應(yīng)驶睦,總結(jié)砰左、分享出來。

? ? 本文的第一场航、二節(jié)講述一些網(wǎng)頁應(yīng)用缠导,ORM和持久化的基本概念,第三節(jié)會講一個最簡單的mybatis使用的實例(正如網(wǎng)上大部分博客那樣)旗闽。

一酬核、網(wǎng)頁應(yīng)用

? ? 以簡書一個不知名博主的主頁為例:http://www.reibang.com/u/6d6837a8715a

? ? 當(dāng)我們在瀏覽器輸入上面這個鏈接,按下回車的時候适室,瀏覽器就會根據(jù)這個鏈接向相關(guān)的服務(wù)器請求數(shù)據(jù)(詳情可見《無線世界》系列)嫡意。服務(wù)器會返回html,js和css文件給我們的電腦捣辆,我們電腦上的瀏覽器會解析這些文件蔬螟,并且將簡書的頁面展示給我們看。

? ? 這種模式被成為瀏覽器/服務(wù)器模式(B/S Browser/Server)汽畴。另外一種常見的叫做客戶端/服務(wù)器模式(C/S Client/Server)旧巾,咱也不懂,咱也不去說忍些。

? ? 但是簡書上的博主鲁猩、用戶這么多,簡書不可能為每一個人都單獨建立一套html/js/css文件罢坝,于是采取了比較討巧的做法:只用一份html/js/css文件來用作頁面的展示廓握,而將用戶名,文章嘁酿,動態(tài)等信息存進數(shù)據(jù)庫中隙券,為每一個用戶配置一個唯一id,用這個id來關(guān)聯(lián)用戶的數(shù)據(jù)闹司。

? ? 這就可以引申到MVC(Model-View-Control)模型的基本思想娱仔。M指業(yè)務(wù)模型,V指用戶界面游桩,C指控制器(用于業(yè)務(wù)模型和用戶界面的同步等)牲迫。控制器處理用戶的入?yún)ⅲū热缟侠泻啎溄幼詈蟮膇d)众弓,控制器會根據(jù)入?yún)⒌綐I(yè)務(wù)模型中存取數(shù)據(jù)(上例中就是取出用戶“宮本花藏”的文章恩溅、評論等信息),最后在用戶界面上予以展示(如上上圖所示)谓娃。

二脚乡、持久化框架與ORM

? ? 在面向?qū)ο笾校腥龑蛹軜?gòu)的思想滨达。對于服務(wù)器來說奶稠,用戶能夠接觸到的往往是最外的表現(xiàn)層,使用MVC模式來接收用戶數(shù)據(jù)捡遍,或者向用戶展示數(shù)據(jù)锌订;服務(wù)層用戶用戶數(shù)據(jù)的邏輯處理;而最里面的持久層用于和數(shù)據(jù)庫打交道画株,負(fù)責(zé)數(shù)據(jù)的增刪改查辆飘。

? ? 人們都說mybatis是持久層框架啦辐,就是說mybatis這個框架,是專門用來讓Java程序和數(shù)據(jù)庫交互的蜈项。

? ? 如果說誰發(fā)明了一個服務(wù)層框架芹关,就是說他設(shè)計的這個框架是專門用來處理業(yè)務(wù)邏輯的。emmm思考題:這么說來紧卒,那些算法的jar包看來都能算成服務(wù)層框架了侥衬??跑芳?

?? ?眾所周知轴总,服務(wù)器能正常運行是要靠代碼部署在上面的。Java是常用的服務(wù)器邏輯代碼博个。如果想要通過Java訪問數(shù)據(jù)庫怀樟,就必須使用到Java中的JDBC接口。傳統(tǒng)的JDBC連接數(shù)據(jù)庫方式很繁瑣盆佣,要先注冊數(shù)據(jù)庫驅(qū)動類漂佩,確認(rèn)url,賬號密碼罪塔,再通過DriverManager打開數(shù)據(jù)庫連接投蝉,將拼接好的SQL語句以字符串的形式給Statement,得到執(zhí)行結(jié)果后手動關(guān)閉數(shù)據(jù)庫鏈接征堪。

? ? 為了解決該問題瘩缆,ORM(Object Relation Mapping,對象-關(guān)系映射)框架應(yīng)運而生佃蚜。java代碼可以根據(jù)映射配置文件庸娱,完成數(shù)據(jù)在對象模型(Java語言)與關(guān)系模型(SQL語言)之間的映射(比如java中的String類可以轉(zhuǎn)換成SQL中的VARCHAR數(shù)據(jù)類型)。

? ? 另外谐算,頻繁的新建熟尉、關(guān)閉數(shù)據(jù)庫連接會極大的消耗資源,成為系統(tǒng)的性能瓶頸洲脂。ORM框架的另外一個特色功能就是建立數(shù)據(jù)庫連接池:專門創(chuàng)建若干給數(shù)據(jù)庫連接斤儿,當(dāng)某進程有連接請求時就將連接分配給該進程,用完了也不釋放連接恐锦,而是將連接對象再放進池子里面來往果,供別的進程使用。

? ? 在書寫代碼的過程中一铅,千千萬萬的程序員上演著可歌可泣的與bug斗智斗勇的故事陕贮,聞?wù)吡鳒I,聽者傷心潘飘。代碼既要處理用戶輸入肮之,又要執(zhí)行業(yè)務(wù)邏輯掉缺,存取數(shù)據(jù);同時內(nèi)要考慮負(fù)載均衡進程沖突資源搶占戈擒,外要預(yù)防非法輸入網(wǎng)絡(luò)攻擊安全漏洞攀圈,忙不勝收。

? ? 于是峦甩,偉大的程序員先賢們針對代碼混亂的問題,建立了各種框架现喳。這些框架劃分不同功能的代碼凯傲,讓它們各司其職。這些代碼大多可以不依賴其他服務(wù)獨立運行嗦篱,并且提供某些特定服務(wù)冰单。隨著時代的發(fā)展,不同功能的代碼還會劃分層次灸促,分出哪些用于公共服務(wù)诫欠,哪些用于應(yīng)用實現(xiàn)。

? ? 比如上面這個浴栽,分成了基礎(chǔ)支持層荒叼,核心處理層和接口層3層。每一層各個模塊的功能目的都不相同典鸡。這個框架就是mybatis整體的框架被廓,也是接下來我們的探索旅程的全景圖。

? ? 不過由于本文是序文萝玷,所以本文只是給了一個最簡單的mybatis使用的示例嫁乘。

三、mybatis示例

?? ?所需:mysql數(shù)據(jù)庫球碉,集成開發(fā)環(huán)境IDEA(社區(qū)版即可)蜓斧,maven,預(yù)先裝好的JDK1.8睁冬,一個能聯(lián)網(wǎng)的環(huán)境

3.1 MySQL

? ? 既然mybatis是與數(shù)據(jù)庫打交道的框架挎春,就必須安裝數(shù)據(jù)庫。以免費的mysql為例豆拨,需要先注冊O(shè)RACLE賬戶搂蜓,登錄進行下載。沒有ORACLE賬戶的需要注冊一個辽装,是免費的帮碰。

? ? mysql向?qū)ф溄樱?a target="_blank">https://www.mysql.com/cn/why-mysql/white-papers/visual-guide-to-installing-mysql-windows-zh/

? ? 安裝的時候需要配置用戶名和密碼,按它給的pdf文檔來即可拾积。安裝完成后殉挽,打開的界面如下所示:

????點擊 Local instance 字樣的方框丰涉,就可以進入到頁面中

? ? 進入數(shù)據(jù)庫后,需要先創(chuàng)建schema斯碌。schema可以理解為是一個用戶一死,一個用戶可以擁有多張數(shù)據(jù)表。不同用戶之間的數(shù)據(jù)表不同傻唾,并且有訪問權(quán)限控制投慈。輸入以下語句創(chuàng)建用戶:

?? ?create schema sjjdata default character set utf8 collate utf8_general_ci;

? ? 選擇該用戶,創(chuàng)建一個包含id冠骄,姓名伪煤,年齡3個字段的表,表的名字叫做student(是不是很俗)

use sjjdata;

?? ?create table student

?? ?(id int(11),

?? ?name varchar(25),

?? ?age int(11));

????最終我們在mysql數(shù)據(jù)庫中凛辣,創(chuàng)建了一個名為sjjdata的用戶抱既,在這個用戶下新建了一張名為student的表。

3.2 Maven

? ? 程序語言發(fā)展至今扁誓,我們編程的時候再也不可能從零開始寫防泵。我們會依靠前人的編程成果,即調(diào)用代碼庫的形式蝗敢,提升我們的編程效率捷泞。在Java中,我們通常以使用jar包的形式寿谴,調(diào)用前人寫好的方法肚邢,而忽略實現(xiàn)該方法的細(xì)節(jié)(這種行為也被成為引用依賴)。jar包是一群java文件和配置文件的集合拭卿。除了jar包以外骡湖,隨著規(guī)模的不同,還有tar包峻厚,war包响蕴。一個jar包舉例:

? ? 發(fā)布jar包的團隊或個人通常會每隔一段時間更新這個包, 修復(fù)一些bug或者新增一些功能惠桃。為了便于區(qū)分浦夷,他們?yōu)槊恳淮伟l(fā)布的jar包取了一個版本號,比如上圖中的mybatis包的版本是3.2.7辜王。

? ? 其他程序員在編寫程序引用jar包的時候劈狐,常常因為jar包的版本不對而引發(fā)bug。為了解決此類問題呐馆,有很多專門解決依賴的工具肥缔,maven就是其中一個。它通過xml文件(往往這個文件的名字叫做pom.xml)確定具體引用哪個版本的哪個包汹来,就可以從它的maven倉庫中取出此包续膳,供程序員調(diào)用改艇。這么做的好處是在程序移植的時候,只要把對應(yīng)的xml文件也移植過去坟岔,其他機器上就算沒有這個jar包谒兄,或者沒有特定版本的jar包,也可以通過xml文件到maven倉庫中找到它社付。

?? ?maven是apache的開源項目承疲,可以在官網(wǎng)下載。https://maven.apache.org

? ? 下載過來的是一個zip文件鸥咖,解壓燕鸽,隨便放在某個目錄就可以。為了避免不必要的字符編碼問題扛或,建議放在英文路徑下。

? ? 當(dāng)然碘饼,有時候IDEA自己在安裝的時候可能已經(jīng)自帶了maven了……

3.3 Java

? ? IDEA也有官網(wǎng)熙兔,也有免費使用的版本,奉上鏈接:

https://www.jetbrains.com/products.html#type=ide

? ? 筆者下載的是2019.3版本艾恼,打開界面如下所示:

? ? 進入后住涉,點擊file-->new-->project,選擇maven

? 點擊next钠绍,確定工程名舆声,直接finish

? ? 在工程的出生地,就可以發(fā)現(xiàn)布局的很有規(guī)律的目錄柳爽,以及一個pom.xml文件媳握,這些都是maven規(guī)范自動生成的。

????在xml文件中磷脯,貼入如下代碼蛾找。其含義將在之后逐漸解釋。

<?xml version="1.0"encoding="UTF-8"?>

<projectxmlns="http://maven.apache.org/POM/4.0.0"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>

<artifactId>SecondMybatis</artifactId>

<version>1.0-SNAPSHOT</version>

<dependencies>

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>3.2.7</version>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>5.1.47</version>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<!-- <scope>test</scope>-->

</dependency>

<dependency>

<groupId>org.apache.logging.log4j</groupId>

<artifactId>log4j-api</artifactId>

<version>2.11.1</version>

</dependency>

<dependency>

<groupId>org.apache.logging.log4j</groupId>

<artifactId>log4j-core</artifactId>

<version>2.11.1</version>

</dependency>

</dependencies>

</project>???

????復(fù)制完之后赵誓,程序右下角會彈出這樣的對話框:

?????點擊Import Changes打毛,就可以加載pom.xml指定的jar包

?? ?按照如下格式建立目錄(直接右鍵文件夾,new俩功,選擇java或者package幻枉,這里不再贅述):

? 在UserBeanMapper中,寫入如下代碼:

package?com.sjj.dao;

import?com.sjj.entity.UserBeanVO;

import?java.util.List;

public interface?UserBeanMapper {

UserBeanVO queryUserByName(String name);

List<UserBeanVO> queryAll();

int?insertUser(UserBeanVO userBean);

int?deleteUserByName(String name);

int?updateUserById(UserBeanVO userBean,int?id);

}

? 在UserBeanVO中诡蜓,寫入如下代碼:

package?com.sjj.entity;

/**

*?@author?jun

*?@date?2019/1/31

*/

public class?UserBeanVO {

private int?id;

private?String?name;

private int?age;

public int?getId() {

return?id;

}

public void?setId(int?id) {

this.id?= id;

}

public?String getName() {

return?name;

}

public void?setName(String name) {

this.name?= name;

}

public int?getAge() {

return?age;

}

public void?setAge(int?age) {

this.age?= age;

}

@Override

public?String toString() {

return?"User{"?+

"id="?+?id?+

", name='"?+?name?+?'\''?+

", age="?+?age?+

'}';

}

}

??在UserBeanService中熬甫,寫入如下代碼:

package?com.sjj.service;

public class?UserBeanService {

}

??在DBTools中,寫入如下代碼:

package?com.sjj;

import?org.apache.ibatis.io.Resources;

import?org.apache.ibatis.session.SqlSessionFactory;

import?org.apache.ibatis.session.SqlSessionFactoryBuilder;

import?java.io.IOException;

import?java.io.Reader;

/**

*?@author?jun

*?@date?2019/1/31

*/

public class?DBtools {

private static?SqlSessionFactory?sqlSessionFactory;

static?{

try?{

Reader reader = Resources.getResourceAsReader("config/SqlMapConfig.xml");

sqlSessionFactory?=?new?SqlSessionFactoryBuilder().build(reader);

}?catch?(IOException e) {

e.printStackTrace();

}

}

public static?SqlSessionFactory getSqlSessionFactory(){

return?sqlSessionFactory;

}

}

??在mysql.properties中蔓罚,寫入如下代碼(注意罗珍,這里需要根據(jù)沒人配置的不同有所更改):

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/sjjdata?useSSL=false

jdbc.username=你的賬號洽腺,一般是root

jdbc.password=你的密碼,安裝的時候你自己配的

??在SqlMapperConfig.xml中覆旱,寫入如下代碼:

<?xml version="1.0"?encoding="UTF-8"?>

<!DOCTYPE?configuration

PUBLIC?"-//mybatis.org//DTD?Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<!--?加載properties文件?-->

<properties?resource="config/mysql.properties"></properties>

<!--?全局配置?-->

<settings>

<!--?打開延遲加載開關(guān)?-->

<setting?name="lazyLoadingEnabled"?value="true"/>

<!--?將積極加載改為消極加載即按需加載?-->

<setting?name="aggressiveLazyLoading"?value="false"/>

</settings>

<!--?定義別名?-->

<typeAliases>

<!--?一個一個地定義?-->

<!-- <typeAlias type="com.gjh.domain.User" alias="user"/> -->

<!--?指定包名定義蘸朋,別名就是類名,首字母大小寫都可以?-->

<package?name="com.sjj.entity"/>

</typeAliases>

<!--?和spring整合后?environments將廢除?-->

<environments?default="development">

<environment?id="development">

<!--?使用JDBC事務(wù)管理扣唱,事務(wù)控制由mybatis藕坯,另一種類型為MANAGED,此配置從來不提交或回滾事務(wù)?-->

<transactionManager?type="JDBC"/>

<!--?數(shù)據(jù)庫連接池噪沙,由mybatis type的值有UNPOOLED炼彪、POOLED、JNDI三種數(shù)據(jù)源

不同的數(shù)據(jù)源有不同的配置屬性?-->

<dataSource?type="POOLED">

<property?name="driver"?value="${jdbc.driver}"/>

<property?name="url"?value="${jdbc.url}"/>

<property?name="username"?value="${jdbc.username}"/>

<property?name="password"?value="${jdbc.password}"/>

</dataSource>

</environment>

</environments>

<mappers>

<!--?當(dāng)映射文件mapper與接口類名一致且在同一個路徑下時可以用class引入?-->

<!-- <mapper class="com.sjj.dao.UserBeanMapper"/>-->

<mapper?resource="mapper/UserBeanMapper.xml"/>

<!--?通過配置文件的位置加載——一次加載一個?-->

<!-- <mapper class="com.gjh.mapper.OrdersMapper"/>-->

<!--?通過包名加載——加載包內(nèi)的所有配置文件-->

<!-- <package name="mapper"/>-->

</mappers>

</configuration>

??在log4j2.xml中正歼,寫入如下代碼:

<?xml version="1.0"?encoding="UTF-8"?>

<Configuration>

<Appenders>

<Console?name="STDOUT"?target="SYSTEM_OUT">

<PatternLayout?pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>

</Console>

<RollingFile?name="RollingFile"?fileName="logs/strutslog1.log"

filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">

<PatternLayout>

<Pattern>%d{MM-dd-yyyy} %p %c{1.} [%t] -%M-%L- %m%n</Pattern>

</PatternLayout>

<Policies>

<TimeBasedTriggeringPolicy?/>

<SizeBasedTriggeringPolicy?size="1 KB"/>

</Policies>

<DefaultRolloverStrategy?fileIndex="max"?max="2"/>

</RollingFile>

</Appenders>

<Loggers>

<Logger?name="com.opensymphony.xwork2"?level="WAN"/>

<Logger?name="org.apache.struts2"?level="WAN"/>

<Root?level="warn">

<AppenderRef?ref="STDOUT"/>

</Root>

</Loggers>

</Configuration>

??在appTest中辐马,寫入如下代碼:

package?com.sjj.test;

import?com.sjj.DBtools;

import?com.sjj.dao.UserBeanMapper;

import?com.sjj.entity.UserBeanVO;

import?org.apache.ibatis.session.SqlSession;

import?org.apache.ibatis.session.SqlSessionFactory;

public class?appTest {

public static void?main(String[] args){

//1.創(chuàng)建sqlsessionFactory

SqlSessionFactory sqlSessionFactory = DBtools.getSqlSessionFactory();

//2.創(chuàng)建SqlSession

SqlSession session = sqlSessionFactory.openSession();

//3.session?中創(chuàng)建相應(yīng)的接口代理類,即mapper對象

UserBeanMapper userBeanMapper = session.getMapper(UserBeanMapper.class);

System.out.println(userBeanMapper.queryAll());

try?{

System.out.println(userBeanMapper.deleteUserByName("jun"));

UserBeanVO u1 =?new?UserBeanVO();

u1.setAge(16);

u1.setName("Nausicaa");

u1.setId(1);

System.out.println(userBeanMapper.insertUser(u1));

session.commit();//一定要提交局义,不然所有增刪改操作不會生效的

System.out.println(userBeanMapper.queryAll());

}catch?(Exception e){

session.rollback();//回滾

}

}

}

? 最終運行程序喜爷,跑出的結(jié)果如下所示:

? ? 去MySQL里面查,可以發(fā)現(xiàn)萄唇,上一篇推送《讀書筆記6:<風(fēng)之谷>》中的主角檩帐,娜烏西卡的信息,已經(jīng)被登記到了數(shù)據(jù)庫之中另萤。

四湃密、總結(jié)

? ? 謝特,怎么又有這么多字……

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末四敞,一起剝皮案震驚了整個濱河市泛源,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌忿危,老刑警劉巖俩由,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異癌蚁,居然都是意外死亡幻梯,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門努释,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碘梢,“玉大人,你說我怎么就攤上這事伐蒂∩饭” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恩沛。 經(jīng)常有香客問我在扰,道長,這世上最難降的妖魔是什么雷客? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任芒珠,我火速辦了婚禮,結(jié)果婚禮上搅裙,老公的妹妹穿的比我還像新娘皱卓。我一直安慰自己,他們只是感情好部逮,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布娜汁。 她就那樣靜靜地躺著,像睡著了一般兄朋。 火紅的嫁衣襯著肌膚如雪掐禁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天颅和,我揣著相機與錄音傅事,去河邊找鬼。 笑死融虽,一個胖子當(dāng)著我的面吹牛享完,可吹牛的內(nèi)容都是我干的灼芭。 我是一名探鬼主播有额,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼彼绷!你這毒婦竟也來了巍佑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤寄悯,失蹤者是張志新(化名)和其女友劉穎萤衰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猜旬,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡脆栋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了洒擦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片椿争。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖熟嫩,靈堂內(nèi)的尸體忽然破棺而出秦踪,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布椅邓,位于F島的核電站柠逞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏景馁。R本人自食惡果不足惜板壮,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望裁僧。 院中可真熱鬧个束,春花似錦、人聲如沸聊疲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽获洲。三九已至阱表,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贡珊,已是汗流浹背最爬。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留门岔,地道東北人爱致。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像寒随,于是被迫代替她去往敵國和親糠悯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351

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