周末无聊,就用了一天时间巩固了一下MyBatis-plus,此文仅作为学习总结,如果对你有用的话,欢迎收藏。
工作中学会如何使用各种各样的工具确实有利于提升我们的开发效率,但是在使用工具的同时,更应该去看看其底层的源码、实现。
- 官网:https://mp.baomidou.com/guide/
- 特性
- 无侵入
- 耗损小
- 强大的CRUD操作
- 支持Lambda形式调用
- 支持主键自动生成
- 支持ActiveRecord模式
- 支持自定义全局通用操作
- 内置代码生成器
- 内置分页插件
- 分页插件支持多种数据库
- 内置性能分析插件
- 内置全局拦截插件
========================================
- 快速入门
- 导入依赖,导入了Mybatis-plus依赖后就不用导入MyBatis依赖了!
<!-- mybayis-plus -->
<!-- mybatis-plus 是开源的,并非官方的 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<verison>3.0.5</version>
</dependency>
- 步骤
- 创建pojo
- 创建mapper接口
- 使用即可(省略了Mapper.xml配置)
//1、创建User实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
//2、创建mapper接口,在对应的Mapper上面继承基本的类BaseMapper
@Repository //代表持久层,也可以加@Mapper
public interface UserMapper extends BaseMapper<User> {
//至此所有基本的CRUD操作都已经编写完成,不用像MyBatis那样还需编写xml文件
}
//3、在SpringBoot启动类上添加扫描Mapper注解
@MapperScan("com.it.mapper")
@SpringBootApplication
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class,args);
}
}
//4、测试
@SpringBootTest
class MybatisPlusApplicationTests {
//继承了BaseMapper,所有的方法都来自父类
//我们也可以编写自己的扩展方法
@AutoWired
private UserMapper userMapper;
@Test
void contextLoads() {
//参数是有个Wrapper,条件构造器,我们不附加任何条件,直接查询所有用户,
//可以置Wrapper:null
//查询全部用户
List<User> users = userMapper.selectList(wrapper:null);
users.forEach(System.out::println); //循环输出
}
}
====================
- 配置日志,在application.properties中配置
#配置日志
mybatis-plus.configuration.log-impl=org.appache.ibatis.logging.stdout.StdOutImpl
- CRUD扩展
//测试插入
@Test
public void testInsert(){
User user = new User();
user,setName("xiaoge");
user.setAge(6);
user.setTmail("126014112@qq.com");
userMapper.insert(user); //自动生成id
}
/**
*主键生成策略
*分布式系统唯一id生成方案:https://www.cnblogs.com/haoxinyue/p/5208136.html
*自增ID,UUID,雪花算法,redis,zookeeper
*是Twitter开源的分布式ID生成算法,结果是一个long型的ID。
*其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID
*(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号
*(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,
*永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。
*
*/
//默认ID_WORKER全局唯一id
//AUTO,主键自增,同时数据库字段一定要选择主键自增即可
//NONE,未设置主键
//INPUT,手动输入,需要自己配置ID user.setID(6L)
//UUID,全局唯一id
//ID_WORKER_STR , ID_WORKER字符串表示法
@TableID(type=IdType.ID_WORDER)
private Long id;
//更新操作
@Test
public void testUpdate(){
User user = new User();
//通过条件自动拼接动态SQL
user.setId(6L);
user.setName("hahahahah");
user.setAge(99);
int i = userMapper.updateById(user);//参数是一个对象
System.out.println(i);
}
- 自动填充
- 创建时间、修改时间,这些操作一般都是自动完成的
- 创建时间、更新时间,几乎所有的表都要配置上,而且需要自动化!
- 数据库级别
- 在表中添加时间字段即可
- 代码级别
- 删除数据库时间字段默认值
- 实体类的字段属性上增加注解
@TableField(file = FieldFill.INSERT) //插入的时候更新时间
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
//编写处理器实现 MetaObjectHandler
@Component //SpringBoot容器扫描,把该处理器放到IOC容器中
@Slf4j //操作日志输出,便于理解
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) {
log.info("start update fill....");
this.setFieldValByName("updateTime" , new Date() , metaObject);
}
}
===================
- 乐观锁
- 总是认为不会出现问题,无论做什么都不去上锁,如果出现了问题,再次更新值测试
- 悲观锁
- 总是认为会出现问题,无论做什么都会上锁,再去操作数据库
- 乐观锁插件
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
- 给数据库中增加version字段
2、在实体类添加对应的version
@Version //乐观锁Version注解
private Integer version;
3、注册组件
//扫描Mapper目录
@MapperScan("com.it.mapper") //这里加上mapper扫描之后,springboot启动类上就不用加了
@EnableTranscactionManagement //自动管理事务
@Configuration //配置类
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerIngerceptor();
}
}
4、测试
//测试乐观锁成功
@Test
public void testOptimisticLocker() {
//1、查询用户信息
User user = userMapper.selectById(1L);
//2、修改用户信息
user.setName("zhangsan");
//3、执行更新操作
userMapper.updateById(user);
}
//测试乐观锁失败,多线程下
@Test
public void testOptimisticLocker2() {
//线程1
User user = userMapper.selectById(1L);
user.setName("zhangsan");
//模拟另外一线程执行插队操作
User user2 = userMapper.selectById(1L);
user2.setName("lisi");
userMapper.updateById(user2);
userMapper.updateById(user) //如果没有乐观锁就会覆盖插队线程的值
}
- 分页查询
1、 配置拦截器
//扫描Mapper目录
@MapperScan("com.it.mapper") //这里加上mapper扫描之后,springboot启动类上就不用加了
@EnableTranscactionManagement //自动管理事务
@Configuration //配置类
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerIngerceptor();
}
//分页插件
@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;
return new PaginationInterceptor(); //简化版本
}
}
2、直接使用page对象即可
@Test
public void testPage(){
//参数一:当前页
//参数二:页面大小
Page<user> page = new Page<>(1,5); //每页显示5条记录
userMapper.selectPage(page,wrapper:null);
}
============================
- 删除操作
- 根据ID删除记录
@Test
public void testDeleteById() {
//通过ID删除
// userMapper.deleteById(1L);
//通过Id批量删除
// userMapper.deleteBatchIds(Arrays.asList(2L,3L));
//通过map删除
HashMap<String,Object> map = new HashMap<>();
map.put("name","zhangsan");
map.put("age",18);
userMapper.deleteByMap(map);
}
- 逻辑删除(在数据库中没有被移除,而是通过一个变量来让它失效,状态字段)
1、添加字段
2、实体类中增加属性
@TableLogic //逻辑删除
private Integer deleted;
3、配置
//扫描Mapper目录
@MapperScan("com.it.mapper") //这里加上mapper扫描之后,springboot启动类上就不用加了
@EnableTranscactionManagement //自动管理事务
@Configuration //配置类
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerIngerceptor();
}
//分页插件
@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;
return new PaginationInterceptor(); //简化版本
}
//逻辑删除组件!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
4、配置逻辑删除
#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
5、测试删除
@Test
public void testDeleteById() {
userMapper.deleteById(1L);
}
6、结果
============================
- 性能分析插件
1、导入插件
/**
*SQL执行效率插件
*/
@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformancInterceptor();
performanceInterceptor.setMaxTime(1000); // ms 设置sql执行的最大时间,如果超过了则不执行
performanceInterceptor.setFormat(true);// 是否格式化代码
return performanceInterceptor;
}
2、设置开发环境,在application.properties中
spring.profiles.active=dev
=========================================
- 条件构造器,顾名思义就是MyBatis-plus下wrapper里面提供了很多条件方法。拿之即用
@SpringBootTest
public UserTest2{
@AutoWired
private UserMapper userMapper;
@Test
void contextLoads() {
//查询name不为空且邮箱不为空,且年龄大于等于17岁的用户
QueryWrapper<User> wrapper = new QuertWrapper<>();
wrapper.isNotNull("name")
.isNotNull("email")
.ge("age",17);
userMapper.selectList(wrapper).forEach(System.out::println);
}
}
@Test
void test2() {
//查询name 为张三的用户
QueryWrapper<User> wrapper = new QuertWrapper<>();
wrapper.eq("name","张三");
User user = userMapper.selectOne(wrapper); //确定查询一条记录
System.out.println(user);
}
@Test
void test3() {
//查询年龄在10-20岁之间的用户
QueryWrapper<User> wrapper = new QuertWrapper<>();
wrapper.between("age",20,30); //区间
Integer count = userMapper.selectCount(wrapper); //查询结果数
System.out.println(count);
}
@Test
void test4() {
//查询名字不包含 三 , 邮箱以t开头的用户
QueryWrapper<User> wrapper = new QuertWrapper<>();
wrapper.notLike("name","三")
.likeRight("email","1"); // 1%, likeLeft("email" , "2") , %2
List<Map<String,Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
@Test
void test5() {
//查询ID小于3的用户
QueryWrapper<User> wrapper = new QuertWrapper<>();
//id在子查询中查出来
wrapper.inSql("id" , "select id from user where id < 3 ");
List<Object> objects = userMapper.selectObjs(wrapper);
objects.forEach(System.out::println);
}
- allEq
- eq
- ne
- gt
- lt
- le
- between
- notBetween
- notLike
- like
- likeLeft
- likeRight
- isNull
- itNotNull
- in
- notIn
- inSql
- notInSql
- groupBy
- orderByAsc
- orderByDesc
- orderBy
- having
- or
- and
- netste
- apply
- last
- exists
- notExists
- QueryWrapper
- select
- excludeColumns
- UpdateWrapper
- set
- setSql
- lambda
====================================================
- 代码自动生成器 , 官网更详细