MyBatisPlus學(xué)習(xí)筆記

1. 簡介

官 網(wǎng):mybatisplus官網(wǎng)
視頻地址:b站狂神說MyBatisPlus最新完整教程通俗易懂

MyBatis-Plus(簡稱 MP)是一個(gè) MyBatis 的增強(qiáng)工具,在 MyBatis 的基礎(chǔ)上只做增強(qiáng)不做改變夭坪,為簡化開發(fā)御滩、提高效率而生抠蚣。

2. 特征

  • 無侵入:只做增強(qiáng)不做改變贿条,引入它不會對現(xiàn)有工程產(chǎn)生影響箍铲,如絲般順滑
  • 損耗小:啟動即會自動注入基本 CURD藻三,性能基本無損耗苗踪,直接面向?qū)ο蟛僮?/li>
  • 強(qiáng)大的 CRUD 操作:內(nèi)置通用 Mapper触机、通用 Service帚戳,僅僅通過少量配置即可實(shí)現(xiàn)單表大部分 CRUD 操作,更有強(qiáng)大的條件構(gòu)造器儡首,滿足各類使用需求
  • 支持 Lambda 形式調(diào)用:通過 Lambda 表達(dá)式片任,方便的編寫各類查詢條件,無需再擔(dān)心字段寫錯(cuò)
  • 支持主鍵自動生成:支持多達(dá) 4 種主鍵策略(內(nèi)含分布式唯一 ID 生成器 - Sequence)蔬胯,可自由配置对供,完美解決主鍵問題
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式調(diào)用,實(shí)體類只需繼承 Model 類即可進(jìn)行強(qiáng)大的 CRUD 操作
  • 支持自定義全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 內(nèi)置代碼生成器:采用代碼或者 Maven 插件可快速生成 Mapper 产场、 Model 鹅髓、 Service 确徙、 Controller 層代碼,支持模板引擎博烂,更有超多自定義配置等您來使用
  • 內(nèi)置分頁插件:基于 MyBatis 物理分頁躺率,開發(fā)者無需關(guān)心具體操作悼吱,配置好插件之后遇西,寫分頁等同于普通 List 查詢
  • 分頁插件支持多種數(shù)據(jù)庫:支持 MySQL、MariaDB哮塞、Oracle如失、DB2槽卫、H2震蒋、HSQL禾唁、SQLite瘦锹、Postgre椅挣、SQLServer 等多種數(shù)據(jù)庫
  • 內(nèi)置性能分析插件:可輸出 Sql 語句以及其執(zhí)行時(shí)間,建議開發(fā)測試時(shí)啟用該功能锈嫩,能快速揪出慢查詢
  • 內(nèi)置全局?jǐn)r截插件:提供全表 delete 受楼、 update 操作智能分析阻斷,也可自定義攔截規(guī)則呼寸,預(yù)防誤操作

3. 快速開始

3.1 依賴

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>

3.2 建表,創(chuàng)建springboot項(xiàng)目,連接數(shù)據(jù)庫

3.3 建立數(shù)據(jù)庫字段對應(yīng)實(shí)體類

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

3.4 mapper接口

繼承BaseMapper接口艳汽,里面有常用的數(shù)據(jù)庫操作方法

@Repository
public interface UserMapper extends BaseMapper<User> {

    //繼承了BaseMapper, 所有的方法都來自己父類
    //我們也可以編寫自己的擴(kuò)展方法
}

注意點(diǎn):需要在主啟動類MybatisPlusApplication上掃描我們Mapper包下的所有接口

@MapperScan("com.wang.mapper")

3.5 測試

 @Test
    void contextLoads() {

        //參數(shù)是一個(gè)Wrapper , 條件構(gòu)造器,這里我們先不用 --null
        List<User> list = userMapper.selectList(null);
        for (User user : list) {
            System.out.println(user);
        }
    }

4 配置日志

application.yml

# 日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

5 CRUD拓展

5.1 插入數(shù)據(jù)

@Test
    public void testInsert(){
        User user = new User(null,"xiaoman",21,"test6@163.com");
        userMapper.insert(user);
    }

幫我們自動生成id,插入的id默認(rèn)值為:全局的唯一id

在這里插入圖片描述

5.2 主鍵生成策略

全局唯一ID生成策略
Mybatis-plus 主鍵生成策略

默認(rèn) ID_WORKER 全局唯一id

snowflake是Twitter開源的分布式ID生成算法对雪,結(jié)果是一個(gè)long型的ID河狐。其核心思想是:使用41bit作為毫秒數(shù),10bit作為機(jī)器的ID(5個(gè)bit是數(shù)據(jù)中心(北京瑟捣,上海...)馋艺,5個(gè)bit的機(jī)器ID),12bit作為毫秒內(nèi)的流水號(意味著每個(gè)節(jié)點(diǎn)在每毫秒可以產(chǎn)生 4096 個(gè) ID)迈套,最后還有一個(gè)符號位捐祠,永遠(yuǎn)是0.可以保證幾乎全球唯一

修改主鍵生成策略
例如配置主鍵自增:

  1. 實(shí)體類id字段上加上@TableId(type = IdType.AUTO)
  2. 數(shù)據(jù)庫字段一定要是自增!


    在這里插入圖片描述

其余源碼解釋

public enum IdType {
    AUTO(0),     //自增
    NONE(1),    //未設(shè)置主鍵
    INPUT(2),   //手動輸入
    ID_WORKER(3),   //默認(rèn)全局唯一id
    UUID(4),        //全局唯一id uuid
    ID_WORKER_STR(5);   //ID_WORKER字符串表示

    private int key;

    private IdType(int key) {
        this.key = key;
    }

    public int getKey() {
        return this.key;
    }
}

5.3 更新操作

注意:updateById()參數(shù)是 一個(gè)對象!

    @Test
    public void testUpdate(){
        User user = new User(1358306497330683906L,"xiaoliu",20,"test7@163.com");
        userMapper.updateById(user);
    }

5.4 自動填充

創(chuàng)建時(shí)間 . 修改時(shí)間! 這些個(gè)操作都是自動化完成的,我們不希望手動更新!

阿里巴巴開發(fā)手冊:所有的數(shù)據(jù)庫表:gmt_create .gmt_modified幾乎所有的表都要配置上!而且需要自動化!

方式一: 數(shù)據(jù)庫級別(工作中不建議使用)

  1. 在表中新增字段 create_time , update_time


    在這里插入圖片描述
  2. 再次測試插入方法,我們需要先把實(shí)體類同步

注意:要導(dǎo)入util包下面的Data,不然會用lombok

 private Data creatTime;
 private Data updateTime;
  1. 測試

方式二: 代碼級別

  1. 刪除數(shù)據(jù)庫默認(rèn)值


    在這里插入圖片描述
  2. 實(shí)體類字段屬性上添加注解

    @TableField(fill = FieldFill.INSERT)
    private Data creatTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Data updateTime;
  1. 編寫處理器來處理這個(gè)注解
@Slf4j      //日志
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    //插入時(shí)的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill...");

        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    //更新時(shí)的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update  fill...");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

  1. 測試

5.5 樂觀鎖和悲觀鎖

樂觀鎖: 顧名思義十分樂觀,他總是認(rèn)為不會出現(xiàn)問題,無論干什么都不去上鎖!如果出現(xiàn)了問題,再次更新值測試
悲觀鎖;顧名思義十分悲觀,他總是認(rèn)為出現(xiàn)問題,無論干什么都會上鎖!再去操作!

當(dāng)要更新一條記錄的時(shí)候,希望這條記錄沒有被別人更新

樂觀鎖實(shí)現(xiàn)方式:

  • 取出記錄時(shí)桑李,獲取當(dāng)前version
  • 更新時(shí)踱蛀,帶上這個(gè)version
  • 執(zhí)行更新時(shí)窿给, set version = newVersion where version = oldVersion
  • 如果version不對,就更新失敗
在這里插入圖片描述

5.1.1 測試一下mybatis樂觀鎖插件

5.1.1.1 給數(shù)據(jù)表中加入version字段
在這里插入圖片描述
5.1.1.2 同步實(shí)體類
 @Version   //樂觀鎖version注解
 private Integer version;
5.1.1.3 注冊組件
/**
 * @program: mybatis_plus
 * @description: mybatisplus配置類
 * @author: Mr.Wang
 * @create: 2021-02-07 19:51
 **/

@Configuration  //配置類
@EnableTransactionManagement  //自動管理事務(wù)
public class MybatisPlusConfig {

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

5.1.1.4 測試樂觀鎖成功
    @Test
    public void testOptimisticLockerInterceptor01(){

        //查詢用戶信息
        User user = userMapper.selectById(1L);

        //更改用戶信息
        user.setName("zjr");
        user.setAge(20);
        user.setEmail("123456@163.com");

        //執(zhí)行修改
        userMapper.updateById(user);

    }
5.1.1.5 測試樂觀鎖失敗
 //測試樂觀鎖失敗
    @Test
    public void testOptimisticLockerInterceptor02(){
        //線程1
        User user = userMapper.selectById(1L);
        user.setName("lp");

        //模擬線程插隊(duì)
        User user1 = userMapper.selectById(1L);
        user1.setName("tsy");
        userMapper.updateById(user1);

        //如果沒有樂觀鎖就會覆蓋插隊(duì)線程的值
        userMapper.updateById(user);
    }

5.6 查詢操作

    //測試查詢
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }

    //測試批量查詢
    @Test
    public void testSelectBatchId(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(System.out::println);
    }

    //按條件查詢 之一使用map操作
    @Test
    public void testSelectByMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name","tsy");
        map.put("age","20");
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }

5.7 分頁查詢

5.7.1 配置攔截器組件

    //分頁插件
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }

5.7.2 測試分頁查詢

 //測試分頁查詢
    @Test
    public void testPage(){
        //參數(shù)1當(dāng)前頁率拒,參數(shù)2頁面大小
        Page<User> page = new Page<>(1,5);
        userMapper.selectPage(page,null);

        page.getRecords().forEach(System.out::println);
    }

5.8 邏輯刪除

普通刪除


在這里插入圖片描述

物理刪除:從數(shù)據(jù)庫中直接移除
邏輯刪除: 在數(shù)據(jù)庫中沒有被移除,而是通過一個(gè)變量來讓他失效! deleted=0=>deleted=1

管理員可以查看被刪除的記錄!防止數(shù)據(jù)的丟失,類似于回收站!

5.8.1 在數(shù)據(jù)表中增加deleted字段

在這里插入圖片描述

5.8.2 實(shí)體類中增加屬性

    @TableLogic
    private Integer deleted;

5.8.3 配置

    //注冊邏輯刪除組件
    @Bean
    public ISqlInjector sqlInjector(){
        return new LogicSqlInjector();
    }
# 配置邏輯刪除    
mybatis-plus:
  global-config:
    db-config:
      logic-not-delete-value: 0
      logic-delete-value: 1

5.9 性能分析插件

我們在平時(shí)的開發(fā)中,會遇到一些慢sql.

mybatis也提供了性能分析插件,如果超過這個(gè)時(shí)間就停止運(yùn)行!

5.9.1 導(dǎo)入插件

    @Bean
    @Profile({"dev","test"}) //設(shè)置dev 和 test環(huán)境開啟
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100);     //設(shè)置sql最大執(zhí)行時(shí)間崩泡,超過就不執(zhí)行
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }

設(shè)置開發(fā)環(huán)境

 profiles:
    active: dev

5.9.2 測試使用

5.10 條件構(gòu)造器Wrapper

我們寫一些復(fù)雜sql就可以用它代替

在這里插入圖片描述

@SpringBootTest
public class WrapperTest {

    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
        // 查詢name不為空的用戶,并且郵箱不為空的用戶猬膨,年齡大于等于20
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.
                isNotNull("name")
                .isNotNull("email")
                .ge("age",20);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

    @Test
    void test01(){
        //查詢名字等于xiaoman
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","xiaoman");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }

    @Test
    void test02(){
        //查詢年齡在21 - 25之間的用戶數(shù)量
        QueryWrapper<User> wrapper= new QueryWrapper<>();
        wrapper.between("age",21,25);
        Integer count = userMapper.selectCount(wrapper);
        System.out.println(count);
    }

    @Test
    void test03(){
        //模糊查詢:名字中不包含'l'并且包含'a'的
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper
                .notLike("name","l")
                .like("name","a");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);

    }

    @Test
    void test04(){
        //id在子查詢中查出來
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.inSql("id","select id from user where id < 3");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

    @Test
    void test05(){
        //通過age排序
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("age");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
}

5.11 代碼自動生成器

AutoGenerator 是 MyBatis-Plus 的代碼生成器允华,通過 AutoGenerator 可以快速生成 Entity、Mapper寥掐、Mapper XML靴寂、Service、Controller 等各個(gè)模塊的代碼召耘,極大的提升了開發(fā)效率百炬。
依賴

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

        <!--MyBatis-Plus 從 3.0.3 之后移除了代碼生成器與模板引擎的默認(rèn)依賴,需要手動添加相關(guān)依賴:-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>

        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>

代碼

package com.wang;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;

import java.util.ArrayList;

/**
 * @program: mybatis_plus
 * @description: 代碼自動生成器
 * @author: Mr.Wang
 * @create: 2021-02-08 11:34
 **/
public class WangCode {
    public static void main(String[] args) {
        //需要構(gòu)建一個(gè) 代碼自動生成器 對象
        // 代碼生成器
        AutoGenerator mpg = new AutoGenerator();
        //配置策略

        //1污它、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("xiaoman");
        gc.setOpen(false);      //是否打開windows文件夾
        gc.setFileOverride(false);  //是否覆蓋
        gc.setServiceName("%sService");  //去Service的I前綴
        gc.setIdType(IdType.ID_WORKER);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        //2剖踊、設(shè)置數(shù)據(jù)源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/db_mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("18170021");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        //3、包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("com.wang");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        //4衫贬、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user");    //設(shè)置要映射的表名,可包含多張表
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);    //自動lombok
        strategy.setLogicDeleteFieldName("deleted");   //邏輯刪除
        //自動填充配置
        TableFill createTime = new TableFill("create_time", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_time", FieldFill.UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(createTime);
        tableFills.add(updateTime);
        strategy.setTableFillList(tableFills);
        //樂觀鎖
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);     //localhost:8080/hello_id_2
        mpg.setStrategy(strategy);

        mpg.execute();  //執(zhí)行代碼構(gòu)造器
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末德澈,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子固惯,更是在濱河造成了極大的恐慌梆造,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葬毫,死亡現(xiàn)場離奇詭異镇辉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)贴捡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門忽肛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人烂斋,你說我怎么就攤上這事屹逛。” “怎么了汛骂?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵罕模,是天一觀的道長。 經(jīng)常有香客問我香缺,道長手销,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任图张,我火速辦了婚禮锋拖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祸轮。我一直安慰自己兽埃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布适袜。 她就那樣靜靜地躺著柄错,像睡著了一般。 火紅的嫁衣襯著肌膚如雪苦酱。 梳的紋絲不亂的頭發(fā)上售貌,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機(jī)與錄音疫萤,去河邊找鬼颂跨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扯饶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钓丰,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼每币,長吁一口氣:“原來是場噩夢啊……” “哼携丁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兰怠,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尚揣,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掖举,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡快骗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年塔次,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藕溅。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡继榆,死狀恐怖汁掠,靈堂內(nèi)的尸體忽然破棺而出集币,到底是詐尸還是另有隱情,我是刑警寧澤鞠苟,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布当娱,位于F島的核電站,受9級特大地震影響跨细,放射性物質(zhì)發(fā)生泄漏扼鞋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一捐友、第九天 我趴在偏房一處隱蔽的房頂上張望溃槐。 院中可真熱鬧,春花似錦昏滴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抚恒,卻和暖如春络拌,著一層夾襖步出監(jiān)牢的瞬間俘闯,已是汗流浹背居触。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瓮恭,地道東北人厘熟。 一個(gè)月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓绳姨,卻偏偏與公主長得像阔挠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子购撼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

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