版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
熟练掌握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
'年龄',
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
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
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
is
not
null)
wrapper.likeRight("name",
"王").or(
q
->
q.lt("age",40)
.gt("age",20)
.isNotNull("email")
);
//
7.
(年龄小于40或者邮箱不为空)
并且名字为王姓
//
(age
<
40
OR
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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年石英或云母填充塑料项目调研分析报告
- 2024年OLED产业项目经营分析报告
- 2024年桩工机械项目营销方案
- 2024年乐器、乐器辅助用品及零件项目安全调研评估报告
- 2024年MICAPS气象图形交互系统项目建议书
- 2024年直流无刷电机项目营销方案
- 参加教研活动总结十三篇
- 禁毒主题班会活动总结
- 2024年乘用车变速器齿轮项目策划方案报告
- 课题年度个人总结
- 重磅!合肥一中回归课本读本
- GB/T 43933-2024金属矿土地复垦与生态修复技术规范
- 护士长在护理管理中的角色及作用
- 足球比赛记录表
- 诊所医疗质量管理方案及措施
- 文明施工、文物保护保证体系及保证措施
- 国家权力机关教学设计教学设计与反思
- 先进典型选树工作方案范文(精选5篇)
- 粉尘爆炸事故树、起重伤害
- 跆拳道协会章程制度
- 柱板式锚杆挡土墙施工工艺工法(完整版)
评论
0/150
提交评论