流程设计网站,创业水务公司网站,5g全连接工厂建设指南,潍坊市做网站MyBatis-Plus#xff08;简称 MP#xff09;是 MyBatis 的增强工具#xff0c;旨在简化开发者的 CRUD 操作。它在 MyBatis 的基础上提供了更多的功能和便利性#xff0c;如代码生成器、分页插件、性能分析插件等#xff0c;使开发者能够更高效地进行数据库操作。MyBatis-P…MyBatis-Plus简称 MP是 MyBatis 的增强工具旨在简化开发者的 CRUD 操作。它在 MyBatis 的基础上提供了更多的功能和便利性如代码生成器、分页插件、性能分析插件等使开发者能够更高效地进行数据库操作。MyBatis-Plus 保持了 MyBatis 原有的灵活性和易用性同时通过一些约定和默认实现减少了重复的代码编写。
1.常见注解
MybatisPlus会根据PO实体的信息来推断出表的信息从而生成SQL的。默认情况下 MybatisPlus会把PO实体的类名驼峰转下划线作为表名 MybatisPlus会把PO实体的所有变量名驼峰转下划线作为表的字段名并根据变量类型推断字段类型 MybatisPlus会把名为id的字段作为主键
但很多情况下默认的实现与实际场景不符因此MybatisPlus提供了一些注解便于我们声明表信息。
1.1.TableName
描述表名注解标识实体类对应的表
TableName(user)
public class User {private Long id;private String name;
}
1.2TableId
主键注解标识实体类中的主键字段 属性 类型 必须指定 默认值 描述 value String 否 表名 type Enum 否 IdType.NONE 指定主键类型
TableName(user)
public class User {TableIdprivate Long id;private String name;
}
IdType支持的类型有 值 描述 AUTO 数据库 ID 自增 NONE 无状态该类型为未设置主键类型注解里等于跟随全局全局里约等于 INPUT INPUT insert 前自行 set 主键值 ASSIGN_ID 分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法) ASSIGN_UUID 分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)
1.3TableField
普通字段注解
TableName(user)
public class User {TableIdprivate Long id;private String name;private Integer age;TableField(isMarried)private Boolean isMarried;TableField(concat)private String concat;
}
一般情况下我们并不需要给字段添加TableField注解一些特殊情况除外 成员变量名与数据库字段名不一致 成员变量是以isXXX命名按照JavaBean的规范MybatisPlus识别字段时会把is去除这就导致与数据库不符。 成员变量名与数据库一致但是与数据库的关键字冲突。使用TableField注解给字段名添加转义字符。
2.常见配置
大多数的配置都有默认值因此我们都无需配置。但还有一些是没有默认值的例如:
实体类的别名扫描包
2.1全局id类型
mybatis-plus:type-aliases-package: com.itheima.mp.domain.poglobal-config:db-config:id-type: auto # 全局id类型为自增长
2.2手写SQL
需要注意的是MyBatisPlus也支持手写SQL的而mapper文件的读取地址可以自己配置默认值是classpath*:/mapper/**/*.xml也就是说我们只要把mapper.xml文件放置这个目录下就一定会被加载。
mybatis-plus:mapper-locations: classpath*:/mapper/**/*.xml # Mapper.xml文件地址当前这个是默认值。
?xml version1.0 encodingUTF-8?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.itheima.mp.mapper.UserMapper/mapper 3.Mapper 接口
mapper提供了一些常见的crud方法继承于BaseMapper后可直接使用
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.mp.domain.po.User;public interface UserMapper extends BaseMapperUser {
}
3.1条件构造器
除了新增以外修改、删除、查询的SQL语句都需要指定where条件。因此BaseMapper中提供的相关方法除了以id作为where条件以外还支持更加复杂的where条件。 Wrapper的子类AbstractWrapper提供了where中包含的所有条件构造方法
QueryWrapper在AbstractWrapper的基础上拓展了一个select方法允许指定查询字段
UpdateWrapper在AbstractWrapper的基础上拓展了一个set方法允许指定SQL中的SET部分
3.2新增 Testvoid testInsert() {User user new User();user.setId(5L);user.setUsername(Lucy);user.setPassword(123);user.setPhone(18688990011);user.setBalance(200);user.setInfo({\age\: 24, \intro\: \英文老师\, \gender\: \female\});user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());userMapper.insert(user);}
3.3通过id查询 Testvoid testQueryById() {User user userMapper.selectById(5L);System.out.println(user user);} 3.4通过id批量查询 Testvoid testQueryByIds() {ListUser users userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L));users.forEach(System.out::println);} 3.5查询一行数据
若实际上有多行数据会报错
Testvoid testSelectOne() {QueryWrapperUser wrapper new QueryWrapperUser().eq(username, 特定用户名);User user userMapper.selectOne(wrapper);System.out.println(user user);}
3.6查询记录数 Testvoid testCount() {QueryWrapperUser wrapper new QueryWrapperUser().like(username, o);long count userMapper.selectCount(wrapper);System.out.println(符合条件的用户数量: count);}
3.7Map查询 Testvoid testSelectByMap() {MapString, Object map new HashMap();map.put(username, Jack);map.put(phone, 13900112224);ListUser users userMapper.selectByMap(map);users.forEach(System.out::println);}
3.8多条件构造查询 Testvoid testQueryWrapper() {// 1.构建查询条件 where name like %o% AND balance 1000QueryWrapperUser wrapper new QueryWrapperUser().select(id, username, info, balance).like(username, o).ge(balance, 1000);// 2.查询数据ListUser users userMapper.selectList(wrapper);users.forEach(System.out::println);}Testvoid testLambdaQueryWrapper() {// 1.构建条件 WHERE username LIKE %o% AND balance 1000QueryWrapperUser wrapper new QueryWrapper();wrapper.lambda().select(User::getId, User::getUsername, User::getInfo, User::getBalance).like(User::getUsername, o).ge(User::getBalance, 1000);// 2.查询ListUser users userMapper.selectList(wrapper);users.forEach(System.out::println);}
3.9分页查询 Testvoid testPageQuery() {PageUser page new Page(1, 10); // 第一页每页10条记录QueryWrapperUser wrapper new QueryWrapperUser().orderByDesc(id);IPageUser result userMapper.selectPage(page, wrapper);result.getRecords().forEach(System.out::println);System.out.println(总记录数: result.getTotal());} 3.10通过id更新
user中必须设置id,不然更新不了没有设置默认为null。以为没有idnull的值故不更新 其他参数没有设置不会进行修改 Testvoid testUpdateById() {User user new User();user.setId(5L);user.setBalance(20000);userMapper.updateById(user);} 3.11构造条件更新 Testvoid testUpdateByQueryWrapper() {// 1.构建查询条件 where name JackQueryWrapperUser wrapper new QueryWrapperUser().eq(username, Jack);// 2.更新数据user中非null字段都会作为set语句User user new User();user.setBalance(2000);userMapper.update(user, wrapper);}
3.12自定义SQL更新 Testvoid testUpdateWrapper() {ListLong ids List.of(1L, 2L, 4L);// 1.生成SQLUpdateWrapperUser wrapper new UpdateWrapperUser().setSql(balance balance - 200) // SET balance balance - 200.in(id, ids); // WHERE id in (1, 2, 4)// 2.更新注意第一个参数可以给null也就是不填更新字段和数据// 而是基于UpdateWrapper中的setSQL来更新userMapper.update(null, wrapper);} 3.13通过id删除 Testvoid testDeleteUser() {userMapper.deleteById(5L); //删除}
3.14通过id批量删除 Testvoid testDeleteUsers() {userMapper.deleteBatchIds(List.of(1L, 2L, 3L, 4L)); //批量删除} 4.Service 接口
mybatis-plus在service接口中同样也提供了基础的crud方法在接口在需要继承IService类
import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.mp.domain.po.User;public interface IUserService extends IServiceUser {// 拓展自定义方法
} 实现IUserService接口并指定mapper接口
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.po.service.IUserService;
import com.itheima.mp.mapper.UserMapper;
import org.springframework.stereotype.Service;Service
public class UserServiceImpl extends ServiceImplUserMapper, Userimplements IUserService {
}
4.1save新增 save是新增单个元素 saveBatch是批量新增 saveOrUpdate是根据id判断如果数据存在就更新不存在则新增 saveOrUpdateBatch是批量的新增或修改 4.2remove删除 removeById根据id删除 removeByIds根据id批量删除 removeByMap根据Map中的键值对为条件删除 remove(WrapperT)根据Wrapper条件删除 removeBatchByIds 4.3update修改 updateById根据id修改 update(WrapperT)根据UpdateWrapper修改Wrapper中包含set和where部分 update(TWrapperT)按照T内的数据修改与Wrapper匹配到的数据 updateBatchById根据id批量修改 4.4查询一条Get getById根据id查询1条数据 getOne(WrapperT)根据Wrapper查询1条数据 getBaseMapper获取Service内的BaseMapper实现某些时候需要直接调用Mapper内的自定义SQL时可以用这个方法获取到Mapper 4.5批量查询List listByIds根据id批量查询 list(WrapperT)根据Wrapper条件查询多条数据 list()查询所有 4.6计数Count count()统计所有数量 count(WrapperT)统计符合Wrapper条件的数据数量
4.7分页
Service
public class UserService extends ServiceImplUserMapper, User {/*** 根据用户名获取用户列表的分页数据** param currentPage 当前页码* param pageSize 每页大小* param username 用户名* return 分页后的用户列表*/public IPageUser getUserPageByName(int currentPage, int pageSize, String username) {// 创建分页对象PageUser page new Page(currentPage, pageSize);// 创建查询条件QueryWrapperUser queryWrapper new QueryWrapper();queryWrapper.like(username, username); // 使用 like 进行模糊匹配// 执行分页查询带条件return this.page(page, queryWrapper);}
}
5.静态工具
有的时候Service之间也会相互调用为了避免出现循环依赖问题MybatisPlus提供一个静态工具类Db其中的一些静态方法与IService中方法签名基本一致也可以帮助我们实现CRUD功能。Db中的静态方法必须
示例
User.class表示查询user表中id为1的值
Test
void testDbGet() {User user Db.getById(1L, User.class);System.out.println(user);
}
利用Db实现复杂条件查询
Test
void testDbList() {ListUser list Db.lambdaQuery(User.class).like(User::getUsername, o).ge(User::getBalance, 1000).list();list.forEach(System.out::println);
}
我们采用了Db的静态方法因此避免了注入其他service减少了循环依赖的风险。
6.逻辑删除
用户注销账号后我们往往不会真正的删除该用户而是通过一个字段表示用户在逻辑上已经删除了。但是这样的操作在以后业务查询上都需要确认用户有没有删除造成不必要的麻烦。假如deleted1删除,0未删除字段我们仅需要在配置文件中进行下述配置mybatis-plus就会自动进行判断
mybatis-plus:global-config:db-config:logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)logic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
注意只有MybatisPlus生成的SQL语句才支持自动的逻辑删除自定义SQL需要自己手动处理逻辑删除。
7.定义枚举
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;Getter
public enum UserStatus {NORMAL(1, 正常),FREEZE(2, 冻结);EnumValue //标记枚举属性private final int value;JsonValue //标记JSON序列化时展示的字段private final String desc;UserStatus(int value, String desc) {this.value value;this.desc desc;}
}
要让MybatisPlus处理枚举与数据库类型自动转换我们必须告诉MybatisPlus枚举中的哪个字段的值作为数据库值。 MybatisPlus提供了EnumValue注解来标记枚举属性并且在UserStatus枚举中通过JsonValue注解标记JSON序列化时展示的字段 配置枚举处理器
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
8.JSON类型处理器
数据库的user表中有一个info字段是JSON类型 {age: 20, intro: 佛系青年, gender: male} 而目前User实体类中却是String类型 这样一来我们要读取info中的属性时就非常不方便。如果要方便获取info的类型最好是一个Map或者实体类。
而一旦我们把info改为对象类型就需要在写入数据库时手动转为String再读取数据库时手动转换为对象这会非常麻烦。
因此MybatisPlus提供了很多特殊类型字段的类型处理器解决特殊字段类型与数据库类型转换的问题。例如处理JSON就可以使用JacksonTypeHandler处理器。
接下来我们就来看看这个处理器该如何使用。
定义实体
首先我们定义一个单独实体类来与info字段的属性匹配
import lombok.Data;Data
public class UserInfo {private Integer age;private String intro;private String gender;
} 3.4.2.使用类型处理器
接下来将User类的info字段修改为UserInfo类型并声明类型处理器 /*** 详细信息*/TableField(typeHandler JacksonTypeHandler.class)private UserInfo info; 9.配置加密
目前我们配置文件中的很多参数都是明文如果开发人员发生流动很容易导致敏感信息的泄露。所以MybatisPlus支持配置文件的加密和解密功能。
我们以数据库的用户名和密码为例。
生成秘钥
首先我们利用AES工具生成一个随机秘钥然后对用户名、密码加密 Testvoid contextLoads() {// 生成 16 位随机 AES 密钥String randomKey AES.generateRandomKey();System.out.println(randomKey randomKey);// 利用密钥对用户名加密String username AES.encrypt(root, randomKey);System.out.println(username username);// 利用密钥对用户名加密String password AES.encrypt(MySQL123, randomKey);System.out.println(password password);} randomKey 6234633a66fb399f username px2bAbnUfiY8K/IgsKvscg password FGvCSEaOuga3ulDAsxw68Q spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mp?useUnicodetruecharacterEncodingUTF-8autoReconnecttrueserverTimezoneAsia/ShanghairewriteBatchedStatementstruedriver-class-name: com.mysql.cj.jdbc.Driverusername: mpw:QWWVnk1Oal3258x5rVhaeQ # 密文要以 mpw:开头password: mpw:EUFmeH3cNAzdRGdOQcabWg # 密文要以 mpw:开头 10.分页插件
import com.baomidou.mybatisplus.annotation.DbType;
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 MybatisConfig {Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {// 初始化核心插件MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();// 添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}
Test
void testPageQuery() {// 1.分页查询new Page()的两个参数分别是页码、每页大小PageUser p userService.page(new Page(2, 2));// 2.总条数System.out.println(total p.getTotal());// 3.总页数System.out.println(pages p.getPages());// 4.数据ListUser records p.getRecords();records.forEach(System.out::println);
}
这里用到了分页参数Page即可以支持分页参数也可以支持排序参数。
int pageNo 1, pageSize 5;
// 分页参数
PageUser page Page.of(pageNo, pageSize);
// 排序参数, 通过OrderItem来指定
page.addOrder(new OrderItem(balance, false));userService.page(page); 分页实体PageDTO
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.util.List;Data
ApiModel(description 分页结果)
public class PageDTOT {ApiModelProperty(总条数)private Long total;ApiModelProperty(总页数)private Long pages;ApiModelProperty(集合)private ListT list;
}
定义分页查询时查询的页号。用于前端的参数
Data
ApiModel(description 分页查询实体)
public class PageQuery {ApiModelProperty(页码)private Long pageNo;ApiModelProperty(页面大小)private Long pageSize;ApiModelProperty(排序字段)private String sortBy;ApiModelProperty(是否升序)private Boolean isAsc;
}
11.自动填充
我们在设计表时一般都需要保存数据的创建时间和更新时间为了不必要的麻烦每次都需要设置我们可以使用mybatis-plus提供的进行自动填充 构造抽象类
后续所有的实体类都可以继承这个基础的实体类以提高代码的复用性
在需要自动创建更新的属性上加上TableField注解
public abstract class BasePojo {//文件创建自动填充。需要实现MetaObjectHandle接口,进行处理TableField(fill FieldFill.INSERT)private Date created;//文件更新自动填充TableField(fill FieldFill.INSERT_UPDATE)private Date updated;
}
实现MetaObjectHandle接口
package com.tanhua.sso.handler;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;import java.util.Date;Component
public class MyMetaObjectHandler implements MetaObjectHandler {Overridepublic void insertFill(MetaObject metaObject) {// 使用严格模式插入填充如果字段为null则进行填充this.strictInsertFill(metaObject, created, Date.class, new Date()); // 创建时间this.strictInsertFill(metaObject, updated, Date.class, new Date()); // 更新时间}Overridepublic void updateFill(MetaObject metaObject) {// 使用严格模式更新填充总是设置更新时间this.strictUpdateFill(metaObject, updated, Date.class, new Date());}
}
版本兼容性问题
若业务中mybatis-plus版本较低可能不含strict方法可以采用以下写法
package com.tanhua.sso.handler;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;import java.util.Date;Component
public class MyMetaObjectHandler implements MetaObjectHandler {Overridepublic void insertFill(MetaObject metaObject) {//字段为空,自动填充字段Object created getFieldValByName(created, metaObject);if(nullcreated){setFieldValByName(created,new Date(),metaObject);}Object updated getFieldValByName(updated, metaObject);if(nullupdated){setFieldValByName(updated,new Date(),metaObject);}}Overridepublic void updateFill(MetaObject metaObject) {//更新数据时更新字段setFieldValByName(updated,new Date(),metaObject);}
}