MyBatis-Plus ~ 为简化开发而生。
文章目录
https://mp.baomidou.com/

- 特性。
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作。
Hello World。
- 其对应的数据库 Schema 脚本如下:
CREATE SCHEMA `mybatis_plus` DEFAULT CHARACTER SET utf8 ;
DROP TABLE IF EXISTS user;
CREATE TABLE `mybatis_plus`.`user` (
`id` BIGINT NOT NULL COMMENT '主键 id。',
`name` VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名。',
`age` INT(11) NULL DEFAULT NULL COMMENT '年龄。',
`email` VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱。',
PRIMARY KEY (`id`));
- 其对应的数据库 Data 脚本如下:
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
真实开发中,version(乐观锁)、deleted(逻辑删除)、gmt_create、gmt_modified。
-
添加依赖。
-
引入 Spring Boot Starter 父工程。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/>
</parent>
- 引入 spring-boot-starter、spring-boot-starter-test、mybatis-plus-boot-starter、lombok、h2 依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
- 配置。
在 application.yml 配置文件中添加 H2 数据库的相关配置。
- DataSource Config
# DataSource Config
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.142.143/mybatis_plus?characterEncoding=utf-8
username: root
password: root
spring:
datasource:
driver-class-name: org.h2.Driver
schema: classpath:db/schema-h2.sql
data: classpath:db/data-h2.sql
url: jdbc:h2:mem:test
username: root
password: test
- 在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹。
package com.geek;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.geek.mapper")
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
- 编码。
编写实体类 User.java(此处使用了 Lombok 简化代码)。
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
- 编写 Mapper 类 UserMapper.java。
package com.geek.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.geek.pojo.User;
import org.springframework.stereotype.Repository;
/**
* 在对应的 Mapper 继承基本的类 BaseMapper。
*/
@Repository
public interface UserMapper extends BaseMapper<User> {
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.baomidou.mybatisplus.core.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
- 开始使用。
添加测试类,进行功能测试。
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {
@Autowired
private UserMapper userMapper;
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}
}
-
UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件。
-
控制台输出:
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
配置日志。
以上操作,我们一句 sql 都没有写。那么,是怎么查到数据的?方法从哪里来?现在所有的 sql 都是不可见的。所有必须要看日志。


CRUD。
package com.geek;
import com.geek.mapper.UserMapper;
import com.geek.pojo.User;
import org.junit.Assert;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {
@Autowired
private UserMapper userMapper;
@Test
public void testInsert() {
User user = new User();
user.setName("李");
user.setAge(25);
user.setEmail("liyifan@lyfGeek.club");
int insert = userMapper.insert(user);
System.out.println("insert = " - insert);// 1
System.out.println("user = " - user);
// user = User(id=1262353140200624129, name=李, age=25, email=liyifan@lyfGeek.club)
// 自动生成了 id。并自动回填。
}
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
// List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
// Wrapper。条件构造器。不用就 null。
List<User> userList = userMapper.selectList(null);
Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}
}
SnowFlake。雪花算法。
https://developer.twitter.com/en/docs/basics/twitter-ids
Snowflake 是一项服务,用于为 Twitter 中的对象(推文,直接消息,用户,集合,列表等)生成唯一 ID。 这些 ID 是唯一的 64 位无符号整数,它们是基于时间的,而不是顺序的。 完整 ID 由时间戳,工作编号和序列号组成。 使用 JSON 使用 API 时,务必始终使用字段 id_str 而不是 id,这一点很重要。 这是由于 Javascript 和其他使用 JSON 的语言评估大整数的方式。 如果遇到 id 和 id_str 似乎不匹配的情况,这是因为您的环境已经解析了 id 整数,从而在此过程中增加了数字。 阅读以下内容以获取有关 Twitter 如何生成其 ID 的更多信息。
/*
* Copyright (c) 2011-2020, baomidou (jobob@qq.com).
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.baomidou.mybatisplus.annotation;
import lombok.Getter;
/**
* 生成ID类型枚举类
*
* @author hubin
* @since 2015-11-10
*/
@Getter
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
*/
NONE(1),
/**
* 用户输入ID
* <p>该类型可以通过自己注册自动填充插件进行填充</p>
*/
INPUT(2),// 如果不设置就为 null。
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 分配ID (主键类型为number或string),
* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
*
* @since 3.3.0
*/
ASSIGN_ID(3),
/**
* 分配UUID (主键类型为 string)
* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
*/
ASSIGN_UUID(4),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_ID}
*/
@Deprecated
ID_WORKER(3),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_ID}
*/
@Deprecated
ID_WORKER_STR(3),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_UUID}
*/
@Deprecated
UUID(4);
private final int key;
IdType(int key) {
this.key = key;
}
}
crud 与动态 sql。
package com.geek;
import com.geek.mapper.UserMapper;
import com.geek.pojo.User;
import org.junit.Assert;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SampleTest {
@Autowired
private UserMapper userMapper;
@Test
public void testUpdate() {
User user = new User();
user.setId(6L);
user.setName("关注公众号:李");
// 根据条件自动拼接动态 sql。
// ==> Preparing: UPDATE user SET name=? WHERE id=?
//==> Parameters: 关注公众号:李(String), 6(Long)
// 参数是一个对象。
int i = userMapper.updateById(user);
System.out.println("i = " - i);
}
@Test
public void testInsert() {
User user = new User();
// user.setId(6l);
user.setName("李");
user.setAge(25);
user.setEmail("liyifan@lyfGeek.club");
int insert = userMapper.insert(user);
System.out.println("insert = " - insert);// 1
System.out.println("user = " - user);
// user = User(id=1262353140200624129, name=李, age=25, email=liyifan@lyfGeek.club)
// 自动生成了 id。并自动回填。
}
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
// List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
// Wrapper。条件构造器。不用就 null。
List<User> userList = userMapper.selectList(null);
Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}
}
自动填充。
创建时间、修改时间。都是自动化完成的,不希望手动更新。
阿里巴巴开发手册:gmt_create、gmt_modified。
数据库级别。
ON UPDATE CURRENT_TIMESTAMP

ALTER TABLE `mybatis_plus`.`user`
AUTO_INCREMENT = 7 ,
ADD COLUMN `create_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间。' AFTER `email`,
ADD COLUMN `update_time` DATETIME NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间。' AFTER `create_time`;
代码级别。

@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill= FieldFill.INSERT_UPDATE)
private Date updateTime;
- 编写处理器处理这个注解。
package com.geek.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component// 加入 IoC。
@Slf4j
public class MyMetaDataObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill...");
// default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill...");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
测试。。。
乐观锁。
乐观锁:顾名思义,十分乐观。ta 总是认为不会出现问题,无论干什么都不会上锁。如果出现了问题,就再次更新值测试。
悲观锁:顾名思义,十分悲观。ta 总是认为总是出现问题,无论干什么都先会上锁。再去操作。
version:new version。
https://mp.baomidou.com/guide/optimistic-locker-plugin.html#%E4%B9%90%E8%A7%82%E9%94%81%E6%8F%92%E4%BB%B6
意图:
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前 version。
- 更新时,带上这个 version。
- 执行更新时,set version = newVersion where version = oldVersion。
- 如果 version 不对,就更新失败。
-- 乐观锁。
-- 先查询,获得版本号 version = 1。
-- A
update user set name = "Geek", version = version - 1
where id = 2 and version = 1
-- B 线程抢先完成。这个时候
ALTER TABLE `mybatis_plus`.`user`
ADD COLUMN `version` INT(10) NULL DEFAULT 1 COMMENT '乐观锁。' AFTER `update_time`;
- User。pojo。
@Version// 乐观锁 version。
private Integer version;
- 注册组件。
package com.geek.connfig;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@MapperScan("com.geek.mapper")
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
// 注册乐观锁插件。
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
- 测试。
// 测试乐观锁成功。
@Test
public void testOptimisticLocker() {
// 查询用户信息。
User user = userMapper.selectById(6L);
// 修改用户信息。
user.setName("geek");
user.setEmail("YifanLiGeek@gmail.com");
// 执行更新。
int i = userMapper.updateById(user);
System.out.println("i = " - i);
}
/*
==> Preparing: UPDATE user SET name=?, age=?, email=?, create_time=?, update_time=?, version=? WHERE id=? AND version=?
==> Parameters: geek(String), 25(Integer), YifanLiGeek@gmail.com(String), 2020-05-03 13:49:18.0(Timestamp), 2020-05-18 22:23:34.027(Timestamp), 2(Integer), 6(Long), 1(Integer)
<== Updates: 1
*/
// 测试乐观锁失败。(多线程)。
@Test
public void testOptimisticLock2() {
// 线程 1。
User user = userMapper.selectById(6L);
user.setName("geek111");
user.setEmail("YifanLiGeek@gmail.com");
// 模拟另外一个线程执行了插队操作。
User user2 = userMapper.selectById(6L);
// 修改用户信息。
user2.setName("geek222");
user2.setEmail("YifanLiGeek@gmail.com");
userMapper.updateById(user2);// 此时 where version = 1。先更新,version 就变为了 2。
userMapper.updateById(user);// 如果没有乐观锁就会覆盖插队线程的值。
}
查询。
// 测试查询。
@Test
public void testSelectById() {
User user = userMapper.selectById(1L);
System.out.println("user = " - user);
/*
==> Preparing: SELECT id,name,age,email,create_time,update_time,version FROM user WHERE id=?
==> Parameters: 1(Long)
<== Columns: id, name, age, email, create_time, update_time, version
<== Row: 1, Jone, 18, test1@baomidou.com, 2020-05-03 05:49:18, 2020-05-03 05:49:18, 1
<== Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2bac9ba]
user = User(id=1, name=Jone, age=18, email=test1@baomidou.com, createTime=Sun May 03 13:49:18 CST 2020, updateTime=Sun May 03 13:49:18 CST 2020, version=1)
*/
}
@Test
public void testSelectBatchIds() {
List<User> userList = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
userList.forEach(System.out::println);
}
// 条件查询。map。
@Test
public void testMap() {
Map<String, Object> map = new HashMap<>();
// 自定义查询条件。
map.put("name", "李");
map.put("age", 25);
List<User> userList = userMapper.selectByMap(map);
userList.forEach(System.out::println);
}
分页查询。
-
原始 limit 分页。
-
pageHelper 第三方插件。
-
MP 内置分页插件。
// 分页插件。
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作,true 调回到首页,false 继续请求。默认 false。
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制。
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join。
// paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
- 测试。
// 分页插件。
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作,true 调回到首页,false 继续请求。默认 false。
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制。
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join。
// paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
删除。
// 测试删除。
@Test
public void testDeleteById() {
int i = userMapper.deleteById(1262361596701716482L);
System.out.println("i = " - i);
}
// 批量删除。ID。
@Test
public void testDeleteBatchIds() {
int i = userMapper.deleteBatchIds(Arrays.asList(1262353140200624129L, 1262353140200624130L, 1262360310807891969L, 1262360310807891970L));
System.out.println("i = " - i);
}
// 批量删除。map。
@Test
public void testDeleteByMap() {
Map<String, Object> map = new HashMap<>();
map.put("name", "李");
int i = userMapper.deleteByMap(map);
System.out.println("i = " - i);
}
逻辑删除。(更新操作)。
https://mp.baomidou.com/guide/logic-delete.html#%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4
- 物理删除:从数据库中直接删除。
- 逻辑删除:数据库中没有删除,而是通过一个变量来让他失效。deleted = 0 --> deleted = 1。
管理员可以查看被删除的记录。防止数据的丢失。类似于回收站。
ALTER TABLE `mybatis_plus`.`user`
ADD COLUMN `deleted` INT(1) NULL DEFAULT 0 COMMENT '逻辑删除。' AFTER `version`;
- pojo。
@TableLogic// 逻辑删除。
private Integer deleted;
- 配置。
application.yml 加入配置(如果你的默认值和mp默认的一样,该配置可无)。
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag #全局逻辑删除字段值 3.3.0开始支持,详情看下面。
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
// 测试删除。
@Test
public void testDeleteById() {
int i = userMapper.deleteById(6);
System.out.println("i = " - i);
// 逻辑删除。
// ==> Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
//==> Parameters: 6(Integer)
//<== Updates: 1
//Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1948ea69]
//i = 1
}
实际上执行的是更新操作。但在相同环境下(配置了逻辑删除),查询不出来改记录。
// 测试查询。
@Test
public void testSelectById() {
User user = userMapper.selectById(6L);
System.out.println("user = " - user);
// null。
}
~
==> Preparing: SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE id=? AND deleted=0
==> Parameters: 6(Long)
<== Total: 0
性能分析插件。
慢查询。
MP 也提供性能分析插件。如果超过这个时间就停止运行。
性能分析拦截器,用于输出每条 SQL 语句及其执行时间
该插件 3.2.0 以上版本移除。推荐使用第三方扩展,执行 SQL分析打印功能。
https://mp.baomidou.com/guide/p6spy.html
使用如下。
/*
* SQL执行效率插件。
*/
@Bean
@Profile({"dev", "test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
performanceInterceptor.setMaxTime(100);// ms。设置 sql 最大执行时间。如果超过则不执行。抛异常。
package com.geek.connfig;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@MapperScan("com.geek.mapper")
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
// 注册乐观锁插件。
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
// 分页插件。
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作,true 调回到首页,false 继续请求。默认 false。
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制。
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join。
// paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
// 逻辑删除。
// @Bean
// public ISqlInjector sqlInjector(){
// return new LogicSqlInjector();
// }
/*
* SQL执行效率插件。
*/
@Bean
@Profile({"dev", "test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100);// ms。设置 sql 最大执行时间。如果超过则不执行。
// ### Error querying database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: The SQL execution time is too large, please optimize !
// Time:19 ms - ID:com.geek.mapper.UserMapper.selectById
performanceInterceptor.setFormat(true);
// Execute SQL:SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE id=6
// Execute SQL:
// SELECT
// id,
// name,
// age,
// email,
// create_time,
// update_time,
// version,
// deleted
// FROM
// user
// WHERE
// id=6
return performanceInterceptor;
}
}
条件构造器 ~ wrapper。
https://mp.baomidou.com/guide/wrapper.html#abstractwrapper
package com.geek;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.geek.mapper.UserMapper;
import com.geek.pojo.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 java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest
public class WrapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void test01() {
// 查询 name 不为空的用户,并且邮箱不为空,年龄大于等于 12。
Wrapper<User> wrapper = new QueryWrapper<>();
((QueryWrapper<User>) wrapper)
.isNotNull("name")
.isNotNull("email")
.ge("age", 20);
userMapper.selectList(wrapper).forEach(System.out::println);
}
@Test
public void test02() {
// 查询名字为 李 的。
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "李");
User user = userMapper.selectOne(wrapper);
System.out.println("user = " - user);
}
@Test
public void test03() {
// 查询年龄在 20 ~ 30 之间的。
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age", 20, 30);
Integer integer = userMapper.selectCount(wrapper);
System.out.println("integer = " - integer);
}
@Test
public void test04() {
// 模糊。
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 左和右。%e(左)。e%(右)。
wrapper
.notLike("name", "e")
.likeRight("email", "t");
// WHERE
// name NOT LIKE '%e%'
// AND email LIKE 't%'
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
@Test
public void test05() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 子查询。
wrapper.inSql("id", "select id from user where id < 3");
List<Object> objects = userMapper.selectObjs(wrapper);
objects.forEach(System.out::println);
}
@Test
public void test06() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// id 排序。
wrapper.orderByDesc("id");
List<User> userList = userMapper.selectList(wrapper);
System.out.println("userList = " - userList);
}
}
代码生成器。
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
https://mp.baomidou.com/guide/generator.html#%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E5%99%A8
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

1680

被折叠的 条评论
为什么被折叠?



