mybatis-plus官网
简介 | MyBatis-Plus (baomidou.com)
一 快速入门
1 创建项目
导入mysql驱动,这里先不做web
2 导入依赖
我这里用的是springboot 3.3.0版本
注意: SpringBoot 3.0 需要 mybatis-spring 3.0.X 版本,否则会报如下错误: nvalid value type for attribute 'factoryBeanObjectType'‘': java.lang.String
这里有一个小坑
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
3 引入例子
package com.demo.learnmybatisplus.Pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Data
@Component
@AllArgsConstructor
@NoArgsConstructor
public class Users {
public int id;
private String username;
private String password;
}
数据库的相应信息
4 编辑持久层
package com.demo.learnmybatisplus.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.learnmybatisplus.Pojo.Users;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<Users> {
}
5 启动!!! 添加测试
package com.demo.learnmybatisplus;
import com.demo.learnmybatisplus.Mapper.UserMapper;
import com.demo.learnmybatisplus.Pojo.Users;
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 LearnMybatisPLusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void selectAll(){
List<Users> users = userMapper.selectList(null);
System.out.println(users);
}
}
结果显示
6 坑!!!
SpringBoot 3.0 需要 mybatis-spring 3.0.X 版本,如果没导入,就会报错。当时我找了好久,哪里没加注解呢?!想不到是版本问题
二 方便快捷的CRUD功能
全部的条件构造器可以看这里
条件构造器 | MyBatis-Plus (baomidou.com)
1 简单介绍有哪些
2 前五个操作,增删改查以及查全部
package com.demo.learnmybatisplus;
import com.demo.learnmybatisplus.Mapper.UserMapper;
import com.demo.learnmybatisplus.Pojo.Users;
import lombok.extern.slf4j.Slf4j;
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
@Slf4j
class LearnMybatisPLusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void selectAll(){
List<Users> users = userMapper.selectList(null);
System.out.println(users);
}
@Test
public void TextInsert(){
Users users = new Users(2, "123456", "789789");
log.info("新增用户:{}", users);
//传入的是实体类books
userMapper.insert(users);
}
@Test
public void TextDelete(){
int id = 6;
userMapper.deleteById(id);
}
@Test
public void TextUpdate(){
Users users = new Users();
users.setId(4);
users.setPassword("12356789");
//根据id锁定修改对象,其他值为修改值
userMapper.updateById(users);
}
@Test
public void TextSelectAll(){
List<Users> usersList = userMapper.selectList(null);
}
}
3 分页查询操作
分页查询需要一个专门的拦截器,来拦截sql语句,实现limit的添加
package com.demo.learnmybatisplus.Config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MpConfiguation {
@Bean
public MybatisPlusInterceptor pageInterceptor() {
//1 创建一个拦截器对象
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//2 在拦截器内部加入小的分页的拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
配置好拦截器之后,在测试类测试分页查询的代码
@Test
public void TextPageSelect() {
//第一个参数代表查询第几页, 第二个代表每页多少个参数
IPage page = new Page(2, 3);
userMapper.selectPage(page, null);
System.out.println("当前页码:" + page.getCurrent());
System.out.println("每页数据总量:" + page.getSize());
System.out.println("总页数:" + page.getPages());
System.out.println("数据总量:" + page.getTotal());
System.out.println("当前页数据:" + page.getRecords());
}
开启sql详细日志的输出,来看看limit是怎么被加上去的。平时可以注释掉,避免控制台太多东西,在出错时可以打开此配置来找错
#mybatis日志的输出
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4 DQL条件查询
一共四种方法,主要用第三种方法 构建条件查询器
//条件查询
@Test
public void TextSelect(){
//方式一 常规格式
QueryWrapper qw = new QueryWrapper();
qw.lt("id", 6);//id小于于6
qw.ge("id", 4);//id大于2
List<Users> usersList = userMapper.selectList(qw);
System.out.println(usersList);
// 方式二 lambda链式编程
QueryWrapper<Users> qwU = new QueryWrapper<>();
qwU.lambda().lt(Users::getId, 6).ge(Users::getId,4);
List<Users> usersListU = userMapper.selectList(qwU);
System.out.println(usersListU);
//方式三 lambda的简化
LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
lqw.lt(Users::getId, 6).ge(Users::getId,4);
List<Users> usersListlqu = userMapper.selectList(lqw);
System.out.println(usersListlqu);
//组合条件,上面的是and的条件,这个是or的条件
lqw.lt(Users::getId, 6).or().ge(Users::getId,4);
}
}
补充,对null的判断
//条件查询,对空的判断
@Test
public void TextNull(){
LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
Users user1 = new Users();
user1.setId(3);
//如果不为空,及前面的表达式为true,则条件生效
lqw.lt(user1 != null, Users::getId, 4);
}
5 查询投影
他主要有两个功能,一个是查询部分的信息。
另一个是可以使用函数等Users类里面没有的信息。因为之前学到的查询都是封装到了实体类的中,本例是Users,所以他不能显示Users里面mei
//条件查询,查询部分信息,以及使用函数等Users类里面没有的信息
@Test
public void TextSelectPath(){
//查询部分属性
LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
lqw.select(Users::getId);
lqw.lt(Users::getId, 6);
List<Users> users = userMapper.selectList(lqw);
System.out.println(users);
//查询函数以及其他User类没有的值
/*
注意selectMaps和上面LambdaQueryWrapper查询的selectList是不一样的,
和之前的也是不一样的
LambdaQueryWrapper不具有这个方法
这个方法有局限,并不是所有的函数都支持,
则需要时我们可以像mybatis一样自己写@Select语句
*/
QueryWrapper<Users> qw = new QueryWrapper<>();
qw.select("count(*) as count, id");
qw.groupBy("id");
List<Map<String, Object>> list = userMapper.selectMaps(qw);
System.out.println(list);
//这就是自己定义的方法
List<Map<Integer, Object>> listByMe = userMapper.TextCount();
System.out.println(listByMe);
}
UserMapper中自己定义的方法,这里有个sql规范,用了聚合函数与非聚合函数就要用分组,只用聚合函数就不用一定要分组
package com.demo.learnmybatisplus.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.learnmybatisplus.Pojo.Users;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
@Mapper
public interface UserMapper extends BaseMapper<Users> {
@Select("select count(*), id from users group by id")
List<Map<Integer, Object>> TextCount();
}
6 映射配置兼容性
问题一 : 实体类里面字段名字与数据库不匹配
问题二 : 编码中实体类添加了数据库没有的字段
问题三 : 查询的权限扩大,有些字段不希望被查询到
问题四: 实体类名字与数据库的表名字不一致
7 逻辑删除
情景:在实际业务中,我们删除数据会对业务造成不可挽回的伤害,所以我们要采取另一种方式来实现删除功能
这里的逻辑:mybatisplus会提供方法,在表格中添加一栏数据来标记此数据是否被删除,从而在其他过程中不在涉及该数据
步骤一 :在数据库添加字段,这里添加了deleted字段
步骤二 : 在实体类添加字段,也是deleted
步骤三: 在yml文件内让spring能识别mybatisplus这个功能:在表格中添加一栏数据来标记此数据是否被删除,若识别为已经删除,则在其他过程中不再涉及该数据
测试一把,看看他是怎么实现的
当我执行delete方法时
他的输出
他底层做的是一个更新操作,并不是真正的删除
三 BaseMapper源码
我们的mapper继承了这个,从中我们可以看到这个mybatisplus中到底有什么方法
//
// 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 com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.exceptions.TooManyResultsException;
import org.apache.ibatis.session.ResultHandler;
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteById(T entity);
default int deleteByMap(Map<String, Object> columnMap) {
return this.delete((Wrapper)Wrappers.query().allEq(columnMap));
}
int delete(@Param("ew") Wrapper<T> queryWrapper);
int deleteBatchIds(@Param("coll") Collection<?> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
default int update(@Param("ew") Wrapper<T> updateWrapper) {
return this.update((Object)null, updateWrapper);
}
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
void selectBatchIds(@Param("coll") Collection<? extends Serializable> idList, ResultHandler<T> resultHandler);
default List<T> selectByMap(Map<String, Object> columnMap) {
return this.selectList((Wrapper)Wrappers.query().allEq(columnMap));
}
default void selectByMap(Map<String, Object> columnMap, ResultHandler<T> resultHandler) {
this.selectList((Wrapper)Wrappers.query().allEq(columnMap), resultHandler);
}
default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {
return this.selectOne(queryWrapper, true);
}
default T selectOne(@Param("ew") Wrapper<T> queryWrapper, boolean throwEx) {
List<T> list = this.selectList(queryWrapper);
int size = list.size();
if (size == 1) {
return list.get(0);
} else if (size > 1) {
if (throwEx) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + size);
} else {
return list.get(0);
}
} else {
return null;
}
}
default boolean exists(Wrapper<T> queryWrapper) {
Long count = this.selectCount(queryWrapper);
return null != count && count > 0L;
}
Long selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
void selectList(@Param("ew") Wrapper<T> queryWrapper, ResultHandler<T> resultHandler);
List<T> selectList(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
void selectList(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper, ResultHandler<T> resultHandler);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
void selectMaps(@Param("ew") Wrapper<T> queryWrapper, ResultHandler<Map<String, Object>> resultHandler);
List<Map<String, Object>> selectMaps(IPage<? extends Map<String, Object>> page, @Param("ew") Wrapper<T> queryWrapper);
void selectMaps(IPage<? extends Map<String, Object>> page, @Param("ew") Wrapper<T> queryWrapper, ResultHandler<Map<String, Object>> resultHandler);
<E> List<E> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E> void selectObjs(@Param("ew") Wrapper<T> queryWrapper, ResultHandler<E> resultHandler);
default <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper) {
page.setRecords(this.selectList(page, queryWrapper));
return page;
}
default <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper) {
page.setRecords(this.selectMaps(page, queryWrapper));
return page;
}
}