Mybatis-Plus学习
MybatisPlus概述
MybatisPlus可以节省我们大量的工作时间,所有的CRUD都可以完成,类似的还有 JPA、tk-mapper
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
一、快速入门
1. 导入依赖
<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>
2. 代码编写
SQL
CREATE TABLE user
(
id BIGINT(20) 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)
);
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');
注意:尽量不要同时导入Mybatis和Mybatis-plus
连接数据库
spring:
datasource:
username: root
password: 1870535196
url: jdbc:mysql://localhost:3306/zl?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
pojo
package cn.imut.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private Integer age;
private String email;
}
dao
package cn.imut.dao;
import cn.imut.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
//继承BaseMapper
//@Repository
@Repository
public interface UserMapper extends BaseMapper<User> {
//所有的crud都完成
}
注意:需要使用mapperScan扫描dao层下所有的接口
测试
package cn.imut;
import cn.imut.dao.UserMapper;
import cn.imut.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class MybatisplusStudyApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println);
}
}
二、配置日志
所有的SQL是不可见的,看日志才能知道是怎么执行的
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
三、CRUD扩展
3.1 插入
//插入
@Test
public void testInsert() {
User user = new User();
user.setId(7);
user.setName("磊爷");
user.setAge(22);
user.setEmail("vip.p@live.com");
int insert = userMapper.insert(user);
System.out.println(insert);
System.out.println(user);
}
3.2 主键生成策略
雪花算法:
SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增的。这 64 个 bit 中,其中 1 个 bit 是不用的,然后用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。
主键自增:
- 实体类上写 @TableId(Type = IdType.AUTO)
- 数据库字段一定要自增
public enum idType {
AUTO(0), //数据库id自增
NONE(1), //未设置主键
INPUT(2), //手动输入
ID_WORKER(3), //默认的全局id
UUID(4), //全局唯一id uuid
ID_WORKER_STR(5); //id_worker的字符串表示
}
3.3 更新
@Test
public void testUpdate() {
//可以通过条件自动拼接动态SQL
User user = new User();
user.setId(7);
user.setName("张磊");
int i = userMapper.updateById(user);
System.out.println(i);
}
3.4 自动填充
创建时间、修改时间。都是自动完成的!
阿里开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都需要配置,并且自动化
-
方式一、数据库级别(工作中不允许使用)
alter table user add create_time datetime default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '创建时间'; alter table user add update_time datetime default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '更新时间'; -
方式二、代码级别
//字段填充内容 @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;编写处理器处理
package cn.imut.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.time.LocalDateTime; import java.util.Date; @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { //插入时的填充策略 @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.setFieldValByName("createTime", new Date(), metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); } //更新时的填充策略 @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("updateTime", new Date(), metaObject); } }
3.5 乐观锁
顾名思义,十分乐观,认为不会出现问题,无论如何,都不会上锁,若出现问题再次更新值进行测试
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
一定程度上,可以保证线性同步进行
测试
-
1.加字段
alter table user add `version` int(10) default 1 comment '乐观锁'; -
2.实体类加对应的字段
@Version private Integer version; -
3.注册组件
package cn.imut.config; 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; @EnableTransactionManagement //自动管理事务 @Configuration @MapperScan("cn.imut.dao") public class MybatisPlusConfig { //注册乐观锁插件 @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } } -
测试(单线程)
//测试乐观锁 @Test public void testOptimisticLocker() { User user = userMapper.selectById(1); user.setName("jsb"); user.setEmail("jssbjssb"); userMapper.updateById(user); } -
测试(多线程)
//测试乐观锁 @Test public void testOptimisticLocker() { User user = userMapper.selectById(1); user.setName("jsb111"); user.setEmail("jssbjssb111"); User user2 = userMapper.selectById(1); user2.setName("jsb222"); user2.setEmail("jssbjssb222"); userMapper.updateById(user2); userMapper.updateById(user); }
3.6 查询
直接查询
@Test
public void testSelectById() {
User user = userMapper.selectById(1);
System.out.println(user);
}
批量查询
@Test
public void testSelectByBatchId() {
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
for (User user : users) {
System.out.println(user);
}
}
条件查询
@Test
public void testSelectByBatchIds() {
HashMap<String, Object> map = new HashMap<>();
map.put("name","张磊");
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
分页查询
- 原始 limit 分页
- 第三方插件
- mybatisplus内置分页
1.配置拦截器
@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;
}
2.使用page对象即可
@Test
public void testPage() {
// 当前页 页面大小
Page<User> page = new Page<>(1, 5);
userMapper.selectPage(page, null);
page.getRecords().forEach(System.out::println);
}
3.7 删除
@Test
public void testDeleteById() {
userMapper.deleteById(8);
}
批量删除
@Test
public void testDeleteBathId() {
userMapper.deleteBatchIds(Arrays.asList(6,7));
}
Map删除
@Test
public void testDeleteMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name","雷爷");
userMapper.deleteByMap(map);
}
逻辑删除(重要)
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除,二十通过一个变量让他失效
管理员可以查看被删除的记录
alter table user add `deleted` int(10) default 0 comment '逻辑删除';
pojo 增加属性
@TableLogic
private Integer deleted;
逻辑删除组件
3.11后不需要写
此后数据库中删除其实是update,查询时会自动过滤
四、性能分析
Mybatisplus 移除了 PerformanceInterceptor 相关, 建议使用 p6spy
五、条件构造器
Wrapper,可以替代一些复杂的SQL
测试一(查询名字,邮箱不为空,且年龄大于12岁)
package cn.imut;
import cn.imut.dao.UserMapper;
import cn.imut.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class WrapperTest {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
//查询姓名不为空,邮箱不为空的用户信息,年龄大于12的
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name");
wrapper.isNotNull("email");
wrapper.ge("age",12);
userMapper.selectList(wrapper).forEach(System.out::println);
}
}
测试二(查询年龄在20到30之间的)
@Test
void test2() {
//查询年龄在20-30之间的
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",20,30);
userMapper.selectList(wrapper).forEach(System.out::println);
}
模糊查询
@Test
void test3() {
//查询名字中有T的
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name","T");
userMapper.selectList(wrapper).forEach(System.out::println);
}
六、代码生成器
dao、pojo、service、controller都不写了!
略
https://mybatis.plus/guide/generator.html#%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B



浙公网安备 33010602011771号