MybatisPlus多表連接查詢

logo 圖片PPT底板16_9 2.001.png

一、序言

(一)背景內(nèi)容

軟件應(yīng)用技術(shù)架構(gòu)中DAO層最常見的選型組件為MyBatis埃篓,熟悉MyBatis的朋友都清楚察净,曾幾何時MyBatis是多么的風(fēng)光,使用XML文件解決了復(fù)雜的數(shù)據(jù)庫訪問的難題锅必。時至今日事格,曾經(jīng)的屠龍者終成惡龍,以XML文件為基礎(chǔ)的數(shù)據(jù)庫訪問技術(shù)變得臃腫搞隐、復(fù)雜驹愚,維護難度直線上升。

MybatisPlus對常見的數(shù)據(jù)庫訪問進行了封裝劣纲,訪問數(shù)據(jù)庫大大減少了XML文件的依賴逢捺,開發(fā)者從臃腫的XML文件中獲得了較大限度的解脫。

MybatisPlus官方并沒有提供多表連接查詢的通用解決方案味廊,然而連接查詢是相當普遍的需求蒸甜。解決連接查詢有兩種需求,一種是繼續(xù)使用MyBatis提供XML文件解決方式余佛;另一種本文提供的解決方案柠新。

事實上筆者強烈推薦徹底告別通過XML訪問數(shù)據(jù)庫,并不斷探索新式更加友好辉巡、更加自然的解決方式恨憎,現(xiàn)分享最新的MybatisPlus技術(shù)的研究成果。

image

(二)場景說明

為了說明連接查詢的關(guān)系,這里以學(xué)生憔恳、課程及其關(guān)系為示例瓤荔。

image

(三)前期準備

此部分需要讀者掌握以下內(nèi)容:Lambda 表達式、特別是方法引用钥组;函數(shù)式接口输硝;流式運算等等,否則理解起來會有些吃力程梦。

image

實體類與 Vo 的映射關(guān)系点把,作者創(chuàng)造性的引入特別構(gòu)造器,合理利用繼承關(guān)系屿附,極大的方便了開發(fā)者完成實體類向 Vo 的轉(zhuǎn)換郎逃。

空指針異常忽略不處理,借助Optional類實現(xiàn)挺份,詳情移步Java8 新特性查看褒翰。

二、一對一查詢

一對一查詢最典型的應(yīng)用場景是將id替換成name匀泊,比如將userId替換成userName优训。

(一)查詢單條記錄

查詢單條記錄是指返回值僅有一條記錄,通常是以唯一索引作為條件的返回查詢結(jié)果各聘。

1型宙、示例代碼
/**
 * 查詢單個學(xué)生信息(一個學(xué)生對應(yīng)一個部門)
 */
public UserVo getOneUser(Integer userId) {
    LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
        .eq(User::getUserId, userId);
    // 先查詢用戶信息
    User user = userMapper.selectOne(wrapper);
    // 轉(zhuǎn)化為Vo
    UserVo userVo = Optional.ofNullable(user).map(UserVo::new).orElse(null);
    // 從其它表查詢信息再封裝到Vo
    Optional.ofNullable(userVo).ifPresent(this::addDetpNameInfo);
    return userVo;
}

附屬表信息補充

/**
 * 補充部門名稱信息
 */
private void addDetpNameInfo(UserVo userVo) {
    LambdaQueryWrapper<Dept> wrapper = Wrappers.lambdaQuery(Dept.class)
        .eq(Dept::getDeptId, userVo.getDeptId());
    Dept dept = deptMapper.selectOne(wrapper);
    Optional.ofNullable(dept).ifPresent(e -> userVo.setDeptName(e.getDeptName()));
}
2、理論分析

查詢單個實體共分為兩個步驟:根據(jù)條件查詢主表數(shù)據(jù)(需處理空指針異常)伦吠;封裝 Vo 并查詢附屬表數(shù)據(jù)妆兑。

查詢結(jié)果(VO)只有一條記錄,需要查詢兩次數(shù)據(jù)庫毛仪,時間復(fù)雜度為O(1)搁嗓。

(二)查詢多條記錄

查詢多條記錄是指查詢結(jié)果為列表,通常是指以普通索引為條件的查詢結(jié)果箱靴。

1腺逛、示例代碼
/**
 * 批量查詢學(xué)生信息(一個學(xué)生對應(yīng)一個部門)
 */
public List<UserVo> getUserByList() {
    // 先查詢用戶信息(表現(xiàn)形式為列表)
    List<User> user = userMapper.selectList(Wrappers.emptyWrapper());
    List<UserVo> userVos = user.stream().map(UserVo::new).collect(toList());
    // 此步驟可以有多個
    addDeptNameInfo(userVos);
    return userVos;
}

附屬信息補充

private void addDeptNameInfo(List<UserVo> userVos) {
    // 提取用戶userId,方便批量查詢
    Set<Integer> deptIds = userVos.stream().map(User::getDeptId).collect(toSet());
    // 根據(jù)deptId查詢deptName(查詢前衡怀,先做非空判斷)
    List<Dept> dept = deptMapper.selectList(Wrappers.lambdaQuery(Dept.class).in(Dept::getDeptId, deptIds));
    // 構(gòu)造映射關(guān)系棍矛,方便匹配deptId與deptName
    Map<Integer, String> hashMap = dept.stream().collect(toMap(Dept::getDeptId, Dept::getDeptName));
    // 封裝Vo,并添加到集合中(關(guān)鍵內(nèi)容)
    userVos.forEach(e -> e.setDeptName(hashMap.get(e.getDeptId())));
}
2抛杨、理論分析

先查詢包含id的列表記錄够委,從結(jié)果集中析出id并轉(zhuǎn)化成批查詢語句再訪問數(shù)據(jù)庫,從第二次調(diào)用結(jié)果集中解析出name怖现。

查詢結(jié)果(VO)有多條記錄茁帽,但僅調(diào)用兩次數(shù)據(jù)庫玉罐,時間復(fù)雜度為O(1)

(三)查詢多條記錄(分頁)

分頁查詢實體的思路與查詢列表的思路相似潘拨,額外多處一步分頁泛型轉(zhuǎn)換吊输。

1、示例代碼
/**
 * 分頁查詢學(xué)生信息(一個學(xué)生對應(yīng)一個部門)
 */
public IPage<UserVo> getUserByPage(Page<User> page) {
    // 先查詢用戶信息
    IPage<User> xUserPage = userMapper.selectPage(page, Wrappers.emptyWrapper());
    // 初始化Vo
    IPage<UserVo> userVoPage = xUserPage.convert(UserVo::new);
    if (userVoPage.getRecords().size() > 0) {
        addDeptNameInfo(userVoPage);
    }
    return userVoPage;
}

查詢補充信息

private void addDeptNameInfo(IPage<UserVo> userVoPage) {
    // 提取用戶userId铁追,方便批量查詢
    Set<Integer> deptIds = userVoPage.getRecords().stream().map(User::getDeptId).collect(toSet());
    // 根據(jù)deptId查詢deptName
    List<Dept> dept = deptMapper.selectList(Wrappers.lambdaQuery(Dept.class).in(Dept::getDeptId, deptIds));
    // 構(gòu)造映射關(guān)系季蚂,方便匹配deptId與deptName
    Map<Integer, String> hashMap = dept.stream().collect(toMap(Dept::getDeptId, Dept::getDeptName));
    // 將查詢補充的信息添加到Vo中
    userVoPage.convert(e -> e.setDeptName(hashMap.get(e.getDeptId())));
}

IPage接口中convert方法,能夠?qū)崿F(xiàn)在原實例上修改琅束。

2癣蟋、理論分析

先查詢包含id的列表記錄,從結(jié)果集中析出id并轉(zhuǎn)化成批查詢語句再訪問數(shù)據(jù)庫狰闪,從第二次調(diào)用結(jié)果集中解析出name

查詢結(jié)果(VO)有多條記錄濒生,但僅調(diào)用兩次數(shù)據(jù)庫埋泵,時間復(fù)雜度為O(1)

三罪治、一對多查詢

一對多查詢最常見的場景是查詢部門所包含的學(xué)生信息丽声,由于一個部門對應(yīng)多個學(xué)生,每個學(xué)生對應(yīng)一個部門觉义,因此稱為一對多查詢雁社。

(一)查詢單條記錄

1、示例代碼
/**
 * 查詢單個部門(其中一個部門有多個用戶)
 */
public DeptVo getOneDept(Integer deptId) {
    // 查詢部門基礎(chǔ)信息
    LambdaQueryWrapper<Dept> wrapper = Wrappers.lambdaQuery(Dept.class).eq(Dept::getDeptId, deptId);
    DeptVo deptVo = Optional.ofNullable(deptMapper.selectOne(wrapper)).map(DeptVo::new).orElse(null);
    Optional.ofNullable(deptVo).ifPresent(this::addUserInfo);
    return deptVo;
}

補充附加信息

private void addUserInfo(DeptVo deptVo) {
    // 根據(jù)部門deptId查詢學(xué)生列表
    LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).eq(User::getDeptId, deptVo.getDeptId());
    List<User> users = userMapper.selectList(wrapper);
    deptVo.setUsers(users);
}
2晒骇、理論分析

整個過程共分為兩個階段:通過部門表中主鍵查詢指定部門信息霉撵,通過學(xué)生表中部門ID外鍵查詢學(xué)生信息,將結(jié)果合并洪囤,形成返回值(Vo)徒坡。

一對多查詢單條記錄整個過程至多需要調(diào)用2次數(shù)據(jù)庫查詢,查詢次數(shù)為常數(shù)瘤缩,查詢時間復(fù)雜度為O(1)喇完。

(二)查詢多條記錄

1、示例代碼
/**
 * 查詢多個部門(其中一個部門有多個用戶)
 */
public List<DeptVo> getDeptByList() {
    // 按條件查詢部門信息
    List<Dept> deptList = deptMapper.selectList(Wrappers.emptyWrapper());
    List<DeptVo> deptVos = deptList.stream().map(DeptVo::new).collect(toList());
    if (deptVos.size() > 0) {
        addUserInfo(deptVos);
    }
    return deptVos;
}

補充附加信息

private void addUserInfo(List<DeptVo> deptVos) {
    // 準備deptId方便批量查詢用戶信息
    Set<Integer> deptIds = deptVos.stream().map(Dept::getDeptId).collect(toSet());
    // 用批量deptId查詢用戶信息
    List<User> users = userMapper.selectList(Wrappers.lambdaQuery(User.class).in(User::getDeptId, deptIds));
    // 重點:將用戶按照deptId分組
    Map<Integer, List<User>> hashMap = users.stream().collect(groupingBy(User::getDeptId));
    // 合并結(jié)果剥啤,構(gòu)造Vo锦溪,添加集合列表
    deptVos.forEach(e -> e.setUsers(hashMap.get(e.getDeptId())));
}
2、理論分析

整個過程共分為三個階段:通過普通索引從部門表中查詢?nèi)舾蓷l記錄府怯;將部門ID轉(zhuǎn)化為批查詢從學(xué)生表中查詢學(xué)生記錄刻诊;將學(xué)生記錄以部門ID為單位進行分組,合并結(jié)果牺丙,轉(zhuǎn)化為Vo坏逢。

一對多查詢多條記錄需要調(diào)用2次數(shù)據(jù)庫查詢,查詢次數(shù)為常數(shù),查詢時間復(fù)雜度為O(1)是整。

(三)查詢多條記錄(分頁)

1肖揣、示例代碼
/**
 * 分頁查詢部門信息(其中一個部門有多個用戶)
 */
public IPage<DeptVo> getDeptByPage(Page<Dept> page) {
    // 按條件查詢部門信息
    IPage<Dept> xDeptPage = deptMapper.selectPage(page, Wrappers.emptyWrapper());
    IPage<DeptVo> deptVoPage = xDeptPage.convert(DeptVo::new);
    if (deptVoPage.getRecords().size() > 0) {
        addUserInfo(deptVoPage);
    }
    return deptVoPage;
}

查詢補充信息

private void addUserInfo(IPage<DeptVo> deptVoPage) {
    // 準備deptId方便批量查詢用戶信息
    Set<Integer> deptIds = deptVoPage.getRecords().stream().map(Dept::getDeptId).collect(toSet());
    LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).in(User::getDeptId, deptIds);
    // 用批量deptId查詢用戶信息
    List<User> users = userMapper.selectList(wrapper);
    // 重點:將用戶按照deptId分組
    Map<Integer, List<User>> hashMap = users.stream().collect(groupingBy(User::getDeptId));
    // 合并結(jié)果,構(gòu)造Vo浮入,添加集合列表
    deptVoPage.convert(e -> e.setUsers(hashMap.get(e.getDeptId())));
}
2龙优、理論分析

整個過程共分為三個階段:通過普通索引從部門表中查詢?nèi)舾蓷l記錄;將部門ID轉(zhuǎn)化為批查詢從學(xué)生表中查詢學(xué)生記錄事秀;將學(xué)生記錄以部門ID為單位進行分組彤断,合并結(jié)果,轉(zhuǎn)化為Vo易迹。

一對多查詢多條記錄需要調(diào)用2次數(shù)據(jù)庫查詢宰衙,查詢次數(shù)為常數(shù),查詢時間復(fù)雜度為O(1)睹欲。

四供炼、多對多查詢

MybatisPlus 實現(xiàn)多對多查詢是一件極富挑戰(zhàn)性的任務(wù),也是連接查詢中最困難的部分窘疮。

以空間置換時間袋哼,借助于流式運算,解決多對多查詢難題闸衫。

多對多查詢相對于一對多查詢涛贯,增加了流式分組運算、批量 HashMap 取值等內(nèi)容蔚出。

image

(一)查詢單條記錄

查詢單條記錄一般是指通過兩個查詢條件查詢出一條匹配表中的記錄弟翘。

1、示例代碼
public StudentVo getStudent(Integer stuId) {
    // 通過主鍵查詢學(xué)生信息
    StudentVo studentVo = ConvertUtils.convertObj(getById(stuId), StudentVo::new);
    LambdaQueryWrapper<StuSubRelation> wrapper = Wrappers.lambdaQuery(StuSubRelation.class).eq(StuSubRelation::getStuId, stuId);
    // 查詢匹配關(guān)系
    List<StuSubRelation> stuSubRelations = stuSubRelationMapper.selectList(wrapper);
    Set<Integer> subIds = stuSubRelations.stream().map(StuSubRelation::getSubId).collect(toSet());
    if (studentVo != null && subIds.size() > 0) {
        List<Subject> subList = subjectMapper.selectList(Wrappers.lambdaQuery(Subject.class).in(Subject::getId, subIds));
        List<SubjectBo> subBoList = ConvertUtils.convertList(subList, SubjectBo::new);
        HashBasedTable<Integer, Integer, Integer> table = getHashBasedTable(stuSubRelations);
        subBoList.forEach(e -> e.setScore(table.get(stuId, e.getId())));
        studentVo.setSubList(subBoList);
    }
    return studentVo;
}
2骄酗、理論分析

多對多單條記錄查詢最多訪問數(shù)據(jù)庫3次衅胀,先查詢學(xué)生信息,然后查詢學(xué)生與課程匹配信息酥筝,最后查詢課程分數(shù)信息滚躯,查詢時間復(fù)雜度為O(1)

(二)查詢多條記錄

1嘿歌、示例代碼
public List<StudentVo> getStudentList() {
    // 通過主鍵查詢學(xué)生信息
    List<StudentVo> studentVoList = ConvertUtils.convertList(list(), StudentVo::new);
    // 批量查詢學(xué)生ID
    Set<Integer> stuIds = studentVoList.stream().map(Student::getId).collect(toSet());
    LambdaQueryWrapper<StuSubRelation> wrapper = Wrappers.lambdaQuery(StuSubRelation.class).in(StuSubRelation::getStuId, stuIds);
    List<StuSubRelation> stuSubRelations = stuSubRelationMapper.selectList(wrapper);
    // 批量查詢課程ID
    Set<Integer> subIds = stuSubRelations.stream().map(StuSubRelation::getSubId).collect(toSet());
    if (stuIds.size() > 0 && subIds.size() > 0) {
        HashBasedTable<Integer, Integer, Integer> table = getHashBasedTable(stuSubRelations);
        List<Subject> subList = subjectMapper.selectList(Wrappers.lambdaQuery(Subject.class).in(Subject::getId, subIds));
        List<SubjectBo> subjectBoList = ConvertUtils.convertList(subList, SubjectBo::new);
        Map<Integer, List<Integer>> map = stuSubRelations.stream().collect(groupingBy(StuSubRelation::getStuId, mapping(StuSubRelation::getSubId, toList())));
        for (StudentVo studentVo : studentVoList) {
            // 獲取課程列表
            List<SubjectBo> list = ListUtils.select(subjectBoList, e -> emptyIfNull(map.get(studentVo.getId())).contains(e.getId()));
            // 填充分數(shù)
            list.forEach(e -> e.setScore(table.get(studentVo.getId(), e.getId())));
            studentVo.setSubList(list);
        }
    }
    return studentVoList;
}
2掸掏、理論分析

多對多N條記錄查詢由于使用了批查詢,因此最多訪問數(shù)據(jù)庫也是3次宙帝,先查詢學(xué)生信息丧凤,然后查詢學(xué)生與課程匹配信息,最后查詢課程分數(shù)信息步脓,查詢時間復(fù)雜度為O(1)愿待。

(三)查詢多條記錄(分頁)

1浩螺、示例代碼
public IPage<StudentVo> getStudentPage(IPage<Student> page) {
    // 通過主鍵查詢學(xué)生信息
    IPage<StudentVo> studentVoPage = ConvertUtils.convertPage(page(page), StudentVo::new);
    // 批量查詢學(xué)生ID
    Set<Integer> stuIds = studentVoPage.getRecords().stream().map(Student::getId).collect(toSet());
    LambdaQueryWrapper<StuSubRelation> wrapper = Wrappers.lambdaQuery(StuSubRelation.class).in(StuSubRelation::getStuId, stuIds);
    // 通過學(xué)生ID查詢課程分數(shù)
    List<StuSubRelation> stuSubRelations = stuSubRelationMapper.selectList(wrapper);
    // 批量查詢課程ID
    Set<Integer> subIds = stuSubRelations.stream().map(StuSubRelation::getSubId).collect(toSet());
    if (stuIds.size() > 0 && subIds.size() > 0) {
        HashBasedTable<Integer, Integer, Integer> table = getHashBasedTable(stuSubRelations);
        // 學(xué)生ID查詢課程ID組
        Map<Integer, List<Integer>> map = stuSubRelations.stream().collect(groupingBy(StuSubRelation::getStuId, mapping(StuSubRelation::getSubId, toList())));

        List<Subject> subList = subjectMapper.selectList(Wrappers.lambdaQuery(Subject.class).in(Subject::getId, subIds));
        List<SubjectBo> subBoList = ConvertUtils.convertList(subList, SubjectBo::new);
        for (StudentVo studentVo : studentVoPage.getRecords()) {
            List<SubjectBo> list = ListUtils.select(subBoList, e -> emptyIfNull(map.get(studentVo.getId())).contains(e.getId()));
            list.forEach(e -> e.setScore(table.get(studentVo.getId(), e.getId())));
            studentVo.setSubList(list);
        }
    }
    return studentVoPage;
}
2、理論分析

多對多N條記錄分頁查詢由于使用了批查詢仍侥,因此最多訪問數(shù)據(jù)庫也是3次要出,先查詢學(xué)生信息,然后查詢學(xué)生與課程匹配信息农渊,最后查詢課程分數(shù)信息患蹂,查詢時間復(fù)雜度為O(1)

五砸紊、總結(jié)與拓展

(一)總結(jié)

通過上述分析传于,能夠用 MybatisPlus 解決多表連接查詢中的一對一一對多醉顽、多對多查詢沼溜。

  • 上述代碼行文緊湊,充分利用 IDE 對 Lambda 表達式的支持游添,在編譯期間完成對代碼的檢查系草。
  • 業(yè)務(wù)邏輯清晰,可維護性否淤、可修改性優(yōu)勢明顯。
  • 一次查詢需要訪問至多兩次數(shù)據(jù)庫棠隐,時間復(fù)雜度為o(1)石抡,主鍵查詢或者索引查詢,查詢效率高助泽。

(二)拓展

MybatisPlus能很好的解決單表查詢問題啰扛,同時借助在單表查詢的封裝能很好地解決連接查詢問題。

本方案不僅解決了連接查詢問題嗡贺,同時具備如下內(nèi)容拓展:

  • 當數(shù)據(jù)量較大時隐解,仍然具有穩(wěn)定的查詢效率

當數(shù)據(jù)量達到百萬級別時,傳統(tǒng)的單表通過索引查詢已經(jīng)面臨挑戰(zhàn)诫睬,普通的多表連接查詢性能隨著數(shù)據(jù)量的遞增呈現(xiàn)指數(shù)級下降煞茫。

本方案通過將連接查詢轉(zhuǎn)化為主鍵(索引)查詢,查詢性能等效于單表查詢摄凡。

  • 與二級緩存配合使用進一步提高查詢效率

當所有的查詢均轉(zhuǎn)化為以單表為基礎(chǔ)的查詢后续徽,方能安全的引入二級緩存。二級緩存的單表增刪改查操作自適應(yīng)聯(lián)動亲澡,解決了二級緩存的臟數(shù)據(jù)問題钦扭。


喜歡本文點個??贊??支持一下,如有需要床绪,可通過微信dream4s與我聯(lián)系客情。相關(guān)源碼在GitHub其弊,視頻講解在B站,本文收藏在博客天地膀斋。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末梭伐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子概页,更是在濱河造成了極大的恐慌籽御,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惰匙,死亡現(xiàn)場離奇詭異技掏,居然都是意外死亡,警方通過查閱死者的電腦和手機项鬼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門哑梳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绘盟,你說我怎么就攤上這事鸠真。” “怎么了龄毡?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵吠卷,是天一觀的道長。 經(jīng)常有香客問我沦零,道長祭隔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任路操,我火速辦了婚禮疾渴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屯仗。我一直安慰自己搞坝,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布魁袜。 她就那樣靜靜地躺著桩撮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪峰弹。 梳的紋絲不亂的頭發(fā)上距境,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音垮卓,去河邊找鬼垫桂。 笑死,一個胖子當著我的面吹牛粟按,可吹牛的內(nèi)容都是我干的诬滩。 我是一名探鬼主播霹粥,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼疼鸟!你這毒婦竟也來了后控?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤空镜,失蹤者是張志新(化名)和其女友劉穎浩淘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吴攒,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡张抄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了洼怔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片署惯。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖镣隶,靈堂內(nèi)的尸體忽然破棺而出极谊,到底是詐尸還是另有隱情,我是刑警寧澤安岂,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布轻猖,位于F島的核電站,受9級特大地震影響域那,放射性物質(zhì)發(fā)生泄漏咙边。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一琉雳、第九天 我趴在偏房一處隱蔽的房頂上張望样眠。 院中可真熱鬧友瘤,春花似錦翠肘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盟戏,卻和暖如春绪妹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柿究。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工邮旷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蝇摸。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓婶肩,卻偏偏與公主長得像办陷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子律歼,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

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