目录
一、简述
1、概述
2、特性
3、支持数据库
二、标准数据层开发
1、标准数据层CRUD功能
1.1 新增insert
1.2 删除功能deleteById
1.3 修改功能updateById
1.4 查询单个selectById
1.5 查询全部selectList
2、分页功能
2.1 设置MybatisPlus分页拦截器作为Spring管理的bean
2.2 分页查询IPage selectPage(IPage page)
三、DQL编程控制
1、条件查询方式IPage selectPage(Wrapper queryWrapper)
1.1 方式一查询(不推荐) :
1.2 方式二查询(推荐):lambda格式减少列名出错
1.3 方式三查询(推荐):使用Lambda方式的API
1.4 组合查询:链式方式(并且)
1.5 组合查询:链式方式(或)
1.6 条件查询 :null值处理
2、查询投影
2.1 适用于lambda方式(推荐)
2.2 适用于非lambda方式(不推荐)
2.3 查询投影的【字段未定义的使用方式】(lambda方式不行)求count
2.3 分组
3、查询条件设定
3.1 eq相等的查询条件
3.2 between范围查询
3.3 模糊匹配like查询(非全文检索版)
4、字段映射与表名映射
4.1 使用TableField(value="数据库字段名")注解 解决数据库字段与实体不一致问题
4.2 使用TableField(exist=false)注解解决数据库未定义属性
4.3 使用TableField(select=false)注解设置属性是否参与查询
4.4 使用TableName("数据库表名")注解设置数据库表名不一致问题
4.5 使用TableId注解 将属性所对应字段指定为主键
4.6 使用TableId(type=) 注解 指定主键id生成策略
4.7 使用TableLogic注解 逻辑删除
四、DML编程控制
1、结合id生成规则(Insert)
2、多记录操作(Delete\Select)
3、逻辑删除(Delete/Update )
4、乐观锁(并发控制)(Update)
4.1 数据库加字段version,默认1
4.2 实体类新增属性version以及@Version注解
4.3 新增拦截器,优化之前的MybatisPlusConfig
4.4 运行修改方法
4.5 检验乐观锁
五、快速开发
1、代码生成器
2、pom导入坐标
3、创建CodeGenetator文件
4、执行CodeGenetator
前言:MyBatisPlus简介、CRUD、分页、条件查询
mysql 、mariadb 、oracle 、db2 、h2 、hsql 、sqlite 、postgresql 、sqlserver 、presto 、Gauss 、Firebird
Phoenix 、clickhouse 、Sybase ASE 、 OceanBase 、达梦数据库 、虚谷数据库 、人大金仓数据库 、南大通用数据库
@SpringBootTest
class MybatisQuickstartApplicationTests {
@Autowired
private EmpMapper empMapper;
@Test
void testSave(){
Emp emp = new Emp();
emp.setId(0);
emp.setName("mimi");
emp.setPassword("111111");
emp.setUsername("咪咪");
emp.setGender((short) 2);
emp.setImage("11.jpg");
emp.setEntrydate(LocalDate.now());
emp.setJob((short) 2);
emp.setDeptId(1);
emp.setUpdateTime(LocalDateTime.now());
emp.setCreateTime(LocalDateTime.now());
empMapper.insert(emp);
}
}
注意:这里因为id数据库是int类型的自增字段,我之前没有设置值,导致报错:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Could not set property 'id' of 'class com.bocai.entity.Emp' with value '1715193012897251329' Cause: java.lang.IllegalArgumentException: argument type mismatch。 所以设定了一个值就OK 了
/**
* 通过id删除数据,这里ID25是从库里查出来了………O(∩_∩)O哈哈~
*/
@Test
void testDelete(){
empMapper.deleteById(25);
}
/**
* 根据ID修改 ,这里的id是库里查的哦
*/
@Test
void testUpate(){
Emp emp = new Emp();
emp.setId(20);
emp.setUpdateTime(LocalDateTime.now());
emp.setName("手感好");
empMapper.updateById(emp);
}
注意:这里看上去是setId,实际上他转换成sql是id是where条件
/**
* 根据id查询
*/
@Test
void testGetById(){
Emp emp = empMapper.selectById(20);
System.out.println(emp);
}
/**
* 查询全部
*/
@Test
void testGetAll() {
List empList = empMapper.selectList(null);
System.out.println(empList);
}
package com.bocai.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;
/**
* 配置MP的分页插件
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
// 1、定义MybatisPlus拦截器
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 2、添加具体的拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
上一步的拦截器必须添加
/**
* 分页查询
*
*/
@Test
void testGetByPage(){
IPage page = new Page(1,5); // 当前第一页,每页5条
empMapper.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());
}
准备用户
User
package com.bocai.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id; //ID
private String name; //姓名
private Integer age; //年龄
private Short gender; // 性别 1 男 2 女
private String phone; //电话
}
UserMapper
package com.bocai.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bocai.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper {
}
/**
* 条件查询 // 小于的查询条件lt(列名,值)
*/
@Test
void testConditionGetAll() {
//按条件查询
QueryWrapper qw = new QueryWrapper<>();
qw.lt("age",38);
List userList = userMapper.selectList(qw);
System.out.println(userList);
}
/**
* 条件查询 // 小于的查询条件lt(列名,值)
*/
@Test
void testConditionGetAll() {
//按条件查询 方式二lambda格式
QueryWrapper qw = new QueryWrapper<>();
qw.lambda().lt(User::getAge,38);
List userList = userMapper.selectList(qw);
System.out.println(userList);
}
/**
* 条件查询 // 小于的查询条件lt(列名,值)
*/
@Test
void testConditionGetAll() {
//按条件查询 方式三lambda格式
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
lqw.lt(User::getAge,38);
List userList = userMapper.selectList(lqw);
System.out.println(userList);
}
/**
* 条件查询 // 小于的查询条件lt(列名,值)
*/
@Test
void testConditionGetAll() {
//按条件查询 多条件
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
lqw.lt(User::getAge,49).gt(User::getAge,38);
List userList = userMapper.selectList(lqw);
System.out.println(userList);
}
/**
* 条件查询 // 小于的查询条件lt(列名,值)
*/
@Test
void testConditionGetAll() {
//按条件查询 多条件38到49之外
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
// 38到49之外
lqw.lt(User::getAge,38).or().gt(User::getAge,49);
List userList = userMapper.selectList(lqw);
System.out.println(userList);
}
前置条件,我们需要模拟前端传参
package com.bocai.entity.query;
import com.bocai.entity.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserQuery extends User {
private Integer age2; //年龄
}
/**
* 条件查询
*/
@Test
void testConditionGetAll() {
//按条件查询 处理null 问题
// 模拟页面传统过来的查询数据
UserQuery userQuery = new UserQuery();
// userQuery.setAge(20);
userQuery.setAge2(40);
// null的判断
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
// null方式判断是否为空,为空不执行这个
lqw.lt(null != userQuery.getAge2(),User::getAge,userQuery.getAge2())
.gt(null != userQuery.getAge(),User::getAge,userQuery.getAge());
List userList = userMapper.selectList(lqw);
System.out.println(userList);
}
查询投影就是查询显示哪些字段
/**
* 条件查询 //
*/
@Test
void testConditionGetAll() {
//========按条件查询 查询投影(适用于lambda方式)
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
lqw.select(User::getId,User::getAge,User::getName);
List userList = userMapper.selectList(lqw);
System.out.println(userList);
}
/**
* 条件查询 //
*/
@Test
void testConditionGetAll() {
//========按条件查询 查询投影(适用于非lambda方式)不推荐
QueryWrapper qw = new QueryWrapper<>();
qw.select("id","age","name");
List userList = userMapper.selectList(qw);
System.out.println(userList);
}
/**
* 条件查询 //
*/
@Test
void testConditionGetAll() {
//========按条件查询 【字段未定义的使用方式】查询投影求count
QueryWrapper qw = new QueryWrapper<>();
qw.select("count(*) as count");
List
/**
* 条件查询 //
*/
@Test
void testConditionGetAll() {
//========按条件查询 查询投影求count,并分组
QueryWrapper qw = new QueryWrapper<>();
qw.select("count(*) as count, gender").groupBy("gender");
List
条件构造器 | MyBatis-Plus
一条数据就使用selectOne
/**
* 条件查询 //
*/
@Test
void testConditionGetAll() {
//========按条件查询 查询条件设定 =匹配
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
//等同于=号
lqw.eq(User::getName,"金毛狮王").eq(User::getAge,45);
User user = userMapper.selectOne(lqw);
System.out.println(user);
}
/**
* 条件查询 //
*/
@Test
void testConditionGetAll() {
//========按条件查询 范围查询between
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
//范围查询between
lqw.between(User::getAge,38,57);
List userList = userMapper.selectList(lqw);
System.out.println(userList);
}
likeLeft likeRight 模糊匹配%位置
/**
* 条件查询 //
*/
@Test
void testConditionGetAll() {
//========按条件查询 模糊查询(非全文检索版)
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
//========按条件查询 like 模糊查询 不在演示likeLeft likeRight 模糊匹配%位置
lqw.like(User::getName,"王");
List userList = userMapper.selectList(lqw);
System.out.println(userList);
}
实体有online字段,数据库没有
package com.bocai.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id; //ID
private String name; //姓名
private Integer age; //年龄
private Short gender; // 性别 1 男 2 女
private String phone; //电话
@TableField(exist = false)
private Integer online; //是否在线 1 在线 2 不在线
}
下图是雪花算法生成主键id
package com.bocai.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 员工实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
@TableId(type= IdType.AUTO) //数据库自增ID方式
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Short gender; //性别 , 1 男, 2 女
private String image; //图像url
private Short job; //职位 , 1 班主任 , 2 讲师 , 3 学工主管 , 4 教研主管 , 5 咨询师
private LocalDate entrydate; //入职日期
private Integer deptId; //部门ID
private LocalDateTime createTime; //创建时间
private LocalDateTime updateTime; //修改时间
}
或者使用全部配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
username: root
password: XXX
main:
banner-mode: off # 关闭控制台springboot的logo
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台显示sql
global-config:
db-config:
id-type: auto # 数据库id生产规则全局 配置 # ASSIGN_ID雪花算法,数据库id建议使用Long类型
# table-prefix: tbl_ # 数据库表前缀全局配置
banner: false # 关闭控制台mybatis-plus的logo
/**
* 新增
*/
@Test
void testSave(){
Emp emp = new Emp();
// emp.setId(0); //实体类设置这个属性就不需要这个@TableId(type= IdType.AUTO) //数据库自增ID 方式
emp.setName("dadamimi");
emp.setPassword("111111");
emp.setUsername("大大咪咪");
emp.setGender((short) 2);
emp.setImage("11.jpg");
emp.setEntrydate(LocalDate.now());
emp.setJob((short) 2);
emp.setDeptId(1);
emp.setUpdateTime(LocalDateTime.now());
emp.setCreateTime(LocalDateTime.now());
empMapper.insert(emp);
}
数据库ID建议使用Long类型,不然本文后面的雪花算法等长度不够
IdType.AUTO:数据库自增
IdType.NONE:没有策略
IdType.INPUT:用户自己输入 。那么数据库的自增策略要移除,新增要指定id值
IdType.ASSIGN_ID:雪花算法。那么数据库的自增策略要移除,新增不需要指定id值
IdType.ASSIGN_UUID:UUID
/** @deprecated */
-======== 下面三个过时了===
IdType.ID_WORKER:生成整型 被他取代IdType.ASSIGN_ID:
IdType.ID_WORKER_STR:生成字符串 被他取代IdType.ASSIGN_ID:
IdType.UUID:被他取代IdType.ASSIGN_UUID:
/**
* 删除多条记录
*/
@Test
void testDeleteList(){
List list = new ArrayList<>();
list.add(26);
list.add(28);
empMapper.deleteBatchIds(list);
}
全局配置,就不需要再实体去配置逻辑删除字段了
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
username: root
password: runa#2050
main:
banner-mode: off # 关闭控制台springboot的logo
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台显示sql
global-config:
db-config:
id-type: auto # 数据库id生产规则全局 配置 # ASSIGN_ID雪花算法,数据库id建议使用Long类型
# logic-delete-field: deleted # 全局配置逻辑删除字段名
# logic-delete-value: 0 # 全局配置逻没有被删除的写0
#logic-not-delete-value: 1 # 全局配置逻没有被逻辑删除的写1
# table-prefix: tbl_ # 数据库表前缀全局配置
banner: false # 关闭控制台mybatis-plus的logo
package com.bocai.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置MP的分页插件
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
// 1、定义MybatisPlus拦截器
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 2、添加分页的拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
// 3、添加乐观锁的拦截器
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
package com.bocai.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置MP的分页插件
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
// 1、定义MybatisPlus拦截器
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 2、添加分页的拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
// 3、添加乐观锁的拦截器
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
需要传Version数值进行修改
这个方式不需要version传值,因为查询出来的数据有version
所有bbb 没有成功 ,下面是分析
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.7.5
com.bocai
mybatis_quickstart
0.0.1-SNAPSHOT
1.8
org.springframework.boot
spring-boot-starter
com.mysql
mysql-connector-j
runtime
org.springframework.boot
spring-boot-starter-test
test
com.baomidou
mybatis-plus-boot-starter
3.4.2
com.alibaba
druid-spring-boot-starter
1.1.23
org.projectlombok
lombok
true
provided
1.18.24
com.baomidou
mybatis-plus-generator
3.4.1
org.apache.velocity
velocity-engine-core
2.3
org.springframework.boot
spring-boot-maven-plugin
package com.bocai;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
public class CodeGenerator {
public static void main(String[] args) {
AutoGenerator autoGenerator = new AutoGenerator();
// 配置数据库
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("runa#2050");
autoGenerator.setDataSource(dataSourceConfig);
// 设置全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/mybatis_quickstart/src/main/java"); //设置代码生成文件输出位置 /mybatis_quickstart(这里目录依据你实际项目配置)
globalConfig.setOpen(false); // 设置生成完毕后是否打开生成代码所在的目录
globalConfig.setAuthor("春天的菠菜"); //设置作者
globalConfig.setFileOverride(false); // 设置是否覆盖原始生成的文件默认是false
globalConfig.setMapperName("%sMapper"); //设置数据层接口名,%s为占位符, 指代模块名称 也有这样写的%Dao,其实不指定的话 他默认就是Mapper
globalConfig.setIdType(IdType.AUTO); //设置id生成策略,目前是数据库自增, 可以ASSIGN_ID雪花算法,但数据库就不能是自增属性了
autoGenerator.setGlobalConfig(globalConfig);
// 设置包名相关配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.niuniu"); //设置生成的包名,与代码所在的位置不冲突,二者叠加组成完整路径
packageConfig.setEntity("entity"); //设置实体类包名 有的叫domain
packageConfig.setMapper("mapper"); //设置数据层包名 ,有的叫dao
autoGenerator.setPackageInfo(packageConfig);
// 策略设置 这个是关键
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("dept");// 设置当前参与生成的 表名,参数为可变参数
// strategyConfig.setInclude("tbl_user");// 设置当前参与生成的 表名,参数为可变参数,("tbl_user","sss","ssss")
// strategyConfig.setTablePrefix("tbl_"); //设置数据库表的前缀名称。 模块名= 数据库名 - 前缀名 例如 User = tbl_user - tbl
strategyConfig.setRestControllerStyle(true); //设置是否启用Rest风格
strategyConfig.setVersionFieldName("version"); // 设置乐观锁字段名
strategyConfig.setLogicDeleteFieldName("deleted"); //设置逻辑删除字段名
strategyConfig.setEntityLombokModel(true); //设置是否启用lambok
autoGenerator.setStrategy(strategyConfig);
// 执行 生成操作
autoGenerator.execute();
}
}
下面那个xml可根据需要迁移到resources对应的文件目录下(包名目录相同)