快速上手Mybatis Plus并速通MybatisPlus所有知识点

目录

一、简介

1.1 概况

1.2 特性

二、快速入门

1.建表

2.引依赖

3.application.ymal文件

4.定义mapper继承BaseMapper

5.总结

三、Mybatis Plus的使用

1.常见注解

1.1 @TableName

1.2 @TableId

1.3 @TableField

2.常见配置

3.BaseMapper的基础CRUD方法

4.Wrapper的使用(条件构造器)

4.1Wrapper的方法集

4.2QueryWapper的使用

4.3UpdateWrapper的使用

4.4LambdaQueryWrapper

5.Mapper分页查询

6.MyBatis Plus的Service查询


一、简介

1.1 概况

大家在日常开发中应该能发现,单表的CRUD功能代码重复度很高,也没有什么难度。而这部分代码量往往比较大,开发起来比较费时。

因此,目前企业中都会使用一些组件来简化或省略单表的CRUD开发工作。目前在国内使用较多的一个组件就是MybatisPlus.

1.2 特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

这里比较重要的几点就是,MybatisPlus不会对现有项目造成影响,也就是说你原有的项目使用的是Mybatis,再导入mybatisPlus之后也是可以继续运行的。

我们平时使用MybatisPlus的场景大多数是对单表的CRUD。

二、快速入门

1.建表

DROP TABLE IF EXISTS user;CREATE TABLE `user` (`id` bigint(20) NOT NULL COMMENT '主键ID',`name` varchar(30) DEFAULT NULL COMMENT '姓名',`sex` char(1) DEFAULT NULL COMMENT '性别 0:男 1:女',`age` int(11) DEFAULT NULL COMMENT '年龄',`birthday` date DEFAULT NULL COMMENT '生日',PRIMARY KEY (`id`)
);INSERT INTO `user` VALUES (1, 'Jone', '1', 27, '2001-10-04');
INSERT INTO `user` VALUES (2, 'Jack', '0', 20, '1999-10-04');
INSERT INTO `user` VALUES (3, 'Tom', '1', 28, '1996-08-12');
INSERT INTO `user` VALUES (4, 'Sandy', '1', 21, '2001-10-04');
INSERT INTO `user` VALUES (5, 'Billie', '0', 24, '1992-09-07');
INSERT INTO `user` VALUES (6, 'Jackson', '0', 18, '1996-08-12');
INSERT INTO `user` VALUES (7, 'Hardy', '1', 25, '1992-09-07');
INSERT INTO `user` VALUES (8, 'Rose', '1', 21, '1992-09-07');
INSERT INTO `user` VALUES (9, 'June', '0', 28, '1992-09-07');
INSERT INTO `user` VALUES (10, 'Aidan', '0', 17, '2001-10-04');

2.引依赖

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version>
</dependency>

3.application.ymal文件

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=GMT%2b8username: rootpassword: admin
#配置日志
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4.定义mapper继承BaseMapper

5.总结

三、Mybatis Plus的使用

1.常见注解

在刚刚的入门案例中,我们仅仅引入了依赖,继承了BaseMapper就能使用MybatisPlus,非常简单。但是问题来了: MybatisPlus如何知道我们要查询的是哪张表?表中有哪些字段呢?

大家回忆一下,UserMapper在继承BaseMapper的时候指定了一个泛型:

泛型中的User就是与数据库对应的PO.

MybatisPlus就是根据PO实体的信息来推断出表的信息,从而生成SQL的。默认情况下:

  • MybatisPlus会把PO实体的类名驼峰转下划线作为表名

  • MybatisPlus会把PO实体的所有变量名驼峰转下划线作为表的字段名,并根据变量类型推断字段类型

  • MybatisPlus会把名为id的字段作为主键

但很多情况下,默认的实现与实际场景不符,因此MybatisPlus提供了一些注解便于我们声明表信息。

那万一你的表名、字段名、主键名都和数据库中的表、字段、主键都不一样,那Mybatis Plus怎么映射过去呢?(虽然说我们开发中一般不会故意出现这种情况,因为不规范,但有时候就是无法避免)

这时候就要使用MybatisPlus提供给我们的注释了

1.1 @TableName

  • 描述:表名注解,标识实体类对应的表

  • 使用位置:实体类

@TableName("user")
public class User {private Long id;private String name;
}

 该注解还有其他的属性配置,如下表:

value

String

""

表名

schema

String

""

schema

keepGlobalPrefix

boolean

false

是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)

resultMap

String

""

xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)

autoResultMap

boolean

false

是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)

excludeProperty

String[]

{}

需要排除的属性名 @since 3.3.1

1.2 @TableId

  • 描述:主键注解,标识实体类中的主键字段

  • 使用位置:实体类的主键字段

@TableName("user")
public class User {@TableIdprivate Long id;private String name;
}

TableId注解支持两个属性:

属性

类型

必须指定

默认值

描述

value

String

""

表名

type

Enum

IdType.NONE

指定主键类型

IdType支持的类型有:

描述

AUTO

数据库 ID 自增

NONE

无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)

INPUT

insert 前自行 set 主键值

ASSIGN_ID

分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)

ASSIGN_UUID

分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)

ID_WORKER

分布式全局唯一 ID 长整型类型(please use ASSIGN_ID)

UUID

32 位 UUID 字符串(please use ASSIGN_UUID)

ID_WORKER_STR

分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

这里比较常见的有三种:

  • AUTO:利用数据库的id自增长

  • INPUT:手动生成id

  • ASSIGN_ID:雪花算法生成Long类型的全局唯一id,这是默认的ID策略

1.3 @TableField

说明:普通字段注解

@TableName("user")
public class User {@TableIdprivate Long id;private String name;private Integer age;@TableField("isMarried")private Boolean isMarried;@TableField("concat")private String concat;
}

一般情况下我们并不需要给字段添加@TableField注解,一些特殊情况除外:

  • 成员变量名与数据库字段名不一致

  • 成员变量是以isXXX命名,按照JavaBean的规范,MybatisPlus识别字段时会把is去除,这就导致与数据库不符。

  • 成员变量名与数据库一致,但是与数据库的关键字冲突。使用@TableField注解给字段名添加转义字符:``

支持的其它属性如下:

属性

类型

必填

默认值

描述

value

String

""

数据库字段名

exist

boolean

true

是否为数据库表字段

condition

String

""

字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window)

update

String

""

字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)

insertStrategy

Enum

FieldStrategy.DEFAULT

举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)

updateStrategy

Enum

FieldStrategy.DEFAULT

举例:IGNORED update table_a set column=#{columnProperty}

whereStrategy

Enum

FieldStrategy.DEFAULT

举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>

fill

Enum

FieldFill.DEFAULT

字段自动填充策略

select

boolean

true

是否进行 select 查询

keepGlobalFormat

boolean

false

是否保持使用全局的 format 进行处理

jdbcType

JdbcType

JdbcType.UNDEFINED

JDBC 类型 (该默认值不代表会按照该值生效)

typeHandler

TypeHander

类型处理器 (该默认值不代表会按照该值生效)

numericScale

String

""

指定小数点后保留的位数

2.常见配置

MybatisPlus也支持基于yaml文件的自定义配置,详见官方文档:

https://www.baomidou.com/pages/56bac0/#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE

大多数的配置都有默认值,因此我们都无需配置。但还有一些是没有默认值的,例如:

  • 实体类的别名扫描包

  • 全局id类型

mybatis-plus:type-aliases-package: com.scau.mp.domain.poglobal-config:db-config:id-type: auto # 全局id类型为自增长

需要注意的是,MyBatisPlus也支持手写SQL的,而mapper文件的读取地址可以自己配置:

mybatis-plus:mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,当前这个是默认值。

3.BaseMapper的基础CRUD方法

官方文档案例如下:https://baomidou.com/pages/49cc81/#mapper-crud-接口

代码测试用例:

@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo01_BaseMapper的基本CURD {@Autowiredprivate UserMapper userMapper;/*** 新增* INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )*/@Testpublic void insert() {User user = new User(100L, "Ken", "0",20);userMapper.insert(user);}/*** 修改* UPDATE user SET name=?, age=?, email=? WHERE id=?*/@Testpublic void update() {User user = new User(100L, "Kevin", "0", 25);userMapper.updateById(user);}/*** 根据id查询* SELECT id,name,age,email FROM user WHERE id=?*/@Testpublic void selectById() {User user = userMapper.selectById(100L);System.out.println(user);}/*** 根据一批id查询* SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )*/@Testpublic void selectBatchIds() {List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));for (User user : userList) {System.out.println(user);}}/*** 根据条件查询数据* SELECT id,name,age,email FROM user WHERE name = ? AND id = ?*/@Testpublic void selectByMap() {// 封装条件HashMap<String, Object> param = new HashMap<>();param.put("id",10L);param.put("name","Kevin");// 根据条件查询,map中的多个条件是并列关系 id=10 and name='小灰灰'List<User> userList = userMapper.selectByMap(param);for (User user : userList) {System.out.println(user);}}/*** 根据id删除* DELETE FROM user WHERE id=?*/@Testpublic void deleteById() {userMapper.deleteById(100L);}/*** 根据id删除一批* DELETE FROM user WHERE id IN ( ? , ? , ? )*/@Testpublic void deleteBatchIds() {userMapper.deleteBatchIds(Arrays.asList(1, 2, 3));}/*** 根据条件删除数据* DELETE FROM user WHERE name = ? AND id = ?*/@Testpublic void deleteByMap() {// 封装条件HashMap<String, Object> param = new HashMap<>();param.put("id",100L);param.put("name","Kevin");userMapper.deleteByMap(param);}
}

4.Wrapper的使用(条件构造器)

通过BaseMapper提供的一些方法我们可以完成一些基本的CRUD,但无法完成复杂条件的查询;对于复杂条件的查询,MyBatis Plus提供了Wrapper接口来处理;

Wrapper是MyBatis Plus提供的一个条件构造器,主要用于构建一系列条件,当Wrapper构建完成后,可以使用Wrapper中的条件进行查询、修改、删除等操作;

官方文档如下:条件构造器 | MyBatis-Plus

Wrapper是条件构造抽象类,最顶端父类,其主要实现类有如下:

AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件

        QueryWrapper : Query条件封装
        UpdateWrapper : Update条件封装
        AbstractLambdaWrapper : 使用Lambda语法
                LambdaQueryWrapper :基于Lambda语法使用的查询Wrapper
                LambdaUpdateWrapper : 基于Lambda语法使用的更新Wrapper

4.1Wrapper的方法集

方法名解释示例
eq等于 =eq("name", "老王") ---> name = '老王' 
ne不等于 <>ne("name", "老王") ---> name <> '老王' 
gt大于 >gt("age", 18) ---> age > 18 
ge大于等于 >=ge("age", 18) ---> age >= 18 
lt小于 <lt("age", 18) ---> age < 18 
le小于等于 <=le("age", 18) ---> age <= 18 
betweenbetween 值1 and 值2between("age", 18, 30) ---> age between 18 and 30 
notBetweennot between 值1 and 值2notBetween("age", 18, 30) ---> age not between 18 and 30 
likeLIKE ‘%值%’like("name", "王") ---> name like '%王%' 
notLikeNOT LIKE ‘%值%’notLike("name", "王") ---> name not like '%王%' 
likeLeftLIKE ‘%值’likeLeft("name", "王") ---> name like '%王' 
likeRightLIKE ‘值%’likeRight("name", "王") ---> name like '王%' 
isNull字段 IS NULLisNull("name") ---> name is null 
isNotNull字段 IS NOT NULLisNotNull("name") ---> name is not null 
in字段 IN (v0, v1, …)in("age", 1, 2, 3) ---> age in (1,2,3) 
notIn字段 NOT IN (v0, v1, …)notIn("age", 1, 2, 3) ---> age not in (1,2,3) 
inSql字段 IN ( sql语句 )inSql("id", "select id from table where id < 3") ---> id in (select id from table where id < 3) 
notInSql字段 NOT IN ( sql语句 )notInSql("id", "select id from table where id < 3") ---> id not in (select id from table where id < 3) 
groupBy分组:GROUP BY 字段, …groupBy("id", "name") ---> group by id,name 
orderByAsc排序:ORDER BY 字段, … ASCorderByAsc("id", "name") ---> order by id ASC,name ASC 
orderByDesc排序:ORDER BY 字段, … DESCorderByDesc("id", "name") ---> order by id DESC,name DESC 
havingHAVING ( sql语句 )having("sum(age) > {0}", 11) ---> having sum(age) > 11 
func主要解决条件拼接func(i -> if(true) {i.eq("id", 1)} else {i.ne ("id", 1)}) 
or拼接 OReq("id",1).or().eq("name","老王") ---> id = 1 or name = '老王' 

这些方法不用背,要构造Wrapper的时候查官方文档即可:

条件构造器 | MyBatis-Plus

4.2QueryWapper的使用

创建Wrapper对象:

  • Wrappers静态方法:
    • public static <T> QueryWrapper<T> query()
  • 通过QueryWrapper对象的构造方法:
    • public QueryWrapper()

代码如下:


@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo02_Wrapper基本方法 {@Autowiredprivate UserMapper userMapper;/*** QueryMapper的创建* SELECT id,name,age,email FROM user*/@Testpublic void test1() {// 创建QueryMapper,默认情况下查询所有数据QueryWrapper<User> wrapper = Wrappers.query();QueryWrapper<User> wrapper2 = new QueryWrapper<>();List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);}
}

其他方法的使用:

@Test
public void test2() {QueryWrapper<User> wrapper = Wrappers.query();// name ='Jack'
//        wrapper.eq("name","Jack");/*参数1: 是否要进行name条件的拼接*/String name = "Jack";wrapper.eq(name != null, "name", name);// name != 'Jack'
//        wrapper.ne("name","Jack");// age > 20
//        wrapper.gt("age",20);// age < 20
//        wrapper.lt("age",20);// age=20
//        wrapper.lt("age",20);// age between 20 and 24
//        wrapper.between("age",20,24);// age not between 20 and 24
//        wrapper.notBetween("age",20,24);// name like "%J%"          自动拼接左右的%
//        wrapper.like("name","J");// name not like "%J%"
//        wrapper.notLike("name","J");// name like "%J"
//        wrapper.likeLeft("name","J");// name like 'J%'
//        wrapper.likeRight("name","J");// name is null
//        wrapper.isNull("name");// name is not null
//        wrapper.isNotNull("name");// name in ('Jack','Tom','Jone')
//        wrapper.in("name","Jack","Tom","Jone");// name not in ('Jack','Tom','Jone')
//        wrapper.notIn("name","Jack","Tom","Jone");List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);
}

4.3UpdateWrapper的使用

代码如下:


@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo05_UpdateWrapper {@Autowiredprivate UserMapper userMapper;@Testpublic void test1() throws Exception {UpdateWrapper<User> wrapper = Wrappers.update();// UpdateWrapper也是AbstractWrapper的子类,因此也具备一些基本的查询方法wrapper.like("name", "J");List<User> userList = userMapper.selectList(wrapper);for (User user : userList) {System.out.println(user);}}/*** 第一种方法: 使用wrapper来修改,并且指定查询条件** @throws Exception*/@Testpublic void test2() throws Exception {UpdateWrapper<User> wrapper = Wrappers.update();wrapper.set("name", "Jackson");wrapper.set("age", "16");wrapper.set("sex", "1");wrapper.eq("id", 2L);// SQL: UPDATE user SET name=?, sex=?, age=? WHERE (id = ?)userMapper.update(null, wrapper);}/*** 第二种方法: 使用wrapper来封装条件,使用entity来封装修改的数据** @throws Exception*/@Testpublic void test3() throws Exception {UpdateWrapper<User> wrapper = Wrappers.update();wrapper.eq("id", 2L);User user = new User(null, "Jack", "0", 28);// SQL: UPDATE user SET name=?, sex=?, age=? WHERE (id = ?)userMapper.update(user, wrapper);}/*** 第三种方法: Wrappers.update(user)传递查询的条件,使用wrapper来修改** @throws Exception*/@Testpublic void test4() throws Exception {User user = new User();user.setId(1L);// user当做查询条件UpdateWrapper<User> wrapper = Wrappers.update(user);wrapper.set("name", "xiaohui");wrapper.set("sex", "0");wrapper.set("age", "22");// SQL : UPDATE user SET name=?,sex=?,age=? WHERE id=?userMapper.update(null, wrapper);}/*** setSql方法** @throws Exception*/@Testpublic void test5() throws Exception {UpdateWrapper<User> wrapper = Wrappers.update();wrapper.setSql("name='abc',sex='0',age=18 where id=1");// SQL: UPDATE user SET name='abc',sex='0',age=18 where id=1userMapper.update(null, wrapper);}
}

4.4LambdaQueryWrapper

无论是QueryWrapper还是UpdateWrapper在构造条件的时候都需要写死字段名称,会出现字符串魔法值。这在编程规范中显然是不推荐的。 那怎么样才能不写字段名,又能知道字段名呢?

其中一种办法是基于变量的gettter方法结合反射技术。因此我们只要将条件对应的字段的getter方法传递给MybatisPlus,它就能计算出对应的变量名了。而传递方法可以使用JDK8中的方法引用Lambda表达式。 因此MybatisPlus又提供了一套基于Lambda的Wrapper,包含两个:

  • LambdaQueryWrapper

  • LambdaUpdateWrapper

分别对应QueryWrapper和UpdateWrapper

@Test
void testLambdaQueryWrapper() {// 1.构建条件 WHERE username LIKE "%o%" AND balance >= 1000QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.lambda().select(User::getId, User::getUsername, User::getInfo, User::getBalance).like(User::getUsername, "o").ge(User::getBalance, 1000);// 2.查询List<User> users = userMapper.selectList(wrapper);users.forEach(System.out::println);
}

5.Mapper分页查询

在MyBatis中提供有Page对象来帮助我们实现分页查询,在Page对象中有如下成员:

方法描述
getRecords()查询当前页的数据记录,返回类型是列表 
getCurrent()返回当前页码 
getTotal()获取总记录数 
getSize()获取页面大小 
getPages()获取总页数 
hasPrevious()判断当前页是否有上一页 
hasNext()判断当前页是否有下一页 

而在MybatisPlus中则是使用分页插件来实现分页查询的,因此我们首先要配置MyBatisPlus的分页插件;

  • 配置分页插件:

@Configuration
@MapperScan("com.scau.mapper")          // mapper接口的所在位置
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}

在BaseMapper中主要提供有如下方法来完成分页查询:

<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper):


参数1:分页配置类
参数2:分页查询条件
解释:根据分页配置和分页查询条件来完成分页查询,当前页数据为指定类型

<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper)


参数1:分页配置类
参数2:分页查询条件
解释:根据分页配置和分页查询条件来完成分页查询,当前页数据为Map类型

  • 1)无条件分页查询:

@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo06_BaseMapper的分页查询 {@Autowiredprivate UserMapper userMapper;/*** 无条件分页查询* @throws Exception*/@Testpublic void test1() throws Exception {// 封装分页信息Page<User> page = new Page<>(1,3);/*执行分页查询,并将结果封装到page中参数1: 分页配置参数2: 查询条件*/userMapper.selectPage(page, null);// 当前页数据List<User> pageData = page.getRecords();for (User user : pageData) {System.out.println(user);}System.out.println("------------");System.out.println("当前页:" + page.getCurrent());System.out.println("每页显示的条数:" + page.getSize());System.out.println("总记录数:" + page.getTotal());System.out.println("总页数:" + page.getPages());System.out.println("是否有上一页:" + page.hasPrevious());System.out.println("是否有下一页:" + page.hasNext());}
}

查询结果如下:

# 首先查询总记录数
==>  Preparing: SELECT COUNT(*) FROM user
==> Parameters: 
<==    Columns: COUNT(*)
<==        Row: 10
<==      Total: 1# 再查询分页
==>  Preparing: SELECT id,name,sex,age FROM user LIMIT ?
==> Parameters: 3(Long)
<==    Columns: id, name, sex, age
<==        Row: 1, Jone, 1, 27
<==        Row: 2, Jack, 0, 20
<==        Row: 3, Tom, 1, 28
<==      Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@226eba67]
User(id=1, name=Jone, sex=1, age=27)
User(id=2, name=Jack, sex=0, age=20)
User(id=3, name=Tom, sex=1, age=28)
------------
当前页:1
每页显示的条数:3
总记录数:10
总页数:4
是否有上一页:false
是否有下一页:true
2022-11-15 15:28:16.946  INFO 8724 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2022-11-15 15:28:16.948  INFO 8724 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.Process finished with exit code 0

2)带条件查询

/*** 带条件分页查询** @throws Exception*/
@Test
public void test2() throws Exception {QueryWrapper<User> wrapper = Wrappers.query();wrapper.like("name", "a");// 封装分页信息Page<User> page = new Page<>(1, 3);/*执行分页查询,并将结果封装到page中参数1: 分页配置参数2: 查询条件*/userMapper.selectPage(page, wrapper);// 当前页数据List<User> pageData = page.getRecords();for (User user : pageData) {System.out.println(user);}System.out.println("------------");System.out.println("当前页:" + page.getCurrent());System.out.println("每页显示的条数:" + page.getSize());System.out.println("总记录数:" + page.getTotal());System.out.println("总页数:" + page.getPages());System.out.println("是否有上一页:" + page.hasPrevious());System.out.println("是否有下一页:" + page.hasNext());
}

查询结果如下:

==>  Preparing: SELECT COUNT(*) FROM user WHERE (name LIKE ?)
==> Parameters: %a%(String)
<==    Columns: COUNT(*)
<==        Row: 5
<==      Total: 1
==>  Preparing: SELECT id,name,sex,age FROM user WHERE (name LIKE ?) LIMIT ?
==> Parameters: %a%(String), 3(Long)
<==    Columns: id, name, sex, age
<==        Row: 2, Jack, 0, 20
<==        Row: 4, Sandy, 1, 21
<==        Row: 6, Jackson, 0, 18
<==      Total: 3
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@58a2b4c]
User(id=2, name=Jack, sex=0, age=20)
User(id=4, name=Sandy, sex=1, age=21)
User(id=6, name=Jackson, sex=0, age=18)
------------
当前页:1
每页显示的条数:3
总记录数:5
总页数:2
是否有上一页:false
是否有下一页:true

3)将分页结果以map的形式返回

/*** 查询结果以Map返回** @throws Exception*/
@Test
public void test3() throws Exception {// 封装分页信息Page page = new Page<>(1, 3);userMapper.selectMapsPage(page, null);// 每一条记录都是一个HashMapList<HashMap<String,Object>> pageData = page.getRecords();for (HashMap userMap : pageData) {System.out.println(userMap);}System.out.println("------------");System.out.println("当前页:" + page.getCurrent());System.out.println("每页显示的条数:" + page.getSize());System.out.println("总记录数:" + page.getTotal());System.out.println("总页数:" + page.getPages());System.out.println("是否有上一页:" + page.hasPrevious());System.out.println("是否有下一页:" + page.hasNext());
}

6.MyBatis Plus的Service查询

通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行、remove删除、list 查询集合、page查询分页

架构图如下:

使用步骤:

  • 1)定义一个UserService接口继承与MyBatisPlus提供的IService接口:

public interface IUserService extends IService<User> {
}
  • 2)定义一个UserService的实现类,并且继承与MyBatisPlus提供的ServiceImpl:
  • 
    @Service("userService")
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {}
    

    常用的service方法集:

  • 新增:

 default boolean save(T entity):新增记录

boolean saveBatch(Collection<T> entityList):批量插入

saveBatch(Collection<T> entityList, int batchSize):一次性批量插入batchSize条记录

  • 删除:

boolean removeById(Serializable id):根据id删除

boolean removeByMap(Map<String, Object> columnMap):根据条件删除

boolean remove(Wrapper<T> queryWrapper):使用Wrapper封装条件删除

boolean removeByIds(Collection<? extends Serializable> idList):删除一批

  • 修改:

boolean updateById(T entity):修改

boolean update(Wrapper<T> updateWrapper):根据Wrapper修改

boolean update(T entity, Wrapper<T> updateWrapper):使用Wrapper查询出结果,修改为entity

boolean updateBatchById(Collection<T> entityList):批量修改

updateBatchById(Collection<T> entityList, int batchSize):一次性批量修改batchSize条记录

boolean saveOrUpdate(T entity):如果id存在则修改,如果id不存在则新增

  • 查询:

T getById(Serializable id):根据id查询

List<T> listByIds(Collection<? extends Serializable> idList):根据一批id查询多条记录

List<T> listByMap(Map<String, Object> columnMap):根据条件查询多条记录

T getOne(Wrapper<T> queryWrapper):根据Wrapper查询一条记录,如果查询到多条则抛出异常

T getOne(Wrapper<T> queryWrapper, boolean throwEx):根据Wrapper查询一条记录,通过throwEx决定是否抛出异常

int count():查询总记录数

int count(Wrapper<T> queryWrapper):根据条件查询总记录数

  • 分页:

<E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper):带条件分页查询,当前页数据为T类型

<E extends IPage<T>> E page(E page):无条件分页

List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper):带条件分页查询,当前页数据为HashMap类型

List<Map<String, Object>> listMaps():无条件分页

测试代码如下:


@SpringBootTest(classes = MyBatisPlusApplication.class)
@RunWith(SpringRunner.class)
public class Demo07_Service查询 {@Autowiredprivate IUserService userService;/*** 新增** @throws Exception*/@Testpublic void test1() throws Exception {User user = new User(null, "xiaohui", "0", 20);userService.save(user);}/*** 如果id存在则修改,不存在则新增** @throws Exception*/@Testpublic void test2() throws Exception {User user = new User(1L, "xiaohui", "0", 20);userService.saveOrUpdate(user);}/*** 根据id删除** @throws Exception*/@Testpublic void test3() throws Exception {userService.removeById(1L);}/*** 根据id修改** @throws Exception*/@Testpublic void test4() throws Exception {User user = new User(1L, "xiaolan", "1", 18);userService.updateById(user);}/*** 根据id查询** @throws Exception*/@Testpublic void test5() throws Exception {User user = userService.getById(1L);System.out.println(user);}/*** 查询列表** @throws Exception*/@Testpublic void test6() throws Exception {QueryWrapper<User> wrapper = Wrappers.query();wrapper.in("id", "1", "2");// 查询所有
//        List<User> userList = userService.list();// 通过wrapper查询List<User> userList = userService.list(wrapper);for (User user : userList) {System.out.println(user);}}/*** 查询总记录数** @throws Exception*/@Testpublic void test7() throws Exception {QueryWrapper<User> wrapper = Wrappers.query();wrapper.like("name", "a");// 查询总记录数
//        int count = userService.count();// 根据条件查询总记录数int count = userService.count(wrapper);System.out.println(count);}/*** 分页查询(当前页类型为指定类型)** @throws Exception*/@Testpublic void test8() throws Exception {Page<User> page = new Page<>(1, 3);userService.page(page);// 当前页数据List<User> pageData = page.getRecords();for (User user : pageData) {System.out.println(user);}System.out.println("------------");System.out.println("当前页:" + page.getCurrent());System.out.println("每页显示的条数:" + page.getSize());System.out.println("总记录数:" + page.getTotal());System.out.println("总页数:" + page.getPages());System.out.println("是否有上一页:" + page.hasPrevious());System.out.println("是否有下一页:" + page.hasNext());}/*** 分页查询(当前页结果为HashMap类型)** @throws Exception*/@Testpublic void test9() throws Exception {Page page = new Page<>(1, 3);userService.pageMaps(page);// 当前页数据List<HashMap<String, Object>> pageData = page.getRecords();for (HashMap userMap : pageData) {System.out.println(userMap);}System.out.println("------------");System.out.println("当前页:" + page.getCurrent());System.out.println("每页显示的条数:" + page.getSize());System.out.println("总记录数:" + page.getTotal());System.out.println("总页数:" + page.getPages());System.out.println("是否有上一页:" + page.hasPrevious());System.out.println("是否有下一页:" + page.hasNext());}/*** 链式查询** @throws Exception*/@Testpublic void test10() throws Exception {QueryChainWrapper<User> chainWrapper = userService.query();// SQL: SELECT id,name,age FROM user WHERE (id IN (?,?,?) AND name LIKE ?)List<User> userList = chainWrapper.select("id", "name", "age").in("id", "1", "2", "3").like("name", "a").list();for (User user : userList) {System.out.println(user);}}/*** 链式修改** @throws Exception*/@Testpublic void test11() throws Exception {UpdateChainWrapper<User> chainWrapper = userService.update();// SQL: UPDATE user SET age=? WHERE (id IN (?,?) OR sex = ?)chainWrapper.in("id","1","2").or().eq("sex","0").set("age",20).update();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/19615.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

使用代理解决前端跨域问题详解

目录 前言1. 什么是跨域问题&#xff1f;1.1 同源策略的定义1.2 跨域问题的表现 2. 解决跨域问题的常见方法3. 在 Vite 中配置代理解决跨域问题3.1 环境准备3.2 配置代理3.2.1 配置基础路径3.2.2 配置 Vite 代理3.2.3 参数解释 3.3 验证代理功能 4. 深入分析与注意事项4.1 代理…

使用MaxKB搭建知识库问答系统并接入个人网站(halo)

首发地址&#xff08;欢迎大家访问&#xff09;&#xff1a;使用MaxKB搭建知识库问答系统并接入个人网站 前言 从OpenAI推出ChatGPT到现在&#xff0c;大模型已经渗透到各行各业&#xff0c;大模型也逐渐趋于平民化&#xff1b;从最开始对其理解、生成、强大的知识积累的惊叹&…

查看台式机主机支持的最大分辨率 | 显卡和显示器

通过检查显卡规格和型号&#xff0c;确认主机支持最大分辨率。 方法1&#xff1a;设置 在设置 -> 系统 -> 屏幕 及其内的高级显示设置 设置 -> 显示 方法2&#xff1a;cmd 在运行中输入“devmgmt.msc”&#xff0c;进入设备管理器界面&#xff0c;点击展开“显示适配…

若依权限控制

springbootvue2项目中的权限控制(若依项目) 步骤: 1.登录管理员账号,为普通用户增加权限按钮 绿色部分为权限控制字符 2.在后端对应的方法上增加权限控制(这里以删除操作为例):PreAuthorize(“ss.hasPermi(‘area:store:remove’)”) 3.在前端对应的按钮上增加权限控制:v-ha…

5G的SUCI、SUPI、5G-GUTI使用场景及关系

使用场景(来源于对23.501、23.502、33.501、23.003的理解) 1、UE初始注册时&#xff0c;根据HN Public Key把SUPI加密成SUCI&#xff0c;并发送初始注册请求 2、AMF转发SUCI给AUSF和UDM进行认证&#xff0c;并获取解密后的SUPI 3、AMF根据SUPI生成一个5G-GUTI&#xff0c;并保…

本地部署 excalidraw

本地部署 excalidraw 0. 引言1. 本地部署 excalidraw2. 访问 excalidraw 0. 引言 Excalidraw 编辑器是一款开源虚拟手绘白板&#xff0c;支持协作且端到端加密。 1. 本地部署 excalidraw git clone https://github.com/excalidraw/excalidraw.git; cd excalidrawvi docker-c…

企业数字化转型的战略指南:物联网与微服务架构的深度融合及应用解析

新时代下的企业数字化转型挑战与机遇 在当前全球经济和技术迅猛发展的背景下&#xff0c;企业数字化转型成为保持竞争力和创新的关键战略。物联网&#xff08;IoT&#xff09; 的兴起为企业提供了无数新的数据来源和运营模式&#xff0c;然而&#xff0c;如何有效整合这些数据…

vue3+vant实现弹幕循环播放~

1、效果图 <!-- 弹幕 --> <div style"height: 88px"><van-barragev-model"list"duration"5000":rows"rows":gap"gap":loop"loop"style"--move-distance: -345px" ><div class&quo…

字母异位词分组(java)

题目描述 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单shilie 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "n…

解决ValueError: Custom function inv is not defined in `extra_sympy_mappings`.

一、报错问题 ValueError: Custom function inv is not defined in extra_sympy_mappings. You can define it with, e.g., model.set_params(extra_sympy_mappings{inv: lambda x: 1/x}), where lambda x: 1/x is a valid SymPy function defining the operator. You can als…

深度学习基础练习:代码复现transformer重难点

2024/11/10-2024/11/18: 主要对transformer一些比较难理解的点做了一些整理&#xff0c;希望对读者有所帮助。 前置知识&#xff1a; 深度学习基础练习&#xff1a;从pytorch API出发复现LSTM与LSTMP-CSDN博客 【神经网络】学习笔记十四——Seq2Seq模型-CSDN博客 【官方双语】一…

GIS与Web开发结合的产物:WebGIS

WebGIS&#xff0c;其实是利用Web开发技术结合地理信息系统&#xff08;GIS&#xff09;的产物&#xff0c;它是一种通过Internet实现GIS交互操作和服务的最佳途径。 WebGIS通过图形化界面直观地呈现地理信息和特定数据&#xff0c;具有可扩展性和跨平台性。 它提供交互性&am…

PAT甲级 1071 Speech Patterns(25)

&#x1f7e0; 题目大意&#x1f7e2; 思路分析&#x1f535; 代码改进&#x1f7e4; 总结提炼 原题链接 &#x1f7e0; 题目大意 给定一串字符串&#xff0c;要求找出字符串中出现次数最多的单词。 输入 输入一行字符串&#xff0c;字符串长度不超过1048576&#xff0c;所有…

基于单片机的多功能环保宠物窝设计

本设计基于单片机设计的多功能环保宠物窝&#xff0c;利用温湿度传感器、压力传感模块、气味传感模块、红外测温传感器、通信模块、显示模块、清扫部件等&#xff0c;使其能够实现自动检测并调节温湿度、补充宠物食物、检测宠物体温健康并出现异常时进行报警、自动清扫消毒宠物…

Spring AOP面向切面的编程

一、场景设定和问题复现: 1.准备AOP项目:spring-aop-annotation pom.xml <dependencies><!--spring context依赖--><!--当你引入Spring Context依赖之后&#xff0c;表示将Spring的基础依赖引入了--><dependency><groupId>org.springframework…

已有docker增加端口号,不用重新创建Docker

已有docker增加端口号&#xff0c;不用重新创建Docker 1. 整体描述2. 具体实现2.1 查看容器id2.2 停止docker服务2.3 修改docker配置文件2.4 重启docker服务 3. 总结 1. 整体描述 docker目前使用的非常多&#xff0c;但是每次更新都需要重新创建docker&#xff0c;也不太方便&…

【WSL+Kali】进行系统升级时在 Setting up libc6:amd64 (2.37-15) ... 卡住不动

问题描述 当尝试执行以下命令进行系统升级时&#xff1a; sudo apt upgrade升级进程在以下步骤中卡住不动&#xff1a; Setting up libc6:amd64 (2.37-15) ...重启系统后&#xff0c;该问题仍然存在&#xff0c;如下图所示&#xff1a; 原因分析 apt命令是一个用于处理包的…

三、谷粒商城- Spring Cloud Alibaba(3)

&#x1f33b;&#x1f33b; 目录 &#x1f33b;&#x1f33b; 一、SpringCloud Alibaba1.1、SpringCloud Alibaba 简介1.2、SpringCloud Alibaba-Nacos[作为注册中心]1.2.1 将微服务注册到 nacos 中1.2.2 服务注册到 nacos&#xff0c;远程调用 1.3、SpringCloud Alibaba-Naco…

SpringFramework实战指南

1. SpringIoC容器和核心概念 1.1. Spring IoC容器和容器实现 1.1.1. SpringIoc容器接口 BeanFactory 接口提供了一种高级配置机制&#xff0c;能够管理任何类型的对象&#xff0c;是SpringIoC容器标准化超接口&#xff01; ApplicationContext 是 BeanFactory 的子接口。它扩…

【油猴脚本】00013 案例 Tampermonkey油猴脚本, 仅用于学习,不要乱搞。添加UI交互实现自定义,更多页抓取数据(1),JavaScript爬虫HTML+Css+JavaScript编写

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【油…