熟练掌握 MyBatis-Plus一篇就够_第1页
熟练掌握 MyBatis-Plus一篇就够_第2页
熟练掌握 MyBatis-Plus一篇就够_第3页
熟练掌握 MyBatis-Plus一篇就够_第4页
熟练掌握 MyBatis-Plus一篇就够_第5页
已阅读5页,还剩80页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

熟练掌握MyBatis-Plus,一篇就够!MyBatis-plus是一款Mybatis增强工具,用于简化开发,提高效率。下文使用缩写mp来简化表示MyBatis-plus,本文主要介绍mp搭配SpringBoot的使用。注:本文使用的mp版本是当前最新的3.4.2,早期版本的差异请自行查阅文档官方网站:/快速入门1.创建一个SpringBoot项目。2.导入依赖

<project

xmlns="/POM/4.0.0"

xmlns:xsi="/2001/XMLSchema-instance"

xsi:schemaLocation="/POM/4.0.0

/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0modelVersion>

<parent>

<groupId>org.springframework.bootgroupId>

<artifactId>spring-boot-starter-parentartifactId>

<version>2.3.4.RELEASEversion>

<relativePath/>

parent>

<groupId>com.examplegroupId>

<artifactId>mybatis-plusartifactId>

<version>0.0.1-SNAPSHOTversion>

<name>mybatis-plusname>

<properties>

<java.version>1.8java.version>

properties>

<dependencies>

<dependency>

<groupId>org.springframework.bootgroupId>

<artifactId>spring-boot-starterartifactId>

dependency>

<dependency>

<groupId>org.springframework.bootgroupId>

<artifactId>spring-boot-starter-testartifactId>

<scope>testscope>

dependency>

<dependency>

<groupId>org.springframework.bootgroupId>

<artifactId>spring-boot-configuration-processorartifactId>

dependency>

<dependency>

<groupId>com.baomidougroupId>

<artifactId>mybatis-plus-boot-starterartifactId>

<version>3.4.2version>

dependency>

<dependency>

<groupId>mysqlgroupId>

<artifactId>mysql-connector-javaartifactId>

<scope>runtimescope>

dependency>

<dependency>

<groupId>jectlombokgroupId>

<artifactId>lombokartifactId>

dependency>

dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.bootgroupId>

<artifactId>spring-boot-maven-pluginartifactId>

plugin>

plugins>

build>

project>3.配置数据库#

application.yml

spring:

datasource:

driver-class-name:

com.mysql.cj.jdbc.Driver

url:

jdbc:mysql://localhost:3306/yogurt?serverTimezone=Asia/Shanghai

username:

root

password:

root

mybatis-plus:

configuration:

log-impl:

org.apache.ibatis.logging.stdout.StdOutImpl

#开启SQL语句打印4.创建一个实体类package

com.example.mp.po;

import

lombok.Data;

import

java.time.LocalDateTime;

@Data

public

class

User

{

private

Long

id;

private

String

name;

private

Integer

age;

private

String

email;

private

Long

managerId;

private

LocalDateTime

createTime;

}5.创建一个mapper接口package

com.example.mp.mappers;

import

com.baomidou.mybatisplus.core.mapper.BaseMapper;

import

com.example.mp.po.User;

public

interface

UserMapper

extends

BaseMapper<User>

{

}6.在SpringBoot启动类上配置mapper接口的扫描路径package

com.example.mp;

import

org.mybatis.spring.annotation.MapperScan;

import

org.springframework.boot.SpringApplication;

import

org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

@MapperScan("com.example.mp.mappers")

public

class

MybatisPlusApplication

{

public

static

void

main(String[]

args)

{

SpringApplication.run(MybatisPlusApplication.class,

args);

}

}7.在数据库中创建表DROP

TABLE

IF

EXISTS

user;

CREATE

TABLE

user

(

id

BIGINT(20)

PRIMARY

KEY

NOT

NULL

COMMENT

'主键',

name

VARCHAR(30)

DEFAULT

NULL

COMMENT

'姓名',

age

INT(11)

DEFAULT

NULL

COMMENT

'年龄',

email

VARCHAR(50)

DEFAULT

NULL

COMMENT

'邮箱',

manager_id

BIGINT(20)

DEFAULT

NULL

COMMENT

'直属上级id',

create_time

DATETIME

DEFAULT

NULL

COMMENT

'创建时间',

CONSTRAINT

manager_fk

FOREIGN

KEY(manager_id)

REFERENCES

user

(id)

)

ENGINE=INNODB

CHARSET=UTF8;

INSERT

INTO

user

(id,

name,

age

,email,

manager_id,

create_time)

VALUES

(1,

'大BOSS',

40,

'boss@',

NULL,

'2021-03-22

09:48:00'),

(2,

'李经理',

40,

'boss@',

1,

'2021-01-22

09:48:00'),

(3,

'黄主管',

40,

'boss@',

2,

'2021-01-22

09:48:00'),

(4,

'吴组长',

40,

'boss@',

2,

'2021-02-22

09:48:00'),

(5,

'小菜',

40,

'boss@',

2,

'2021-02-22

09:48:00')8.编写一个SpringBoot测试类package

com.example.mp;

import

com.example.mp.mappers.UserMapper;

import

com.example.mp.po.User;

import

org.junit.Test;

import

org.junit.runner.RunWith;

import

org.springframework.beans.factory.annotation.Autowired;

import

org.springframework.boot.test.context.SpringBootTest;

import

org.springframework.test.context.junit4.SpringRunner;

import

java.util.List;

import

static

org.junit.Assert.*;

@RunWith(SpringRunner.class)

@SpringBootTest

public

class

SampleTest

{

@Autowired

private

UserMapper

mapper;

@Test

public

void

testSelect()

{

List

list

=

mapper.selectList(null);

assertEquals(5,

list.size());

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

}

}准备工作完成,数据库情况如下:项目目录如下:图片运行测试类图片可以看到,针对单表的基本CRUD操作,只需要创建好实体类,并创建一个继承自BaseMapper的接口即可,可谓非常简洁。并且,我们注意到,User类中的managerId,createTime属性,自动和数据库表中的manager_id,create_time对应了起来,这是因为mp自动做了数据库下划线命名,到Java类的驼峰命名之间的转化。核心功能注解mp一共提供了8个注解,这些注解是用在Java的实体类上面的。@TableName注解在类上,指定类和数据库表的映射关系。实体类的类名(转成小写后)和数据库表名相同时,可以不指定该注解。@TableId注解在实体类的某一字段上,表示这个字段对应数据库表的主键。当主键名为id时(表中列名为id,实体类中字段名为id),无需使用该注解显式指定主键,mp会自动关联。若类的字段名和表的列名不一致,可用value属性指定表的列名。另,这个注解有个重要的属性type,用于指定主键策略。@TableField注解在某一字段上,指定Java实体类的字段和数据库表的列的映射关系。这个注解有如下几个应用场景。关于Spring项目中的注解,这篇做了详细介绍:注解介绍排除非表字段若Java实体类中某个字段,不对应表中的任何列,它只是用于保存一些额外的,或组装后的数据,则可以设置exist属性为false,这样在对实体对象进行插入时,会忽略这个字段。排除非表字段也可以通过其他方式完成,如使用static或transient关键字,但个人觉得不是很合理,不做赘述字段验证策略通过insertStrategy,updateStrategy,whereStrategy属性进行配置,可以控制在实体对象进行插入,更新,或作为WHERE条件时,对象中的字段要如何组装到SQL语句中。字段填充策略通过fill属性指定,字段为空时会进行自动填充@Version乐观锁注解@EnumValue注解在枚举字段上@TableLogic逻辑删除KeySequence序列主键策略(oracle)InterceptorIgnore插件过滤规则CRUD接口mp封装了一些最基础的CRUD方法,只需要直接继承mp提供的接口,无需编写任何SQL,即可食用。mp提供了两套接口,分别是MapperCRUD接口和ServiceCRUD接口。并且mp还提供了条件构造器Wrapper,可以方便地组装SQL语句中的WHERE条件。搜索公众号顶级架构师回复关键字“1024”,获取一份惊喜礼包。MapperCRUD接口只需定义好实体类,然后创建一个接口,继承mp提供的BaseMapper,即可食用。mp会在mybatis启动时,自动解析实体类和表的映射关系,并注入带有通用CRUD方法的mapper。BaseMapper里提供的方法,部分列举如下:insert(Tentity)

插入一条记录deleteById(Serializableid)

根据主键id删除一条记录delete(Wrapperwrapper)

根据条件构造器wrapper进行删除selectById(Serializableid)

根据主键id进行查找selectBatchIds(CollectionidList)

根据主键id进行批量查找selectByMap(Mapmap)

根据map中指定的列名和列值进行等值匹配查找selectMaps(Wrapperwrapper)

根据wrapper条件,查询记录,将查询结果封装为一个Map,Map的key为结果的列,value为值selectList(Wrapperwrapper)

根据条件构造器wrapper进行查询update(Tentity,Wrapperwrapper)

根据条件构造器wrapper进行更新updateById(Tentity)...下面讲解几个比较特别的方法selectMapsBaseMapper接口还提供了一个selectMaps方法,这个方法会将查询结果封装为一个Map,Map的key为结果的列,value为值该方法的使用场景如下:只查部分列当某个表的列特别多,而SELECT的时候只需要选取个别列,查询出的结果也没必要封装成Java实体类对象时(只查部分列时,封装成实体后,实体对象中的很多属性会是null),则可以用selectMaps,获取到指定的列后,再自行进行处理即可比如@Test

public

void

test3()

{

QueryWrapper

wrapper

=

new

QueryWrapper<>();

wrapper.select("id","name","email").likeRight("name","黄");

List>

maps

=

userMapper.selectMaps(wrapper);

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

}进行数据统计比如//

按照直属上级进行分组,查询每组的平均年龄,最大年龄,最小年龄

/**

select

avg(age)

avg_age

,min(age)

min_age,

max(age)

max_age

from

user

group

by

manager_id

having

sum(age)

<

500;

**/

@Test

public

void

test3()

{

QueryWrapper

wrapper

=

new

QueryWrapper<>();

wrapper.select("manager_id",

"avg(age)

avg_age",

"min(age)

min_age",

"max(age)

max_age")

.groupBy("manager_id").having("sum(age)

<

{0}",

500);

List>

maps

=

userMapper.selectMaps(wrapper);

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

}图片selectObjs只会返回第一个字段(第一列)的值,其他字段会被舍弃比如@Test

public

void

test3()

{

QueryWrapper

wrapper

=

new

QueryWrapper<>();

wrapper.select("id",

"name").like("name",

"黄");

List

objects

=

userMapper.selectObjs(wrapper);

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

}得到的结果,只封装了第一列的idselectCount查询满足条件的总数,注意,使用这个方法,不能调用QueryWrapper的select方法设置要查询的列了。这个方法会自动添加selectcount(1)比如@Test

public

void

test3()

{

QueryWrapper

wrapper

=

new

QueryWrapper<>();

wrapper.like("name",

"黄");

Integer

count

=

userMapper.selectCount(wrapper);

System.out.println(count);

}图片ServiceCRUD接口另外一套CRUD是Service层的,只需要编写一个接口,继承IService,并创建一个接口实现类,即可食用。(这个接口提供的CRUD方法,和Mapper接口提供的功能大同小异,比较明显的区别在于IService支持了更多的批量化操作,如saveBatch,saveOrUpdateBatch等方法。食用示例如下1.首先,新建一个接口,继承IServicepackage

com.example.mp.service;

import

com.baomidou.mybatisplus.extension.service.IService;

import

com.example.mp.po.User;

public

interface

UserService

extends

IService<User>

{

}2.创建这个接口的实现类,并继承ServiceImpl,最后打上@Service注解,注册到Spring容器中,即可食用package

com.example.mp.service.impl;

import

com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import

com.example.mp.mappers.UserMapper;

import

com.example.mp.po.User;

import

com.example.mp.service.UserService;

import

org.springframework.stereotype.Service;

@Service

public

class

UserServiceImpl

extends

ServiceImpl<UserMapper,

User>

implements

UserService

{

}3.测试代码package

com.example.mp;

import

com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import

com.baomidou.mybatisplus.core.toolkit.Wrappers;

import

com.example.mp.po.User;

import

com.example.mp.service.UserService;

import

org.junit.Test;

import

org.junit.runner.RunWith;

import

org.springframework.beans.factory.annotation.Autowired;

import

org.springframework.boot.test.context.SpringBootTest;

import

org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)

@SpringBootTest

public

class

ServiceTest

{

@Autowired

private

UserService

userService;

@Test

public

void

testGetOne()

{

LambdaQueryWrapper

wrapper

=

Wrappers.lambdaQuery();

wrapper.gt(User::getAge,

28);

User

one

=

userService.getOne(wrapper,

false);

//

第二参数指定为false,使得在查到了多行记录时,不抛出异常,而返回第一条记录

System.out.println(one);

}

}4.结果图片另,IService也支持链式调用,代码写起来非常简洁,查询示例如下@Test

public

void

testChain()

{

List

list

=

userService.lambdaQuery()

.gt(User::getAge,

39)

.likeRight(User::getName,

"王")

.list();

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

}更新示例如下@Test

public

void

testChain()

{

userService.lambdaUpdate()

.gt(User::getAge,

39)

.likeRight(User::getName,

"王")

.set(User::getEmail,

"w39@")

.update();

}图片删除示例如下@Test

public

void

testChain()

{

userService.lambdaUpdate()

.like(User::getName,

"青蛙")

.remove();

}图片条件构造器mp让我觉得极其方便的一点在于其提供了强大的条件构造器Wrapper,可以非常方便的构造WHERE条件。条件构造器主要涉及到3个类,AbstractWrapper。QueryWrapper,UpdateWrapper,它们的类关系如下图片在AbstractWrapper中提供了非常多的方法用于构建WHERE条件,而QueryWrapper针对SELECT语句,提供了select()方法,可自定义需要查询的列,而UpdateWrapper针对UPDATE语句,提供了set()方法,用于构造set语句。条件构造器也支持lambda表达式,写起来非常舒爽。下面对AbstractWrapper中用于构建SQL语句中的WHERE条件的方法进行部分列举eq:equals,等于allEq:allequals,全等于ne:notequals,不等于gt:greaterthan,大于

>ge:greaterthanorequals,大于等于≥lt:lessthan,小于<le:lessthanorequals,小于等于≤between:相当于SQL中的BETWEENnotBetweenlike:模糊匹配。like("name","黄"),相当于SQL的namelike'%黄%'likeRight:模糊匹配右半边。likeRight("name","黄"),相当于SQL的namelike'黄%'likeLeft:模糊匹配左半边。likeLeft("name","黄"),相当于SQL的namelike'%黄'notLike:notLike("name","黄"),相当于SQL的namenotlike'%黄%'isNullisNotNullinand:SQL连接符ANDor:SQL连接符ORapply:用于拼接SQL,该方法可用于数据库函数,并可以动态传参使用示例下面通过一些具体的案例来练习条件构造器的使用。(使用前文创建的user表)//

案例先展示需要完成的SQL语句,后展示Wrapper的写法

//

1.

名字中包含佳,且年龄小于25

//

SELECT

*

FROM

user

WHERE

name

like

'%佳%'

AND

age

<

25

QueryWrapper

wrapper

=

new

QueryWrapper<>();

wrapper.like("name",

"佳").lt("age",

25);

List

users

=

userMapper.selectList(wrapper);

//

下面展示SQL时,仅展示WHERE条件;展示代码时,仅展示Wrapper构建部分

//

2.

姓名为黄姓,且年龄大于等于20,小于等于40,且email字段不为空

//

name

like

'黄%'

AND

age

BETWEEN

20

AND

40

AND

email

is

not

null

wrapper.likeRight("name","黄").between("age",

20,

40).isNotNull("email");

//

3.

姓名为黄姓,或者年龄大于等于40,按照年龄降序排列,年龄相同则按照id升序排列

//

name

like

'黄%'

OR

age

>=

40

order

by

age

desc,

id

asc

wrapper.likeRight("name","黄").or().ge("age",40).orderByDesc("age").orderByAsc("id");

//

4.创建日期为2021年3月22日,并且直属上级的名字为李姓

//

date_format(create_time,'%Y-%m-%d')

=

'2021-03-22'

AND

manager_id

IN

(SELECT

id

FROM

user

WHERE

name

like

'李%')

wrapper.apply("date_format(create_time,

'%Y-%m-%d')

=

{0}",

"2021-03-22")

//

建议采用{index}这种方式动态传参,

可防止SQL注入

.inSql("manager_id",

"SELECT

id

FROM

user

WHERE

name

like

'李%'");

//

上面的apply,

也可以直接使用下面这种方式做字符串拼接,但当这个日期是一个外部参数时,这种方式有SQL注入的风险

wrapper.apply("date_format(create_time,

'%Y-%m-%d')

=

'2021-03-22'");

//

5.

名字为王姓,并且(年龄小于40,或者邮箱不为空)

//

name

like

'王%'

AND

(age

<

40

OR

email

is

not

null)

wrapper.likeRight("name",

"王").and(q

->

q.lt("age",

40).or().isNotNull("email"));

//

6.

名字为王姓,或者(年龄小于40并且年龄大于20并且邮箱不为空)

//

name

like

'王%'

OR

(age

<

40

AND

age

>

20

AND

email

is

not

null)

wrapper.likeRight("name",

"王").or(

q

->

q.lt("age",40)

.gt("age",20)

.isNotNull("email")

);

//

7.

(年龄小于40或者邮箱不为空)

并且名字为王姓

//

(age

<

40

OR

email

is

not

null)

AND

name

like

'王%'

wrapper.nested(q

->

q.lt("age",

40).or().isNotNull("email"))

.likeRight("name",

"王");

//

8.

年龄为30,31,34,35

//

age

IN

(30,31,34,35)

wrapper.in("age",

Arrays.asList(30,31,34,35));

//

wrapper.inSql("age","30,31,34,35");

//

9.

年龄为30,31,34,35,

返回满足条件的第一条记录

//

age

IN

(30,31,34,35)

LIMIT

1

wrapper.in("age",

Arrays.asList(30,31,34,35)).last("LIMIT

1");

//

10.

只选出id,

name

(QueryWrapper

特有)

//

SELECT

id,

name

FROM

user;

wrapper.select("id",

"name");

//

11.

选出id,

name,

age,

email,

等同于排除

manager_id

create_time

//

当列特别多,

而只需要排除个别列时,

采用上面的方式可能需要写很多个列,

可以采用重载的select方法,指定需要排除的列

wrapper.select(User.class,

info

->

{

String

columnName

=

info.getColumn();

return

!"create_time".equals(columnName)

&&

!"manager_id".equals(columnName);

});Condition条件构造器的诸多方法中,均可以指定一个boolean类型的参数condition,用来决定该条件是否加入最后生成的WHERE语句中,比如String

name

=

"黄";

//

假设name变量是一个外部传入的参数

QueryWrapper

wrapper

=

new

QueryWrapper<>();

wrapper.like(StringUtils.hasText(name),

"name",

name);

//

仅当

StringUtils.hasText(name)

true

时,

会拼接这个like语句到WHERE中

//

其实就是对下面代码的简化

if

(StringUtils.hasText(name))

{

wrapper.like("name",

name);

}实体对象作为条件调用构造函数创建一个Wrapper对象时,可以传入一个实体对象。后续使用这个Wrapper时,会以实体对象中的非空属性,构建WHERE条件(默认构建等值匹配的WHERE条件,这个行为可以通过实体类里各个字段上的@TableField注解中的condition属性进行改变)示例如下@Test

public

void

test3()

{

User

user

=

new

User();

user.setName("黄主管");

user.setAge(28);

QueryWrapper

wrapper

=

new

QueryWrapper<>(user);

List

users

=

userMapper.selectList(wrapper);

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

}执行结果如下。可以看到,是根据实体对象中的非空属性,进行了等值匹配查询。若希望针对某些属性,改变等值匹配的行为,则可以在实体类中用@TableField注解进行配置,示例如下package

com.example.mp.po;

import

com.baomidou.mybatisplus.annotation.SqlCondition;

import

com.baomidou.mybatisplus.annotation.TableField;

import

lombok.Data;

import

java.time.LocalDateTime;

@Data

public

class

User

{

private

Long

id;

@TableField(condition

=

SqlCondition.LIKE)

//

配置该字段使用like进行拼接

private

String

name;

private

Integer

age;

private

String

email;

private

Long

managerId;

private

LocalDateTime

createTime;

}运行下面的测试代码@Test

public

void

test3()

{

User

user

=

new

User();

user.setName("黄");

QueryWrapper

wrapper

=

new

QueryWrapper<>(user);

List

users

=

userMapper.selectList(wrapper);

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

}从下图得到的结果来看,对于实体对象中的name字段,采用了like进行拼接图片@TableField中配置的condition属性实则是一个字符串,SqlCondition类中预定义了一些字符串以供选择package

com.baomidou.mybatisplus.annotation;

public

class

SqlCondition

{

//下面的字符串中,

%s

是占位符,

第一个

%s

是列名,

第二个

%s

是列的值

public

static

final

String

EQUAL

=

"%s=#{%s}";

public

static

final

String

NOT_EQUAL

=

"%s<>#{%s}";

public

static

final

String

LIKE

=

"%s

LIKE

CONCAT('%%',#{%s},'%%')";

public

static

final

String

LIKE_LEFT

=

"%s

LIKE

CONCAT('%%',#{%s})";

public

static

final

String

LIKE_RIGHT

=

"%s

LIKE

CONCAT(#{%s},'%%')";

}SqlCondition中提供的配置比较有限,当我们需要<或>等拼接方式,则需要自己定义。比如package

com.example.mp.po;

import

com.baomidou.mybatisplus.annotation.SqlCondition;

import

com.baomidou.mybatisplus.annotation.TableField;

import

lombok.Data;

import

java.time.LocalDateTime;

@Data

public

class

User

{

private

Long

id;

@TableField(condition

=

SqlCondition.LIKE)

private

String

name;

@TableField(condition

=

"%s

>

#{%s}")

//

这里相当于大于,

其中

>

是字符实体

private

Integer

age;

private

String

email;

private

Long

managerId;

private

LocalDateTime

createTime;

}测试如下@Test

public

void

test3()

{

User

user

=

new

User();

user.setName("黄");

user.setAge(30);

QueryWrapper

wrapper

=

new

QueryWrapper<>(user);

List

users

=

userMapper.selectList(wrapper);

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

}从下图得到的结果,可以看出,name属性是用like拼接的,而age属性是用>拼接的图片allEq方法allEq方法传入一个map,用来做等值匹配@Test

public

void

test3()

{

QueryWrapper

wrapper

=

new

QueryWrapper<>();

Map

param

=

new

HashMap<>();

param.put("age",

40);

param.put("name",

"黄飞飞");

wrapper.allEq(param);

List

users

=

userMapper.selectList(wrapper);

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

}图片当allEq方法传入的Map中有value为null的元素时,默认会设置为isnull@Test

public

void

test3()

{

QueryWrapper

wrapper

=

new

QueryWrapper<>();

Map

param

=

new

HashMap<>();

param.put("age",

40);

param.put("name",

null);

wrapper.allEq(param);

List

users

=

userMapper.selectList(wrapper);

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

}若想忽略map中value为null的元素,可以在调用allEq时,设置参数booleannull2IsNull为false@Test

public

void

test3()

{

QueryWrapper

wrapper

=

new

QueryWrapper<>();

Map

param

=

new

HashMap<>();

param.put("age",

40);

param.put("name",

null);

wrapper.allEq(param,

false);

List

users

=

userMapper.selectList(wrapper);

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

}图片若想要在执行allEq时,过滤掉Map中的某些元素,可以调用allEq的重载方法allEq(BiPredicatefilter,Mapparams)@Test

public

void

test3()

{

QueryWrapper

wrapper

=

new

QueryWrapper<>();

Map

param

=

new

HashMap<>();

param.put("age",

40);

param.put("name",

"黄飞飞");

wrapper.allEq((k,v)

->

!"name".equals(k),

param);

//

过滤掉map中key为name的元素

List

users

=

userMapper.selectList(wrapper);

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

}图片lambda条件构造器lambda条件构造器,支持lambda表达式,可以不必像普通条件构造器一样,以字符串形式指定列名,它可以直接以实体类的方法引用来指定列。示例如下@Test

public

void

testLambda()

{

LambdaQueryWrapper

wrapper

=

new

LambdaQueryWrapper<>();

wrapper.like(User::getName,

"黄").lt(User::getAge,

30);

List

users

=

userMapper.selectList(wrapper);

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

}像普通的条件构造器,列名是用字符串的形式指定,无法在编译期进行列名合法性的检查,这就不如lambda条件构造器来的优雅。另外,还有个链式lambda条件构造器,使用示例如下@Test

public

void

testLambda()

{

LambdaQueryChainWrapper

chainWrapper

=

new

LambdaQueryChainWrapper<>(userMapper);

List

users

=

chainWrapper.like(User::getName,

"黄").gt(User::getAge,

30).list();

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

}更新操作上面介绍的都是查询操作,现在来讲更新和删除操作。BaseMapper中提供了2个更新方法updateById(Tentity)根据入参entity的id(主键)进行更新,对于entity中非空的属性,会出现在UPDATE语句的SET后面,即entity中非空的属性,会被更新到数据库,示例如下@RunWith(SpringRunner.class)

@SpringBootTest

public

class

UpdateTest

{

@Autowired

private

UserMapper

userMapper;

@Test

public

void

testUpdate()

{

User

user

=

new

User();

user.setId(2L);

user.setAge(18);

userMapper.updateById(user);

}

}图片update(Tentity,Wrapperwrapper)根据实体entity和条件构造器wrapper进行更新,示例如下@Test

public

void

testUpdate2()

{

User

user

=

new

User();

user.setName("王三蛋");

LambdaUpdateWrapper

wrapper

=

new

LambdaUpdateWrapper<>();

wrapper.between(User::getAge,

26,31).likeRight(User::getName,"吴");

userMapper.update(user,

wrapper);

}额外演示一下,把实体对象传入Wrapper,即用实体对象构造WHERE条件的案例@Test

public

void

testUpdate3()

{

User

whereUser

=

new

User();

whereUser.setAge(40);

whereUser.setName("王");

LambdaUpdateWrapper

wrapper

=

new

LambdaUpdateWrapper<>(whereUser);

User

user

=

new

User();

user.setEmail("share@");

user.setManagerId(10L);

userMapper.update(user,

wrapper);

}注意到我们的User类中,对name属性和age属性进行了如下的设置@Data

public

class

User

{

private

Long

id;

@TableField(condition

=

SqlCondition.LIKE)

private

String

name;

@TableField(condition

=

"%s

>

#{%s}")

private

Integer

age;

private

String

email;

private

Long

managerId;

private

LocalDateTime

createTime;

}执行结果图片图片再额外演示一下,链式lambda条件构造器的使用@Test

public

void

testUpdate5()

{

LambdaUpdateChainWrapper

wrapper

=

new

LambdaUpdateChainWrapper<>(userMapper);

wrapper.likeRight(User::getEmail,

"share")

.like(User::getName,

"飞飞")

.set(User::getEmail,

"ff@")

.update();

}图片反思由于BaseMapper提供的2个更新方法都是传入一个实体对象去执行更新,这在需要更新的列比较多时还好,若想要更新的只有那么一列,或者两列,则创建一个实体对象就显得有点麻烦。针对这种情况,UpdateWrapper提供有set方法,可以手动拼接SQL中的SET语句,此时可以不必传入实体对象,示例如下搜索公众号顶级架构师回复关键字“offer”,获取一份惊喜礼包。@Test

public

void

testUpdate4()

{

LambdaUpdateWrapper

wrapper

=

new

LambdaUpdateWrapper<>();

wrapper.likeRight(User::getEmail,

"share").set(User::getManagerId,

9L);

userMapper.update(null,

wrapper);

}图片删除操作BaseMapper一共提供了如下几个用于删除的方法deleteById

根据主键id进行删除deleteBatchIds

根据主键id进行批量删除deleteByMap

根据Map进行删除(Map中的key为列名,value为值,根据列和值进行等值匹配)delete(Wrapperwrapper)

根据条件构造器Wrapper进行删除与前面查询和更新的操作大同小异,不做赘述自定义SQL当mp提供的方法还不能满足需求时,则可以自定义SQL。原生mybatis示例如下注解方式package

com.example.mp.mappers;

import

com.baomidou.mybatisplus.core.mapper.BaseMapper;

import

com.example.mp.po.User;

import

org.apache.ibatis.annotations.Select;

import

java.util.List;

/**

*

@Author

yogurtzzz

*

@Date

2021/3/18

11:21

**/

public

interface

UserMapper

extends

BaseMapper<User>

{

@Select("select

*

from

user")

List

selectRaw();

}xml方式

mapper

PUBLIC

"-////DTD

Mapper

3.0//EN"

"/dtd/mybatis-3-mapper.dtd">

<mapper

namespace="com.example.mp.mappers.UserMapper">

<select

id="selectRaw"

resultType="com.example.mp.po.User">

SELECT

*

FROM

user

select>

mapper>

package

com.example.mp.mappers;

import

com.baomidou.mybatisplus.core.mapper.BaseMapper;

import

com.example.mp.po.User;

import

org.apache.ibatis.annotations.Select;

import

java.util.List;

public

interface

UserMapper

extends

BaseMapper<User>

{

List

selectRaw();

}使用xml时,若xml文件与mapper接口文件不在同一目录下,则需要在application.yml中配置mapper.xml的存放路径mybatis-plus:

mapper-locations:

/mappers/*若有多个地方存放mapper,则用数组形式进行配置mybatis-plus:

mapper-locations:

-

/mappers/*

-

/com/example/mp/*测试代码如下@Test

public

void

testCustomRawSql()

{

List

users

=

userMapper.selectRaw();

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

}结果图片mybatis-plus也可以使用mp提供的Wrapper条件构造器,来自定义SQL示例如下注解方式package

com.example.mp.mappers;

import

com.baomidou.mybatisplus.core.conditions.Wrapper;

import

com.baomidou.mybatisplus.core.mapper.BaseMapper;

import

com.baomidou.mybatisplus.core.toolkit.Constants;

import

com.example.mp.po.User;

import

org.apache.ibatis.annotations.Param;

import

org.apache.ibatis.annotations.Select;

import

java.util.List;

public

interface

UserMapper

extends

BaseMapper<User>

{

//

SQL中不写WHERE关键字,且固定使用${ew.customSqlSegment}

@Select("select

*

from

user

${ew.customSqlSegment}")

List

findAll(@Param(Constants.WRAPPER)Wrapper

wrapper);

}xml方式package

com.example.mp.mappers;

import

com.baomidou.mybatisplus.core.conditions.Wrapper;

import

com.baomidou.mybatisplus.core.mapper.BaseMapper;

import

com.example.mp.po.User;

import

java.util.List;

public

interface

UserMapper

extends

BaseMapper<User>

{

List

findAll(Wrapper

wrapper);

}

mapper

PUBLIC

"-////DTD

Mapper

3.0//EN"

"/dtd/mybatis-3-mapper.dtd">

<mapper

namespace="com.example.mp.mappers.UserMapper">

<select

id="findAll"

resultType="com.example.mp.po.User">

SELECT

*

FROM

user

${ew.customSqlSegment}

select>

mapper>分页查询BaseMapper中提供了2个方法进行分页查询,分别是selectPage和selectMapsPage,前者会将查询的结果封装成Java实体对象,后者会封装成Map。分页查询的食用示例如下1.创建mp的分页拦截器,注册到Spring容器中package

com.example.mp.config;

import

com.baomidou.mybatisplus.annotation.DbType;

import

com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;

import

com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;

import

org.springframework.context.annotation.Bean;

import

org.springframework.context.annotation.Configuration;

@Configuration

public

class

MybatisPlusConfig

{

/**

新版mp

**/

@Bean

public

MybatisPlusInterceptor

mybatisPlusInterceptor()

{

MybatisPlusInterceptor

interceptor

=

new

MybatisPlusInterceptor();

interceptor.addInnerInterceptor(new

PaginationInnerInterceptor(DbType.MYSQL));

return

interceptor;

}

/**

旧版mp

PaginationInterceptor

**/

}2.执行分页查询@Test

public

void

testPage()

{

LambdaQueryWrapper

wrapper

=

new

LambdaQueryWrapper<>();

wrapper.ge(User::getAge,

28);

//

设置分页信息,

查第3页,

每页2条数据

Page

page

=

new

Page<>(3,

2);

//

执行分页查询

Page

userPage

=

userMapper.selectPage(page,

wrapper);

System.out.println("总记录数

=

"

+

userPage.getTotal());

System.out.println("总页数

=

"

+

userPage.getPages());

System.out.println("当前页码

=

"

+

userPage.getCurrent());

//

获取分页查询结果

List

records

=

userPage.getRecords();

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

}3.结果图片4.其他注意到,分页查询总共发出了2次SQL,一次查总记录数,一次查具体数据。若希望不查总记录数,仅查分页结果。可以通过Page的重载构造函数,指定isSearchCount为false即可public

Page(long

current,

long

size,

boolean

isSearchCount)在实际开发中,可能遇到多表联查的场景,此时BaseMapper中提供的单表分页查询的方法无法满足需求,需要自定义SQL,示例如下(使用单表查询的SQL进行演示,实际进行多表联查时,修改SQL语句即可)1.在mapper接口中定义一个函数,接收一个Page对象为参数,并编写自定义SQL//

这里采用纯注解方式。当然,若SQL比较复杂,建议还是采用XML的方式

@Select("SELECT

*

FROM

user

${ew.customSqlSegment}")

Page

selectUserPage(Page

page,

@Param(Constants.WRAPPER)

Wrapper

wrapper);2.执行查询@Test

public

void

testPage2()

{

LambdaQueryWrapper

wrapper

=

new

LambdaQueryWrapper<>();

wrapper.ge(User::getAge,

28).likeRight(User::getName,

"王");

Page

page

=

new

Page<>(3,2);

Page

userPage

=

userMapper.selectUserPage(page,

wrapper);

System.out.println("总记录数

=

"

+

userPage.getTotal());

System.out.println("总页数

=

"

+

userPage.getPages());

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

}3.结果AR模式ActiveRecord模式,通过操作实体对象,直接操作数据库表。与ORM有点类似。示例如下让实体类User继承自Modelpackage

com.example.mp.po;

import

com.baomidou.mybatisplus.annotation.SqlCondition;

import

com.baomidou.mybatisplus.annotation.TableField;

import

com.baomidou.mybatisplus.extension.activerecord.Model;

import

lombok.Data;

import

lombok.EqualsAndHashCode;

import

java.time.LocalDateTime;

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论