@[TOC]
1 简介
MyBatis-Plus是一个MyBatis的增强工具
,在MyBatis的基础上只做增强不做改变
,为简化开发、提高效率而生
。MyBatis-Plus提供了通用的mapper和service,可以在不编写任何SQL语句的情况下,快速的实现对单表
的CRUD、批量、逻辑删除、分页等操作。
2 初始化项目
2.1引入pom
<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>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 简化实体类开发 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
2.2 引入lombok插件
2.3 配置信息
spring:
# 配置数据源信息
datasource:
# 配置数据源类型(spring默认的数据源)
type: com.zaxxer.hikari.HikariDataSource
# 配置连接数据库信息(配置驱动类,版本为8)
driver-class-name: com.mysql.cj.jdbc.Driver
#mysql8版本的写法
url: jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
username: root
password: yuan159951.
# mysql5版本的写法
# driver-class-name: com.mysql.jdbc.Driver
# url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
2.4 创建实体类
import lombok.Data;
@Data //lombok注解
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
2.5 创建mapper
import com.yunfeng.mybatisplus.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}
2.6 配置注解MapperScan
@SpringBootApplication
//扫描mapper接口所在的包
@MapperScan("com.yunfeng.mybatisplus.mapper")
public class MybatisplusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisplusApplication.class, args);
}
}
2.7 编写测试类
import com.yunfeng.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MybatisPlusTest {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
//selectList()根据MP内置的条件构造器查询一个list集合,null表示没有条件,即查询所有
userMapper.selectList(null).forEach(System.out::println);
}
}
2.8 配置MyBatis日志
# 配置MyBatis日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
3 测试基本的CRUD
3.1 新增
@Test
public void testInsert(){
User user = new User();
user.setName("张三");
user.setAge(18);
user.setEmail("302976975@qq.com");
int row = userMapper.insert(user);
System.out.println("row = " + row);
System.out.println(user.getId());
}
3.2 查询
@Test
public void testSelectById(){
// User user = userMapper.selectById(1L);
// System.out.println(user);
// List<Long> longs = Arrays.asList(1l, 2l, 3l);
// List<User> users = userMapper.selectBatchIds(longs);
// System.out.println("users = " + users);
// Map<String,Object> map = new HashMap<>();
// map.put("name","jack");
// map.put("age",20);
// List<User> users = userMapper.selectByMap(map);
// System.out.println("users = " + users);
List<User> users = userMapper.selectList(null);
System.out.println("users = " + users);
}
3.3 修改
@Test
public void testUpdateById(){
User user = new User();
user.setId(4L);
user.setName("李四");
int result = userMapper.updateById(user);
System.out.println("受影响行数:"+result);
}
3.4 删除
@Test
public void testDeleteById(){
// int result = userMapper.deleteById(1595594324846141442L);
// System.out.println("受影响行数:"+result);
// Map<String,Object> map = new HashMap<>();
// map.put("name","张三");
// map.put("age",18);
// userMapper.deleteByMap(map);
List<Long> longs = Arrays.asList(1l, 2l, 3l);
int rows = userMapper.deleteBatchIds(longs);
System.out.println("rows = " + rows);
}
4 自定义动态sql
- 默认位置可以不写!
- 新增mybatis模板文件
- 官方模板文件
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
* UserMapper接口代码
```java
Map<String,Object> selectMapById(Long id);
- UserMapper.xml代码
<select id="selectMapById" resultType="map"> select * from user where id = #{id} </select>
- 测试类
Map<String, Object> map = userMapper.selectMapById(1l); System.out.println("map = " + map);
5 Service 层使用mybatis-plus方法
5.1 service层代码
- 接口
public interface UserService extends IService<User> { }
- 实现类
```java
@Service
public class UserServiceImpl extends ServiceImpl implements UserService{
}
## 5.2 测试查询总记录数
```java
@Test
public void testGetCount(){
long count = userService.count();
System.out.println("count = " + count);
}
5.3 测试批量新增
@Test
public void testSaveBatch(){
// SQL长度有限制,海量数据插入单条SQL无法实行,
// 因此MP将批量插入放在了通用Service中实现,而不是通用Mapper
ArrayList<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setName("ybc" + i);
user.setAge(20 + i);
users.add(user);
}
//SQL:INSERT INTO t_user ( username, age ) VALUES ( ?, ? )
boolean bool = userService.saveBatch(users);
System.out.println("bool = " + bool);
}
6 id不是用雪花算法,自己定义
@Data //lombok注解
@TableName("user")
public class User {
//IdType.AUTO就是自增
@TableId(value = "id",type = IdType.AUTO)
private Long id;
@TableField("name")
private String name;
private Integer age;
private String email;
//逻辑删除
@TableLogic
private Integer isDeleted;
}
- 配置方法
# 配置MyBatis mybatis-plus: configuration: # 日志信息 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: # 配置MyBatis-Plus的主键策略 id-type: auto # 配置MyBatis-Plus操作表的默认前缀 # table-prefix: # 配置类型别名所对应的包 type-aliases-package: com.yunfeng.mybatisplus.pojo # 配置扫描通用枚举 type-enums-package: com.yunfeng.mybatisplus.enums
7 雪花算法
雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的
主键的有序性。 - 和时间有关。
- ①核心思想:
长度共64bit(一个long型)。
首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负
数是1,所以id一般是正数,最高位是0。
41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。
10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。
12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。 - ②优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。
8 wapper条件构造器
8.1 QueryWrapper(查询、删除、修改)
- 查询
@Test public void test01(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.like("name","a") .between("age",20,30) .isNotNull("email"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
- 查询排序
@Test public void test02(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc("age") .orderByAsc("id"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
- 删除
@Test public void test03(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.isNull("email"); int row = userMapper.delete(queryWrapper); System.out.println("row = " + row); }
- 条件修改
@Test public void test04(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.gt("age",20) .like("name","a") .or() .isNull("email"); User user = new User(); user.setName("张三"); int rows = userMapper.update(user, queryWrapper); System.out.println("rows = " + rows); }
- lambda中的条件优先执行
@Test public void test05(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //lambda中的条件优先执行 queryWrapper.like("name","a") .and(i -> i.gt("age",20).or().isNull("email")); User user = new User(); user.setName("李四"); int rows = userMapper.update(user, queryWrapper); System.out.println("rows = " + rows); }
- 查询部分字段
//查询部分字段 @Test public void test06(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.select("name","age"); List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper); maps.forEach(System.out::println); }
- 子查询
// 子查询 @Test public void test07(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.inSql("age","select age from user where age < 20"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
8.2 UpdateWrapper
- UpdateWrapper修改不需要new实体类
@Test public void test08(){ UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(); updateWrapper.like("name","a") .and( i -> i.gt("age",20).or().isNull("email")); updateWrapper.set("name","王五"); int rows = userMapper.update(null, updateWrapper); System.out.println("rows = " + rows); }
- 条件组装
@Test public void test10(){ String name = ""; Integer ageBegin = 20; Integer ageEnd = 30; QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.like(StringUtils.isNotBlank(name),"name",name) .ge(ageBegin != null,"age",ageBegin) .gt(ageEnd != null,"age",ageEnd); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
8.3 LambdaQueryWrapper
@Test public void test11(){ String name = ""; Integer ageBegin = 20; Integer ageEnd = 30; LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(StringUtils.isNotBlank(name),User::getName,name) .ge(ageBegin != null,User::getAge,ageBegin) .gt(ageEnd != null,User::getAge,ageEnd); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
8.4 LambdaUpdateWrapper
@Test public void test12(){ LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.like(User::getName,"a") .and( i -> i.gt(User::getAge,20).or().isNull(User::getEmail)); updateWrapper.set(User::getName,"赵六"); int rows = userMapper.update(null, updateWrapper); System.out.println("rows = " + rows); }
9 插件
9.1 分页插件
- 写配置类
```java
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
//扫描mapper接口所在的包
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MyBatisPlusConfig {
//分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
* 测试
```java
@Test
public void testPage(){
Page<User> page = new Page<>(2,3);
userMapper.selectPage(page, null);
System.out.println("page = " + page);
}
9.2 乐观锁和悲观锁
- 添加@Version注解
@Data public class Product { private Long id; private String name; private Integer price; @Version private Integer version; }
- 添加插件
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //添加分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //添加乐观锁插件 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; }
10 代码生成器
官网地址:https://baomidou.com/pages/779a6e/#%E5%AE%89%E8%A3%85
10.1引入以依赖
<!-- 代码生成器 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency>
10.2 生成代码
public static void main(String[] args) { FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false", "root", "yuan159951.") .globalConfig(builder -> { builder.author("logic") // 设置作者 //.enableSwagger() // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 .outputDir("D://mybatis_plus"); // 指定输出目录 }) .packageConfig(builder -> { builder.parent("com.yunfeng") // 设置父包名 .moduleName("mybatisplus") // 设置父包模块名 .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("user") // 设置需要生成的表名 .addTablePrefix("t_", "c_"); // 设置过滤表前缀 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker 引擎模板,默认的是Velocity引擎模板 .execute(); }