2, mybatisPlus學(xué)習(xí)

來源于螞蟻課堂
1.Mybatis-plus與mybatis區(qū)別
2.BaseMapper接口實現(xiàn)快速增刪改查
3.實現(xiàn)復(fù)雜的QueryWrapper條件構(gòu)造器
4.mybatis-plus實現(xiàn)邏輯刪除
5.mybatis-plus整合分頁插件
6.mybatis-plus代碼自動生成器
7.mybatis-plus動態(tài)切換數(shù)據(jù)源
8.mybatis-plus生成全局的主鍵id
9.mybatis-plus樂觀鎖的機制

mybatisPlus介紹
MyBatis-Plus(簡稱 MP)是一個 MyBatis 的增強工具泵喘,在 MyBatis 的基礎(chǔ)上只做增強不做改變墩瞳,為簡化開發(fā)、提高效率而生,和hibernate怎静、jpa注解方式非常相似。

mybatisPlus特性
無侵入:只做增強不做改變,引入它不會對現(xiàn)有工程產(chǎn)生影響,如絲般順滑
損耗屑尉埂:啟動即會自動注入基本 CURD,性能基本無損耗洋侨,直接面向?qū)ο蟛僮?br> 強大的 CRUD 操作:內(nèi)置通用 Mapper舍扰、通用 Service,僅僅通過少量配置即可實現(xiàn)單表大部分 CRUD 操作希坚,更有強大的條件構(gòu)造器边苹,滿足各類使用需求
支持 Lambda 形式調(diào)用:通過 Lambda 表達(dá)式,方便的編寫各類查詢條件吏够,無需再擔(dān)心字段寫錯
支持主鍵自動生成:支持多達(dá) 4 種主鍵策略(內(nèi)含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題
支持 ActiveRecord 模式:支持 ActiveRecord 形式調(diào)用锅知,實體類只需繼承 Model 類即可進(jìn)行強大的 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í)行時間,建議開發(fā)測試時啟用該功能蒲讯,能快速揪出慢查詢
內(nèi)置全局?jǐn)r截插件:提供全表 delete 忘朝、 update 操作智能分析阻斷,也可自定義攔截規(guī)則判帮,預(yù)防誤操作

支持?jǐn)?shù)據(jù)庫
mysql 局嘁、 mariadb 、 oracle 脊另、 db2 导狡、 h2 、 hsql 偎痛、 sqlite 旱捧、 postgresql 、 sqlserver
達(dá)夢數(shù)據(jù)庫 踩麦、 虛谷數(shù)據(jù)庫 枚赡、 人大金倉數(shù)據(jù)庫

image.png

SpringBoot整合mybatisPlus
初始化表結(jié)構(gòu)

CREATE TABLE `meite_user` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) DEFAULT NULL,
  `user_age` int(10) DEFAULT NULL,
  `user_addres` varchar(255) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `deleted` int(1) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of meite_user
-- ----------------------------
INSERT INTO `meite_user` VALUES ('27', 'zhangsan', '18', '湖北省武漢市', '2020-05-27 15:45:44', '0');
INSERT INTO `meite_user` VALUES ('29', 'yushengjun', '22', '湖北省孝感市', '2020-06-25 15:45:48', '0');
INSERT INTO `meite_user` VALUES ('30', '1', '19', '上海市', '2020-04-22 15:45:52', '1');




Maven依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.taotao</groupId>
    <artifactId>mybatis-plus1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mybatis-plus1</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>







實體:

package com.taotao.mybatisplus1.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * <p>
 *
 * </p>
 *
 * @author jobob
 * @since 2020-06-09
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class MeiteUser implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "user_id", type = IdType.AUTO)
    private Integer userId;

    private String userName;

    private Integer userAge;

    private String userAddres;

    private LocalDateTime createTime;

    /**
     * 邏輯刪除
     * 0存在 1 隱藏
     */
    @TableLogic
    private Integer deleted = 0;
    // 版本
    @Version
    private Integer version;

}

mapper:

package com.taotao.mybatisplus1.mapper;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.taotao.mybatisplus1.entity.MeiteUser;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author jobob
 * @since 2020-06-09
 */
public interface MeiteUserMapper extends BaseMapper<MeiteUser> {

}





啟動類:

package com.taotao.mybatisplus1;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.taotao.mybatisplus1.mapper")
@SpringBootApplication
public class MybatisPlus1Application {

    public static void main(String[] args) {
        SpringApplication.run(MybatisPlus1Application.class, args);
    }

}


service:


package com.taotao.mybatisplus1.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.taotao.mybatisplus1.entity.MeiteUser;
import com.taotao.mybatisplus1.mapper.MeiteUserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * <p>
 *  服務(wù)實現(xiàn)類
 * </p>
 *
 * @author jobob
 * @since 2020-06-09
 */
@RestController
public class MeiteUserServiceImpl {

    @Autowired
    public MeiteUserMapper meiteUserMapper;


    /**
     * 根據(jù)id查詢數(shù)據(jù)
     * @param userId
     * @return
     */
    @GetMapping("/findByUser")
    public MeiteUser findByUser(Integer userId) {
        MeiteUser meiteUser = meiteUserMapper.selectById(userId);
        return meiteUser;
    }

    /**
     * 插入數(shù)據(jù)
     * @param user
     * @return
     */
    @GetMapping("/insertUser")
    public String insertUser(MeiteUser user) {
        String result = meiteUserMapper.insert(user) > 0 ? "success" : "fail";
        return result;
    }

    @GetMapping("/queryWrapper")
    public List<MeiteUser> userList(MeiteUser user) {

        QueryWrapper<MeiteUser> queryWrapper = new QueryWrapper<MeiteUser>();
        String userName = user.getUserName();
        //等于
      /*  if (!StringUtils.isEmpty(userName)) {
            queryWrapper.eq("user_name", user.getUserName());
        }*/
        queryWrapper.eq(!StringUtils.isEmpty(user.getUserName()), "user_name", user.getUserName());
        //大于
        queryWrapper.gt(user.getUserAge() != null, "user_age", user.getUserAge());
        //between
        queryWrapper.between("user_age", 1, 34);
        //like
        queryWrapper.like(!StringUtils.isEmpty(user.getUserAddres()), "user_addres", user.getUserAddres());
        //in
        //orderbyDesc
        queryWrapper.orderByDesc("create_time");
        queryWrapper.orderByDesc("user_age");
        List<MeiteUser> userList = meiteUserMapper.selectList(queryWrapper);
        return userList;
    }

    /**
     * 多條件修改
     * @param user
     * @return
     */
    @GetMapping("/updateUserWrapper")
    public String updateUserWrapper(MeiteUser user) {
        UpdateWrapper<MeiteUser> userUpdateWrapper = new UpdateWrapper<>();

        Integer userAge = user.getUserAge();
        if (userAge != null) {
            userUpdateWrapper.eq("user_age", userAge);
        }
        return meiteUserMapper.update(user, userUpdateWrapper) > 0 ? "success" : "fail";
    }

    /**
     * 邏輯刪除
     * @param userId
     * @return
     */

    @GetMapping("/deleteById")
    public String deleteById(Integer userId) {
        return meiteUserMapper.deleteById(userId) > 0 ? "success" : "fail";
    }

    @GetMapping("/findByPageUserList")
    public List<MeiteUser> findByPageUserList(Page page) {
        QueryWrapper<MeiteUser> userQueryWrapper = new QueryWrapper<>();
        Page<MeiteUser> pageResult = meiteUserMapper.selectPage(page, userQueryWrapper);
        return pageResult.getRecords();

    }
}


條件構(gòu)造器
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父類
用于生成 sql 的 where 條件, entity 屬性也用于生成 sql 的 where 條件
注意: entity 生成的 where 條件與 使用各個 api 生成的 where 條件沒有任何關(guān)聯(lián)行為、
等于查詢

分頁插件

package com.taotao.mybatisplus1.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 *@author tom
 *Date  2020/6/16 0016 22:44
 *分頁插件組合
 */
@EnableTransactionManagement
@Configuration
@MapperScan("com.taotao.mybatisplus1.mapper")
public class MybatisPlusConfig {
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        PaginationInterceptor paginationInterceptor=new PaginationInterceptor();
        //設(shè)置請求的頁面大于最大頁后操作,true調(diào)回到首頁,false 繼續(xù)請求
        paginationInterceptor.setOverflow(false);
        //設(shè)置最大頁限制數(shù)量谓谦。默認(rèn)為500條,-1 不限制
        paginationInterceptor.setLimit(10);
        //開啟count d join 優(yōu)化只針對部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return  paginationInterceptor;
    }


    /**
     * 整合樂觀鎖插件 改寫我們的sql語句 加上版本號碼
     * @return
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

自定義主鍵id

package com.taotao.mybatisplus1.config;

import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import org.springframework.stereotype.Component;

/**
 *@author tom
 *Date  2020/6/17 0017 8:25
 *自定義分布式主鍵id
 */
@Component
public class CustomIdGenerator  implements IdentifierGenerator {

    @Override
    public Long  nextId(Object entity) {
        return 60L;
    }
}

實體類主鍵id改為自定義形式

@Data
@EqualsAndHashCode(callSuper = false)
public class MeiteUser implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "user_id", type = IdType.ASSIGN_ID)
    private Integer userId;

雪花算法:

package com.taotao.mybatisplus1.utils;

import org.springframework.stereotype.Component;

@Component
public class SnowflakeIdUtils {
    // ==============================Fields===========================================
    /**
     * 開始時間截 (2015-01-01)
     */
    private final long twepoch = 1420041600000L;

    /**
     * 機器id所占的位數(shù)
     */
    private final long workerIdBits = 5L;

    /**
     * 數(shù)據(jù)標(biāo)識id所占的位數(shù)
     */
    private final long datacenterIdBits = 5L;

    /**
     * 支持的最大機器id贫橙,結(jié)果是31 (這個移位算法可以很快的計算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù))
     */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

    /**
     * 支持的最大數(shù)據(jù)標(biāo)識id,結(jié)果是31
     */
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

    /**
     * 序列在id中占的位數(shù)
     */
    private final long sequenceBits = 12L;

    /**
     * 機器ID向左移12位
     */
    private final long workerIdShift = sequenceBits;

    /**
     * 數(shù)據(jù)標(biāo)識id向左移17位(12+5)
     */
    private final long datacenterIdShift = sequenceBits + workerIdBits;

    /**
     * 時間截向左移22位(5+5+12)
     */
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    /**
     * 生成序列的掩碼反粥,這里為4095 (0b111111111111=0xfff=4095)
     */
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    /**
     * 工作機器ID(0~31)
     */
    private long workerId;

    /**
     * 數(shù)據(jù)中心ID(0~31)
     */
    private long datacenterId;

    /**
     * 毫秒內(nèi)序列(0~4095)
     */
    private long sequence = 0L;

    /**
     * 上次生成ID的時間截
     */
    private long lastTimestamp = -1L;

    //==============================Constructors=====================================
    public SnowflakeIdUtils() {
        this.workerId = 3;
        this.datacenterId = 1;
    }

    /**
     * 構(gòu)造函數(shù)
     *
     * @param workerId     工作ID (0~31)
     * @param datacenterId 數(shù)據(jù)中心ID (0~31)
     */
    public SnowflakeIdUtils(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    // ==============================Methods==========================================

    /**
     * 獲得下一個ID (該方法是線程安全的)
     *
     * @return SnowflakeId
     */
    public synchronized long nextId() {
        long timestamp = timeGen();

        //如果當(dāng)前時間小于上一次ID生成的時間戳卢肃,說明系統(tǒng)時鐘回退過這個時候應(yīng)當(dāng)拋出異常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        //如果是同一時間生成的疲迂,則進(jìn)行毫秒內(nèi)序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            //毫秒內(nèi)序列溢出
            if (sequence == 0) {
                //阻塞到下一個毫秒,獲得新的時間戳
                timestamp = tilNextMillis(lastTimestamp);
            }
        }
        //時間戳改變,毫秒內(nèi)序列重置
        else {
            sequence = 0L;
        }

        //上次生成ID的時間截
        lastTimestamp = timestamp;

        //移位并通過或運算拼到一起組成64位的ID
        return ((timestamp - twepoch) << timestampLeftShift) //
                | (datacenterId << datacenterIdShift) //
                | (workerId << workerIdShift) //
                | sequence;
    }

    /**
     * 阻塞到下一個毫秒莫湘,直到獲得新的時間戳
     *
     * @param lastTimestamp 上次生成ID的時間截
     * @return 當(dāng)前時間戳
     */
    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    /**
     * 返回以毫秒為單位的當(dāng)前時間
     *
     * @return 當(dāng)前時間(毫秒)
     */
    protected long timeGen() {
        return System.currentTimeMillis();
    }

    //==============================Test=============================================

    /**
     * 測試
     */
    public static void main(String[] args) {
        SnowflakeIdUtils idWorker = new SnowflakeIdUtils(3, 1);
        System.out.println(idWorker.nextId());
    }
}




優(yōu)化自增id 配置:

package com.taotao.mybatisplus1.config;

import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.taotao.mybatisplus1.utils.SnowflakeIdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 *@author tom
 *Date  2020/6/17 0017 8:25
 *自定義分布式主鍵id
 */
@Component
public class CustomIdGenerator  implements IdentifierGenerator {
@Autowired
private SnowflakeIdUtils snowflakeIdUtils;
    @Override
    public Long  nextId(Object entity) {
        return snowflakeIdUtils.nextId();
    }
}





image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末尤蒿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子幅垮,更是在濱河造成了極大的恐慌腰池,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忙芒,死亡現(xiàn)場離奇詭異示弓,居然都是意外死亡,警方通過查閱死者的電腦和手機呵萨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門奏属,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人甘桑,你說我怎么就攤上這事拍皮。” “怎么了跑杭?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵铆帽,是天一觀的道長。 經(jīng)常有香客問我德谅,道長爹橱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任窄做,我火速辦了婚禮愧驱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘椭盏。我一直安慰自己组砚,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布掏颊。 她就那樣靜靜地躺著糟红,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乌叶。 梳的紋絲不亂的頭發(fā)上盆偿,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音准浴,去河邊找鬼事扭。 笑死,一個胖子當(dāng)著我的面吹牛乐横,可吹牛的內(nèi)容都是我干的求橄。 我是一名探鬼主播今野,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼罐农!你這毒婦竟也來了腥泥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤啃匿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蛆楞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溯乒,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年豹爹,在試婚紗的時候發(fā)現(xiàn)自己被綠了裆悄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡臂聋,死狀恐怖光稼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情孩等,我是刑警寧澤艾君,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站肄方,受9級特大地震影響冰垄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜权她,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一虹茶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧隅要,春花似錦蝴罪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尼啡,卻和暖如春暂衡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背崖瞭。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工狂巢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人书聚。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓唧领,卻偏偏與公主長得像藻雌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子斩个,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349