MyBatisPlus使用

一、MP 是什么

MP 全称 Mybatis-Plus ,套用官方的解释便是成为 MyBatis 最好的搭档,简称基友。它是在MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

1. 三大特性

1)润物无声

只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。

2)效率至上

只需简单配置,即可快速进行单表 CRUD 操作,从而节省大量时间。

3)丰富功能

代码生成、物理分页、性能分析等功能一应俱全。

2. 支持数据库

mysql 、mariadb 、oracle 、db2 、h2 、hsql 、sqlite 、postgresql 、sqlserverpresto 、Gauss 、Firebird

Phoenix 、clickhouse 、Sybase ASE 、 OceanBase 、达梦数据库 、虚谷数据库 、人大金仓数据库 、南大通用数据库

3. 框架结构

pom 依赖


配置文件



实体类


Mapper


测试类


2.  CRUD 基操

1)insert

@Test

publicvoidinsert(){

//这里使用了 lombok 中的建造者模式构建对象

User user = User.builder().deptId(1).name("小华").remark("小华爱学习").build();

intinsertFlag = userMapper.insert(user);

log.info("插入影响行数,{} | 小华的ID: {}", insertFlag, user.getId());

}

/** OUTPUT:

插入影响行数,1 | 小华的ID: 8

**/

可以看到我们不仅插入了数据,而且还获取到了插入数据的ID,但是值得注意的是这里的ID 虽然是自增的,但并非是 MP 默认的 ID生成策略,而是我们在实体类中指定的:

在 MP 中支持的主键生成策略有以下几种:

我们既然已经看到了 @TableId 这个注解,那我们再来关注一个常用注解 @TableField

从注解名上我们就可以看出,@TableId 是用来标记主键 ID 的,而 @TableField 是用来标记其他字段的。

可以看得出来这个注解中存在的值还是比较多的,下面介绍几个常用的值:

value

用于解决字段名不一致问题和驼峰命名,比如实体类中属性名为 remark,但是表中的字段名为 describe ,这个时候就可以使用 @TableField(value="describe") 来进行转换。驼峰转换如果在全局中有配置驼峰命名,这个地方可不写。

exist

用于在数据表中不存在的字段,我们可以使用 @TableField(exist = false) 来进行标记

condition

用在预处理 WHERE 实体条件自定义运算规则,比如我配置了 @TableField(condition = SqlCondition.LIKE),输出 SQL 为:select 表 where name LIKE CONCAT('%',值,'%'),其中 SqlCondition 值如下:

update

用在预处理 set 字段自定义注入,比如我配置了 @TableField(update = "%s+1"),其中%s 会填充字段,输出 SQL 为:update 表名 set 字段 = 字段+1 where 条件

select

用于是否查询时约束,如果我们有个字段 remark 是 text 类型的,查询的时候不想查询该字段,那么就可以使用 @TableField(select = false) 来约束查询的时候不查询该字段

2)update

MybatisPlus 的更新操作存在两种:

intupdateById(Param("et")T entity);

intupdate(@Param("et")T entity, @Param("ew")Wrapper updateWrapper);

根据 ID 更新

@Test

publicvoidupdate(){

User user = User.builder().id(3).name("小华").remark("小华爱玩游戏").build();

userMapper.updateById(user);

}

/** 更新结果:

User(id=3, deptId=1, name=小华, remark=小华爱玩游戏)

**/

根据条件更新

@Test

publicvoidupdate(){

UpdateWrapper updateWrapper =newUpdateWrapper<>();

updateWrapper.eq("name","小华").set("remark","小华爱下棋");

userMapper.update(null, updateWrapper);

}

/** 更新结果:

User(id=3, deptId=1, name=小华, remark=小华爱下棋)

**/

我们也可以将要更新的条件放进 user 对象 里面:

@Test

publicvoidupdate(){

UpdateWrapper updateWrapper =newUpdateWrapper<>();

updateWrapper.eq("name","小华");

User user = User.builder().remark("小华爱游泳").build();

userMapper.update(user, updateWrapper);

}

/** 更新结果:

User(id=3, deptId=1, name=小华, remark=小华爱游泳)

**/

3)delete

在 MybatisPlus 中删除的方式相对于更新多,总共有四种:

intdeleteById(Serializable id);

intdeleteByMap(@Param("cm")Map columnMap);

intdelete(@Param("ew")Wrapper wrapper);

intdeleteBatchIds(@Param("coll")Collection idList);

根据 ID 删除

@Test

publicvoiddeleteById(){

userMapper.deleteById(3);

}

/** SQL语句:

DELETE FROM student WHERE id = 3;

**/

根据 Map 删除

@Test

publicvoiddeleteByMap(){

HashMap columnMap =newHashMap<>();

columnMap.put("name","小华");

columnMap.put("remark","小华爱游泳");

userMapper.deleteByMap(columnMap);

}

/** SQL语句:

DELETE FROM student WHRE name = '小华' AND remark = '小华爱游泳';

**/

根据 Wrapper 删除

@Test

publicvoiddelete(){

UpdateWrapper wrapper =newUpdateWrapper<>();

wrapper.eq("remark","小华爱下棋");

userMapper.delete(wrapper);

}

/** SQL语句:

DELETE FROM student WHRE remark = '小华爱下棋';

**/

根据 Wrapper 删除还有另外一种方式,直接将实体类放入 Wrapper 中包装:

@Test

publicvoiddelete(){

User user = User.builder().remark("小华爱下棋").build();

UpdateWrapper wrapper =newUpdateWrapper<>(user);

userMapper.delete(wrapper);

}

/** SQL语句:

DELETE FROM student WHRE remark = '小华爱下棋';

**/

根据 ID 批量删除

@Test

publicvoiddeleteBatchIds(){

List idList =newArrayList<>();

idList.add(4);

idList.add(7);

userMapper.deleteBatchIds(idList);

}

/** SQL语句:

DELETE FROM student WHERE id In (4,7)

**/

4)select

查询操作在我们开发中是最经常用到的,也是重中之重。MybatisPlus 中支持查询的方法也比较多,如下:

TselectById(Serializable id);

ListselectBatchIds(@Param("coll")Collection idList);

ListselectByMap(@Param("cm")Map columnMap);

TselectOne(@Param("ew")Wrapper queryWrapper);

IntegerselectCount(@Param("ew")Wrapper queryWrapper);

ListselectList(@Param("ew")Wrapper queryWrapper);

List> selectMaps(@Param("ew") Wrapper queryWrapper);

ListselectObjs(@aram("ew")Wrapper queryWrapper);

IPageselectPage(IPage page, @Param("ew")Wrapper queryWrapper);

IPage> selectMapsPage(IPage page,@Param("ew") Wrapper queryWrapper);

可以看到总共有 10 个方法,我们接下来一个一个测试

查询所有

@Test

publicvoidselectList(){

List users = userMapper.selectList(null);

users.forEach(System.out::println);

}

/**

OUTPUT:

User(id=1, deptId=1, name=小菜, remark=关注小菜不迷路!)

User(id=2, deptId=1, name=小明, remark=好好学习,天天向上!)

SQL语句:

SELECT id, dept_id, name, remark FROM student;

**/

查询数量

@Test

publicvoidselectCount(){

QueryWrapper queryWrapper =newQueryWrapper<>();

queryWrapper.like("name","小");

System.out.println(userMapper.selectCount(queryWrapper));

}

/**

OUTPUT:

2

SQL语句:

SELECT COUNT( 1 ) FROM student WHERE (name LIKE '%小%');

**/

根据 ID 查询

@Test

publicvoidselectById(){

User user = userMapper.selectById(1);

System.out.println(user);

}

/**

OUTPUT:

User(id=1, deptId=1, name=小菜, remark=关注小菜不迷路!)

SQL语句:

SELECT id, dept_id, name, remark FROM student WHERE ID = 1;

**/

根据 ID 批量查询

@Test

publicvoidselectBatchIds(){

List users = userMapper.selectBatchIds(Arrays.asList(1,2));

users.forEach(System.out::println);

}

/**

OUTPUT:

User(id=1, deptId=1, name=小菜, remark=关注小菜不迷路!)

User(id=2, deptId=1, name=小明, remark=好好学习,天天向上!)

SQL语句:

SELECT id, dept_id, name, remark FROM student WHERE ID IN (1, 2);

**/

根据条件查询单条

@Test

publicvoidselectOne(){

QueryWrapper queryWrapper =newQueryWrapper<>();

queryWrapper.eq("name","小菜");

User user = userMapper.selectOne(queryWrapper);

System.out.println(user);

}

/**

OUTPUT:

User(id=1, deptId=1, name=小菜, remark=关注小菜不迷路!)

SQL语句:

SELECT id, name, dept_id, remark FROM student WHERE (name = '小菜');

**/

根据条件查询多条

通过 map 传递参数,不是通过 LIKE 查询,而是通过 = 查询

@Test

publicvoidselectByMap(){

HashMap columnMap =newHashMap<>();

columnMap.put("name","小");

List users = userMapper.selectByMap(columnMap);

users.forEach(System.out::println);

}

/**

OUTPUT:

null

SQL语句:

SELECT id, name, dept_id, remark FROM student WHERE name = '小';

**/

如果我们没有新建实体类进行结果封装,我们还可以用 Map 来接收结果集:

@Test

publicvoidselectMaps(){

QueryWrapper queryWrapper =newQueryWrapper<>();

queryWrapper.like("name","小");

List> maps = userMapper.selectMaps(queryWrapper);

maps.forEach(System.out::println);

}

/**

OUTPUT:

{name=小菜, remark=关注小菜不迷路!, id=1, dept_id=1}

{name=小明, remark=好好学习,天天向上!, id=2, dept_id=1}

SQL语句:

SELECT id, name, dept_id, remark FROM student WHERE (name LIKE '%小%');

**/

也可以用 Object 对象来接收结果集:

@Test

publicvoidselectObjs(){

QueryWrapper queryWrapper =newQueryWrapper<>();

queryWrapper.like("name","小");

List objects = userMapper.selectObjs(queryWrapper);

}

/**

OUTPUT:

{name=小菜, remark=关注小菜不迷路!, id=1, dept_id=1}

{name=小明, remark=好好学习,天天向上!, id=2, dept_id=1}

SQL语句:

SELECT id, name, dept_id, remark FROM student WHERE (name LIKE '%小%');

**/

分页查询

@Test

publicvoidselectPage(){

QueryWrapper queryWrapper =newQueryWrapper<>();

queryWrapper.like("name","小");

Page page =newPage<>(1,1);

IPage userIPage = userMapper.selectPage(page, queryWrapper);

System.out.println("数据总数:"+ userIPage.getTotal());

System.out.println("总页数:"+ userIPage.getPages());

System.out.println("当前页:"+ userIPage.getCurrent());

System.out.println("页大小:"+ userIPage.getSize());

userIPage.getRecords().forEach(System.out::println);

}

/**

OUTPUT:

数据总数:2

总页数:2

当前页:1

页大小:1

User(id=1, deptId=1, name=小菜, remark=关注小菜不迷路!)

SQL语句:

SELECT id, name, dept_id, remark

FROM student

WHERE (name LIKE '%小%')

LIMIT 0,1;

**/

3. 条件构造器

在 CRUD 的基本操作中,我们想要通过条件查询都是通过 Wrapper 类进行封装的,上面只是简单的用到 eq 和 like 操作。事实上这个类十分强大,我们在下面会详细进行介绍。

1)allEq

全部 eq 或个别 isNull

allEq(Map params)

allEq(Map params,booleannull2IsNull)

allEq(booleancondition, Map params,booleannull2IsNull)

allEq(BiPredicate filter, Map params)

allEq(BiPredicate filter, Map params,booleannull2IsNull)

allEq(booleancondition, BiPredicate filter, Map params,booleannull2IsNull)

参数说明:

param: key 为数据库字段名,value 为字段值

**nullsIsNull:**为 true 则在 map 的 value 为 null 时调用 isNull 方法,为 false 时则忽略 value 为 null 时不调用 isNull 方法

filter: 过滤函数,判断是否允许字段传入比对条件中

使用示例:

allEq(Map<R, V> params)

@Test

publicvoidtestAllEq(){

QueryWrapper queryWrapper =newQueryWrapper<>();

Map params =newHashMap<>();

params.put("name","小菜");

params.put("dept_id",1);

params.put("remark",null);

queryWrapper.allEq(params);//会调用 isNull 方法

userMapper.selectList(queryWrapper);

}

/**

结果:

{}

SQL语句:

SELECT id,name,dept_id,remark

FROM student

WHERE (name = '小菜' AND dept_id = 1 AND remark IS NULL);

**/

allEq(Map<R, V> params, boolean null2IsNull)

@Test

publicvoidtestAllEq(){

QueryWrapper queryWrapper =newQueryWrapper<>();

Map params =newHashMap<>();

params.put("name","小菜");

params.put("dept_id",1);

params.put("remark",null);

queryWrapper.allEq(params,false);//不会调用 isNull 方法

userMapper.selectList(queryWrapper);

}

/**

结果:

User(id=1, deptId=1, name=小菜, remark=关注小菜不迷路!)

SQL语句:

SELECT id,name,dept_id,remark

FROM student

WHERE (name = '小菜' AND dept_id = 1);

**/

allEq(boolean condition, Map<R, V> params, boolean null2IsNull)

@Test

publicvoidtestAllEq(){

QueryWrapper queryWrapper =newQueryWrapper<>();

Map params =newHashMap<>();

params.put("name","小菜");

params.put("dept_id",1);

params.put("remark",null);

queryWrapper.allEq(false,params,false);//不会带入条件进行查询

userMapper.selectList(queryWrapper);

}

/**

结果:

{name=小菜, remark=关注小菜不迷路!, id=1, dept_id=1}

{name=小明, remark=好好学习,天天向上!, id=2, dept_id=1}

SQL语句:

SELECT id,name,dept_id,remark

FROM student;

**/

allEq(BiPredicate<R, V> filter, Map<R, V> params)

@Test

publicvoidtestAllEq(){

QueryWrapper queryWrapper =newQueryWrapper<>();

Map params =newHashMap<>();

params.put("name","小菜");

params.put("dept_id",1);

params.put("remark",null);

//只有 key 中含有 “m” 才会用作条件判断

queryWrapper.allEq((k, v) -> (k.contains("m")), params);

userMapper.selectList(queryWrapper);

}

/**

结果:

0

SQL语句:

SELECT id,name,dept_id,remark

FROM student

WHERE (name = '小菜' AND remark IS NULL);

**/

2)比较操作

eq: 相当于 =

ne: 相当于 !=

gt: 相当于 >

ge: 相当于>=

lt: 相当于 <

le: 相当于<=

between: 相当于between ... and ...

notBetween: 相当于not between ... and ...

in: 相当于in(.., .., ..)

notIn: 相当于not in(.., .., ..)

3)模糊查询

like: like("name","小菜") --> name like "%小菜%"

notLike: notLike("name","小菜") --> name not like "%小菜%"

likeLeft: like("name","小菜") --> name like "%小菜"

likeRight: like("name","小菜") --> name like "小菜%"

4)排序

orderBy:

orderBy(booleancondition,booleanisAsc, R... columns)

orderBy(true, true, "id", "name") --> order by id ASC, name ASC

orderByAsc:

orderByAsc("id","name") --> order by id ASC, name ASC

orderByDesc:

orderByDesc("id","name) --> order by id Desc, name Desc

5)逻辑查询

or:

拼接:主动调用 or 表示紧接着下一个方法不是用 and 连接!(不调用 or 则默认为使用 and连接), eq("id",1).or().eq("name","老王")

嵌套:or(i -> i.eq("name", "李白").ne("status", "活着"))

and:

嵌套:and(i -> i.eq("name", "李白").ne("status", "活着"))

6)select

在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段,如select("id", "name")

4. 配置讲解

1)基本配置

configLocation

用于指明 **MyBatis ** 配置文件的位置,如果我们有 MyBatis 的配置文件,需将配置文件的路径配置到 configLocation 中

SpringBoot:

mybatis-plus.config-location = classpath:mybatis-config.xml

SpringMvc:

class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">

mapperLocations

用于指明 Mapper 所对应的 XML 的文件位置,我们在 通用 CRUD 中用到的 Mapper 是直接继承 MP 提供的 BaseMapper ,我们也可以自定义方法,然后在 XML 文件中自定义SQL,而这时我们需要告诉 Mapper 所对应 XML 文件的位置

SpringBoot:

mybatis-plus.mapper-locations = classpath*:mybatis/*.xml

SpringMVC:

class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">

typeAliasesPackage

用于 MyBatis 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名

SpringBoot:

mybatis-plus.type-aliases-package = cbuc.life.bean

SpringMVC:

class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">

value="com.baomidou.mybatisplus.samples.quickstart.entity"/>

2)进阶配置

mapUnderScoreToCamelCase

是否开启自动驼峰命名规则映射,这个配置的默认值是 true,但是这个属性在 MyBatis 中的默认值是 false,所以在我们平时的开发中都会将这个配置开启。

#关闭自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在

mybatis-plus.configuration.map-underscore-to-camel-case = false

cacheEnabled

全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为 true

mybatis-plus.configuration.cache-enabled = false

3)DB 策略配置

idType

全局默认主键类型,设置后,即可省略实体对象中的@TableId(type = IdType.AUTO)配置。该配置的默认值为 ID_WORKER

SpringBoot:

mybatis-plus.global-config.db-config.id-type = auto

SpringMVC:

class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">

tablePrefix

表名前缀,全局配置后可省略@TableName()配置。该配置的默认值为 null

SpringBoot:

mybatis-plus.global-config.db-config.table-prefix = yq_

SpringMVC:

class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">

5. 其他扩展

1)自动填充

有时候我们在插入或更新数据的时候,希望有些字段可以自动填充。比如我们平时数据表里面会有个 插入时间 或者 更新时间 这种字段,我们会默认以当前时间填充,在 MP 中我们也可以进行配置。

首先我们需要借助 @TableField(fill = FieldFill.INSERT) 这个注解,在插入时进行填充。

@TableField(fill = FieldFill.INSERT)

privateString remark;

其中自动填充的模式如下:

publicenumFieldFill {

/**

* 默认不处理

*/

DEFAULT,

/**

* 插入时填充字段

*/

INSERT,

/**

* 更新时填充字段

*/

UPDATE,

/**

* 插入和更新时填充字段

*/

INSERT_UPDATE

}

然后我们再编写自定义的填充处理模式:

@Component

publicclassMyMetaObjectHandlerimplementsMetaObjectHandler{

@Override

publicvoidinsertFill(MetaObject metaObject){

Object remark = getFieldValByName("remark", metaObject);

if(null== remark) {

setFieldValByName("remark","好好学习", metaObject);

}

}

@Override

publicvoidupdateFill(MetaObject metaObject){

//自定义更新时填充

}

}

测试:

@Test

publicvoidtestObjectHandler(){

User user = User.builder().deptId(1).name("小明").build();

userMapper.insert(user);

}

/**

SQL语句:

INSERT INTO student ( name, dept_id, remark )

VALUES ( '小明', 1, '好好学习' );

**/

可以看到插入时,已经自动将我们填充的字段合并进去。

2)逻辑删除

在开发中,很多时候我们删除数据并不需要真正意义上的物理删除,而是使用逻辑删除,这样子查询的时候需要状态条件,确保被标记的数据不被查询到。MP 当然也支持这样的功能。

我们需要先为 student 表添加一个字段 status 来声明数据是否被删除,0 表示被删除,1表示未删除,然后也需要在实体类上增加这个属性:

@TableLogic

privateInteger status;

在 application.yaml 中配置:

mybatis-plus:

global-config:

db-config:

logic-delete-value:0

logic-not-delete-value:1

测试:

@Test

publicvoidtestLogicDelete(){

userMapper.deleteById(1);

}

/**

SQL语句:

UPDATE student SET status=0

WHERE id=1 AND status=1;

**/

可以看出这段 SQL 并没有真正删除,而是进行了逻辑删除,只是更新了删除标识

3)通用枚举

如果有性别之类的字段,我们通常会用 0 和 1 来表示,但是查出来我们得进行值转换,这个时候我们就可以使用枚举来解决这个问题:

首先为 student 表添加一个 sex 字段来表示性别,0 表示女性,1 表示男性,然后定义一个枚举类:

publicenumSexEnum implements IEnum {

MAN(1,"男"),

WOMEN(0,"女");

privateintcode;

privateString value;

SexEnum(intcode, String value) {

this.code = code;

this.value = value;

}

@Override

publicIntegergetValue(){

returnthis.code;

}

//注意要重写此方法,不然会将值转换成 ‘MAN’,而不是 ‘男’

@Override

publicStringtoString(){

returnthis.value;

}

}

然后在实体类中添加对应属性:

privateSexEnum sex;

在 application.yaml 中配置:

mybatis-plus:

type-enums-package:cbuc.life.enums

测试:

@Test

publicvoidselectOne(){

QueryWrapper queryWrapper =newQueryWrapper<>();

queryWrapper.eq("name","小菜");

User user = userMapper.selectOne(queryWrapper);

System.out.println(user);

}

/**

输出结果:

User(id=1, deptId=1, name=小菜, remark=关注小菜不迷路!, status=1, sex=男)

SQL语句:

SELECT id,sex,name,dept_id,remark,status

FROM student

WHERE status=1 AND (name = '小菜');

**/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 1. MyBatisPlus概述 为什么要学习它呢?MyBatisPlus可以节省我们大量工作时间,所有的CRUD...
    弹钢琴的崽崽阅读 1,966评论 0 3
  • 一、重点知识 git 监视的是文件内容的修改 $ git checkout -- abc.txt : 其实是用版本...
    一花一世界yu阅读 875评论 0 2
  • MyBatis 简介 MyBatis 是什么? MyBatis 是一款优秀的持久层框架,一个半 ORM(对象关系映...
    Java__JJ阅读 392评论 0 0
  • 1. 多表查询 2. 事务 3. DCL ## 多表查询: * 查询语法: select 列名列表 from 表名...
    吕游_b601阅读 613评论 0 0
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,495评论 16 22