当前位置: 首页 > news >正文

MyBatis-Plus 一、(基础应用)

        MyBatis-Plus(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

        mybatis 、mybatis-plus 二者区别:

        MyBatis:

  • 所有SQL语句全部自己写
  • 手动解析实体关系映射转换为MyBatis内部对象注入容器
  • 不支持Lambda形式调用

        Mybatis Plus:

  • 强大的条件构造器,满足各类使用需求
  • 内置的Mapper,通用的Service,少量配置即可实现单表大部分CRUD操作
  • 支持Lambda形式调用
  • 提供了基本的CRUD功能,连SQL语句都不需要编写
  • 自动解析实体关系映射转换为MyBatis内部对象注入容器

        

一、什么是MybatisPlus 

MybatisPlus可以节省大量时间,所有的CRUD代码都可以自动化完成

MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

  • 损耗小:启动即会自动注入基本 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、准备数据库:

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '主键id',`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姓名',`job` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '工作',`salary` double NULL DEFAULT NULL COMMENT '工资',`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',`update_time` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',`deleted` bigint(0) NULL DEFAULT 0 COMMENT '是否删除',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 191 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '张三', '随便', 2000, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);
INSERT INTO `user` VALUES (2, '李四', '程序员', 2800, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);
INSERT INTO `user` VALUES (3, '王五', '程序员鼓励师', 2700, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);
INSERT INTO `user` VALUES (4, '王二', '部门总监', 4200, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);
INSERT INTO `user` VALUES (5, '麻子', '程序员', 3000, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);
INSERT INTO `user` VALUES (6, '最帅三太子', '程序员', 3500, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);
INSERT INTO `user` VALUES (7, '苍老师', '程序员', 3700, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);
INSERT INTO `user` VALUES (8, '波多野结衣', 'CEO', 5000, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);
INSERT INTO `user` VALUES (9, '测试3', '测试工作3', 500, '2024-08-19 17:15:34', '2024-08-19 17:15:34', 0);

        2、创建项目 略

        3、引入依赖:

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.6.14</version></dependency><dependency><groupId>org.projectlombok</groupId><!----><artifactId>lombok</artifactId><optional>true</optional><version>1.18.22</version></dependency><!-- mysql驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version></dependency><!-- mybatis plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency></dependencies>

         4、添加配置:

spring:datasource:url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=truedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456transaction-isolation: 2 #具体定义可在Transactional->Isolation属性查看#hikari数据库连接池hikari:pool-name: Retail_HikariCPminimum-idle: 1 #最小空闲连接数量idle-timeout: 180000 #空闲连接存活最大时间,默认600000(10分钟)maximum-pool-size: 10 #连接池最大连接数,默认是10auto-commit: true  #此属性控制从池返回的连接的默认自动提交行为,默认值:truemax-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000

     在spring boot启动类中添加@MapperScan注解,扫描Dao文件夹:   

@SpringBootApplication
@MapperScan("com.test.demo.dao")
public class TESTApplication {public static void main(String[] args) {SpringApplication.run(TESTApplication.class,args);}}

        5、编码:

@Getter
@Setter
@ToString(callSuper = true)
@Accessors(chain = true)
@TableName("user")
public class User {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.ASSIGN_ID)private Integer id;private String name;private String type;private String job;private Double salary;private LocalDateTime createTime;private LocalDateTime updateTime;private Long deleted;}

        编写Mapper包下的Dao接口 


//再对应的mapper上面实现基本的接口 BaseMapper
@Mapper
public interface UserDao extends BaseMapper<User> {//所有的CRUD都已经完成//不需要像以前一样配置一大堆文件:pojo-dao(连接mybatis,配置mapper.xml文件)==>service-controller}

注意:

要在主启动类上去扫描mapper包下的所有接口:@MapperScan("com.test.demo.dao")

        6、简单使用 

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserDao userDao;@GetMapping("/get/{id}")public User findAll(@PathVariable("id") int id ){return userDao.selectById(id);}}

        

三、增删改查

        上面说我们dao接口继承了BaseMapper之后,基本的crud方法就可以直接使用了,就像举例中的 userDao.selectById(id) 方法一样,我们在 userDao 中并没有写 selectById() 方法,但是继承了BaseMapper之后就可以直接用了。这是因为BaseMapper已经帮我们写好了基本的crud方法,可以简单看一下源码:

public interface BaseMapper<T> extends Mapper<T> {int insert(T entity);int deleteById(Serializable id);int deleteById(T entity);int deleteByMap(@Param("cm") Map<String, Object> 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);T selectById(Serializable id);List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {List<T> ts = this.selectList(queryWrapper);if (CollectionUtils.isNotEmpty(ts)) {if (ts.size() != 1) {throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records", new Object[0]);} else {return ts.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);List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);<P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper);<P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper);
}

        上面的所有方法其实都比较容易理解,insert、delect、update、select开头的方法分别对应着增删改查,page方法代表着分页查询。

        上面的方法涵盖了单表查询的基本方法,所以如果不是复杂sql的,我们直接直接使用现成的方法进行查询。下面对各个方法做一个简单演示。

         以下面几个简单的增删改查方法为例:

    int insert(T entity);int deleteById(Serializable id);int updateById(@Param("et") T entity);T selectById(Serializable id);

        这几个方法是最基本的增删改查的方法:

        1、insert 
        User user = new User();user.setName("测试1");user.setJob("测试工作");userDao.insert(user);

        说到增加,就得提一下主键的生成策略,在mybatis中主键的生成策略需要配合标签或者注解中的属性来设置。在mybatisplus中主键的生成策略可以通过 @TableId() 注解来设置。这个注解是直接加载主键字段上面的。例如User类中:

    @TableId(value = "id", type = IdType.ASSIGN_ID)private Long id;

        上面这个设置代表的是,id字段对应数据库字段为id,且为主键。 type = IdType.ASSIGN_ID 代表 基于雪花算法的策略生成数据id。我们执行两次保存操作后,会发现数据自动填充了id:
        

         type 也可以设置为 IdType.AUTO ,代表:使用数据库的自增策略,注意:该类型需确保数据库设置了自增id,否则无效。

        加上这个注解之后,不需要再加任何配置,就可以生成主键id,这对于我们操作来说变得非常方便。至于其中的原理会放在后面说。

        还有一个注解顺便提一下:@TableId ,这个注解主要是解决属性所对应字段不一致的情况,比如说当user实体类中的name 属性命名的是 userName ,但是数据库中命名的是 name 这样不一致,查询就无法映射到对应字段,可以加上这个注解代表这两个字段是同一个:

    @TableField("name")private String userName;
         2、delect

        根据主键id 删除对应数据。

userDao.deleteById(1825476600460238849L);
         3、update

        根据主键id修改某条数据。

        User user = new User();user.setUserName("测试2");user.setJob("测试工作2");user.setId(1825476862067429378L);userDao.updateById(user);
        4、select

        根据主键id查询某条数据。

        User user = userDao.selectById(id);

        以上就是最简单的增删改查的用法,对于单表查询其实非常的方便。也就是这个其实帮我们提前写好了很多简单的sql操作,也是常用的sql操作。而且不光是 dao层 ,在service层也封装了很多操作,让我们在service层也可以非常方便进行处理。

        四、service 层增删改查

        如果想要在service层实现增删改查,就需要我们service继承 ServiceImpl 接口,其实也就是继承 Iservice 接口,Iservice 接口中含有方法如下:

public interface IService<T> {/*** 默认批次提交数量*/int DEFAULT_BATCH_SIZE = 1000;/*** 插入一条记录(选择字段,策略插入)** @param entity 实体对象*/default boolean save(T entity) {return SqlHelper.retBool(getBaseMapper().insert(entity));}/*** 插入(批量)** @param entityList 实体对象集合*/@Transactional(rollbackFor = Exception.class)default boolean saveBatch(Collection<T> entityList) {return saveBatch(entityList, DEFAULT_BATCH_SIZE);}/*** 插入(批量)** @param entityList 实体对象集合* @param batchSize  插入批次数量*/boolean saveBatch(Collection<T> entityList, int batchSize);/*** 批量修改插入** @param entityList 实体对象集合*/@Transactional(rollbackFor = Exception.class)default boolean saveOrUpdateBatch(Collection<T> entityList) {return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);}/*** 批量修改插入** @param entityList 实体对象集合* @param batchSize  每次的数量*/boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);/*** 根据 ID 删除** @param id 主键ID*/default boolean removeById(Serializable id) {return SqlHelper.retBool(getBaseMapper().deleteById(id));}/*** 根据 ID 删除** @param id      主键(类型必须与实体类型字段保持一致)* @param useFill 是否启用填充(为true的情况,会将入参转换实体进行delete删除)* @return 删除结果* @since 3.5.0*/default boolean removeById(Serializable id, boolean useFill) {throw new UnsupportedOperationException("不支持的方法!");}/*** 根据实体(ID)删除** @param entity 实体* @since 3.4.4*/default boolean removeById(T entity) {return SqlHelper.retBool(getBaseMapper().deleteById(entity));}/*** 根据 columnMap 条件,删除记录** @param columnMap 表字段 map 对象*/default boolean removeByMap(Map<String, Object> columnMap) {Assert.notEmpty(columnMap, "error: columnMap must not be empty");return SqlHelper.retBool(getBaseMapper().deleteByMap(columnMap));}/*** 根据 entity 条件,删除记录** @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/default boolean remove(Wrapper<T> queryWrapper) {return SqlHelper.retBool(getBaseMapper().delete(queryWrapper));}/*** 删除(根据ID 批量删除)** @param list 主键ID或实体列表*/default boolean removeByIds(Collection<?> list) {if (CollectionUtils.isEmpty(list)) {return false;}return SqlHelper.retBool(getBaseMapper().deleteBatchIds(list));}/*** 批量删除** @param list    主键ID或实体列表* @param useFill 是否填充(为true的情况,会将入参转换实体进行delete删除)* @return 删除结果* @since 3.5.0*/@Transactional(rollbackFor = Exception.class)default boolean removeByIds(Collection<?> list, boolean useFill) {if (CollectionUtils.isEmpty(list)) {return false;}if (useFill) {return removeBatchByIds(list, true);}return SqlHelper.retBool(getBaseMapper().deleteBatchIds(list));}/*** 批量删除(jdbc批量提交)** @param list 主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)* @return 删除结果* @since 3.5.0*/@Transactional(rollbackFor = Exception.class)default boolean removeBatchByIds(Collection<?> list) {return removeBatchByIds(list, DEFAULT_BATCH_SIZE);}/*** 批量删除(jdbc批量提交)** @param list    主键ID或实体列表(主键ID类型必须与实体类型字段保持一致)* @param useFill 是否启用填充(为true的情况,会将入参转换实体进行delete删除)* @return 删除结果* @since 3.5.0*/@Transactional(rollbackFor = Exception.class)default boolean removeBatchByIds(Collection<?> list, boolean useFill) {return removeBatchByIds(list, DEFAULT_BATCH_SIZE, useFill);}/*** 批量删除(jdbc批量提交)** @param list      主键ID或实体列表* @param batchSize 批次大小* @return 删除结果* @since 3.5.0*/default boolean removeBatchByIds(Collection<?> list, int batchSize) {throw new UnsupportedOperationException("不支持的方法!");}/*** 批量删除(jdbc批量提交)** @param list      主键ID或实体列表* @param batchSize 批次大小* @param useFill   是否启用填充(为true的情况,会将入参转换实体进行delete删除)* @return 删除结果* @since 3.5.0*/default boolean removeBatchByIds(Collection<?> list, int batchSize, boolean useFill) {throw new UnsupportedOperationException("不支持的方法!");}/*** 根据 ID 选择修改** @param entity 实体对象*/default boolean updateById(T entity) {return SqlHelper.retBool(getBaseMapper().updateById(entity));}/*** 根据 UpdateWrapper 条件,更新记录 需要设置sqlset** @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}*/default boolean update(Wrapper<T> updateWrapper) {return update(null, updateWrapper);}/*** 根据 whereEntity 条件,更新记录** @param entity        实体对象* @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}*/default boolean update(T entity, Wrapper<T> updateWrapper) {return SqlHelper.retBool(getBaseMapper().update(entity, updateWrapper));}/*** 根据ID 批量更新** @param entityList 实体对象集合*/@Transactional(rollbackFor = Exception.class)default boolean updateBatchById(Collection<T> entityList) {return updateBatchById(entityList, DEFAULT_BATCH_SIZE);}/*** 根据ID 批量更新** @param entityList 实体对象集合* @param batchSize  更新批次数量*/boolean updateBatchById(Collection<T> entityList, int batchSize);/*** TableId 注解存在更新记录,否插入一条记录** @param entity 实体对象*/boolean saveOrUpdate(T entity);/*** 根据 ID 查询** @param id 主键ID*/default T getById(Serializable id) {return getBaseMapper().selectById(id);}/*** 查询(根据ID 批量查询)** @param idList 主键ID列表*/default List<T> listByIds(Collection<? extends Serializable> idList) {return getBaseMapper().selectBatchIds(idList);}/*** 查询(根据 columnMap 条件)** @param columnMap 表字段 map 对象*/default List<T> listByMap(Map<String, Object> columnMap) {return getBaseMapper().selectByMap(columnMap);}/*** 根据 Wrapper,查询一条记录 <br/>* <p>结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/default T getOne(Wrapper<T> queryWrapper) {return getOne(queryWrapper, true);}/*** 根据 Wrapper,查询一条记录** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}* @param throwEx      有多个 result 是否抛出异常*/T getOne(Wrapper<T> queryWrapper, boolean throwEx);/*** 根据 Wrapper,查询一条记录** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/Map<String, Object> getMap(Wrapper<T> queryWrapper);/*** 根据 Wrapper,查询一条记录** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}* @param mapper       转换函数*/<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);/*** 查询总记录数** @see Wrappers#emptyWrapper()*/default long count() {return count(Wrappers.emptyWrapper());}/*** 根据 Wrapper 条件,查询总记录数** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/default long count(Wrapper<T> queryWrapper) {return SqlHelper.retCount(getBaseMapper().selectCount(queryWrapper));}/*** 查询列表** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/default List<T> list(Wrapper<T> queryWrapper) {return getBaseMapper().selectList(queryWrapper);}/*** 查询所有** @see Wrappers#emptyWrapper()*/default List<T> list() {return list(Wrappers.emptyWrapper());}/*** 翻页查询** @param page         翻页对象* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {return getBaseMapper().selectPage(page, queryWrapper);}/*** 无条件翻页查询** @param page 翻页对象* @see Wrappers#emptyWrapper()*/default <E extends IPage<T>> E page(E page) {return page(page, Wrappers.emptyWrapper());}/*** 查询列表** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {return getBaseMapper().selectMaps(queryWrapper);}/*** 查询所有列表** @see Wrappers#emptyWrapper()*/default List<Map<String, Object>> listMaps() {return listMaps(Wrappers.emptyWrapper());}/*** 查询全部记录*/default List<Object> listObjs() {return listObjs(Function.identity());}/*** 查询全部记录** @param mapper 转换函数*/default <V> List<V> listObjs(Function<? super Object, V> mapper) {return listObjs(Wrappers.emptyWrapper(), mapper);}/*** 根据 Wrapper 条件,查询全部记录** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/default List<Object> listObjs(Wrapper<T> queryWrapper) {return listObjs(queryWrapper, Function.identity());}/*** 根据 Wrapper 条件,查询全部记录** @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}* @param mapper       转换函数*/default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {return getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());}/*** 翻页查询** @param page         翻页对象* @param queryWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}*/default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {return getBaseMapper().selectMapsPage(page, queryWrapper);}/*** 无条件翻页查询** @param page 翻页对象* @see Wrappers#emptyWrapper()*/default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {return pageMaps(page, Wrappers.emptyWrapper());}/*** 获取对应 entity 的 BaseMapper** @return BaseMapper*/BaseMapper<T> getBaseMapper();/*** 获取 entity 的 class** @return {@link Class<T>}*/Class<T> getEntityClass();/*** 以下的方法使用介绍:** 一. 名称介绍* 1. 方法名带有 query 的为对数据的查询操作, 方法名带有 update 的为对数据的修改操作* 2. 方法名带有 lambda 的为内部方法入参 column 支持函数式的* 二. 支持介绍** 1. 方法名带有 query 的支持以 {@link ChainQuery} 内部的方法名结尾进行数据查询操作* 2. 方法名带有 update 的支持以 {@link ChainUpdate} 内部的方法名为结尾进行数据修改操作** 三. 使用示例,只用不带 lambda 的方法各展示一个例子,其他类推* 1. 根据条件获取一条数据: `query().eq("column", value).one()`* 2. 根据条件删除一条数据: `update().eq("column", value).remove()`**//*** 链式查询 普通** @return QueryWrapper 的包装类*/default QueryChainWrapper<T> query() {return ChainWrappers.queryChain(getBaseMapper());}/*** 链式查询 lambda 式* <p>注意:不支持 Kotlin </p>** @return LambdaQueryWrapper 的包装类*/default LambdaQueryChainWrapper<T> lambdaQuery() {return ChainWrappers.lambdaQueryChain(getBaseMapper());}/*** 链式查询 lambda 式* kotlin 使用** @return KtQueryWrapper 的包装类*/default KtQueryChainWrapper<T> ktQuery() {return ChainWrappers.ktQueryChain(getBaseMapper(), getEntityClass());}/*** 链式查询 lambda 式* kotlin 使用** @return KtQueryWrapper 的包装类*/default KtUpdateChainWrapper<T> ktUpdate() {return ChainWrappers.ktUpdateChain(getBaseMapper(), getEntityClass());}/*** 链式更改 普通** @return UpdateWrapper 的包装类*/default UpdateChainWrapper<T> update() {return ChainWrappers.updateChain(getBaseMapper());}/*** 链式更改 lambda 式* <p>注意:不支持 Kotlin </p>** @return LambdaUpdateWrapper 的包装类*/default LambdaUpdateChainWrapper<T> lambdaUpdate() {return ChainWrappers.lambdaUpdateChain(getBaseMapper());}/*** <p>* 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法* 此次修改主要是减少了此项业务代码的代码量(存在性验证之后的saveOrUpdate操作)* </p>** @param entity 实体对象*/default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {return update(entity, updateWrapper) || saveOrUpdate(entity);}
}

        Iservice 中方法非常多,也就说如果我们的servcie 层接口实现了 Iservice,那这些方法等于都已经默认帮我们实现了,所以我们在service层也就可以非常方便的进行增删改查的操作了。简单讲讲增删改查的操作:
        首先根据service层的规范先进行定义service接口,再用serviceImpl去实现service,如下:
        1、定义service接口 并继承 IService:

public interface IUserService extends IService<User> {}

        2、定义service实现类,并继承ServiceImpl 。

@Service
public class UserService extends ServiceImpl<UserDao, User> implements IUserService {}

        此时我们就可以使用上面所提供的方法了:

        1、save
        User user = new User();user.setUserName("测试2");user.setJob("测试工作2");userService.save(user);
        2、remove
        userService.removeById(user.getId());
      3、update
        User user = new User();user.setUserName("测试3");user.setJob("测试工作3");user.setId(1825476862067429378L);userService.updateById(user);
        4、get
        User user = userService.getById(user.getId());

        上面就是根据主键id进行的增删改查最基础的方法。

        因为IService提供了很多方法,有很多其实应用场景很小,所以下一篇会简单讲讲 其他方法的应用。

五、条件构造器

        BaseMapper 与 Iservice 提供的方法一般只能满足基本的sql语句,如果需要执行复杂的带条件的sql,mybatisplus支持原生的mabatis中的功能,所以如果进行复杂sql,例如多条件动态sql或者多表查询,我们依然可以使用 使用@Servcie、@Update 等注解或者在mapper.xml文件中使用标签书写sql。
        但是其实MybatisPlus中也为我们提供了条件构造器,来执行复杂的多条件动态查询等方法。

        例如通用service常用方法:

  • 新增:
    • default boolean save(T entity):新增记录
    • boolean saveBatch(Collection<T> entityList):批量插入
    • saveBatch(Collection<T> entityList, int batchSize):一次性批量插入batchSize条记录
  • 删除:
    • boolean removeById(Serializable id):根据id删除
    • boolean removeByMap(Map<String, Object> columnMap):根据条件删除
    • boolean remove(Wrapper<T> queryWrapper):使用Wrapper封装条件删除
    • boolean removeByIds(Collection<? extends Serializable> idList):删除一批
  • 修改:
    • boolean updateById(T entity):修改
    • boolean update(Wrapper<T> updateWrapper):根据Wrapper修改
    • boolean update(T entity, Wrapper<T> updateWrapper):使用Wrapper查询出结果,修改为entity
    • boolean updateBatchById(Collection<T> entityList):批量修改
    • updateBatchById(Collection<T> entityList, int batchSize):一次性批量修改batchSize条记录
    • boolean saveOrUpdate(T entity):如果id存在则修改,如果id不存在则新增
  • 查询:
    • T getById(Serializable id):根据id查询
    • List<T> listByIds(Collection<? extends Serializable> idList):根据一批id查询多条记录
    • List<T> listByMap(Map<String, Object> columnMap):根据条件查询多条记录
    • T getOne(Wrapper<T> queryWrapper):根据Wrapper查询一条记录,如果查询到多条则抛出异常
    • T getOne(Wrapper<T> queryWrapper, boolean throwEx):根据Wrapper查询一条记录,通过throwEx决定是否抛出异常
    • int count():查询总记录数
    • int count(Wrapper<T> queryWrapper):根据条件查询总记录数
  • 分页:
    • <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper):带条件分页查询,当前页数据为T类型
    • <E extends IPage<T>> E page(E page):无条件分页
    • List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper):带条件分页查询,当前页数据为HashMap类型
    • List<Map<String, Object>> listMaps():无条件分页

        在有一些方法中的参数类型是 Wrapper<T> queryWrapper ,这个就是条件构造器,例如 

T getOne(Wrapper<T> queryWrapper):根据Wrapper查询一条记录,如果查询到多条则抛出异常

        例如上面这个方法,使用如下所示:

        QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("name","张三");User user = userService.getOne(wrapper);

        代表的意思就是查询 name 字段等于张三的数据,并且这条数据必须唯一。
        eq()这个就是Wrapper接口中提供的相关函数,映射在sql语句中的方法是 = ,代表相等。
        除了eq()还提供了其他很多相关映射函数:  

  1、QueryWrapper

  QueryWrapper用于构建查询条件,可以通过链式调用的方式组装各种查询条件。

        QueryWrapper的基本用法:

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;public class QueryWrapperExample {public static void main(String[] args) {QueryWrapper<User> queryWrapper = new QueryWrapper<>();// 等值条件queryWrapper.eq("name", "John");// 不等值条件queryWrapper.ne("age", 25);// 大于条件queryWrapper.gt("create_time", "2022-01-01");// 小于等于条件queryWrapper.le("update_time", "2023-01-01");// 模糊查询queryWrapper.like("email", "@gmail.com");// 排序queryWrapper.orderByAsc("age");// 使用Lambda表达式queryWrapper.lambda().eq(User::getName, "Alice");// 打印SQL语句System.out.println("SQL: " + queryWrapper.getSqlSelect());}
}

  Lambda表达式的高级用法:
  QueryWrapper支持Lambda表达式,可以进一步简化代码,提高可读性。

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;public class LambdaQueryWrapperExample {public static void main(String[] args) {QueryWrapper<User> queryWrapper = new QueryWrapper<>();// Lambda表达式queryWrapper.lambda().eq(User::getName, "John").ne(User::getAge, 25).like(User::getEmail, "@gmail.com");// 打印SQL语句System.out.println("SQL: " + queryWrapper.getSqlSelect());}
}

如果要使用Lambda表达式的用法,我们也可以直接使用 LambdaQueryWrapper。

        2、LambdaQueryWrapper

        可以把LambdaQueryWrapper看作是实现了Lambda语法的 QueryWrapper,使用方式跟QueryWrapper 一样,只不过可以不用 lambda() 就可以直接使用lambda语法。

        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getName,"张三");User user = userService.getOne(wrapper);
        3、UpdateWrapper

  UpdateWrapper用于构建更新条件,与QueryWrapper类似,也支持链式调用和Lambda表达式。
        注意:在调用更新方法的时候会用到这个。

        基本用法:

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;public class UpdateWrapperExample {public static void main(String[] args){UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();// 等值条件updateWrapper.eq("name", "John");// 不等值条件updateWrapper.ne("age", 25);// 大于条件updateWrapper.gt("create_time", "2022-01-01");// 小于等于条件updateWrapper.le("update_time", "2023-01-01");// 模糊查询updateWrapper.like("email", "@gmail.com");// 使用Lambda表达式updateWrapper.lambda().set(User::getName, "Alice").eq(User::getAge, 30);// 打印SQL语句System.out.println("SQL: " + updateWrapper.getSqlSet());}
}

        UpdateWrapper的基本用法与QueryWrapper类似,可以通过链式调用添加等值、不等值、范围、模糊等更新条件。

         Lambda表达式的高级用法:

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;public class LambdaUpdateWrapperExample {public static void main(String[] args) {UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();// Lambda表达式updateWrapper.lambda().set(User::getName, "Alice").eq(User::getAge, 30).like(User::getEmail, "@gmail.com");// 打印SQL语句System.out.println("SQL: " + updateWrapper.getSqlSet());}
}

        通过lambda方法,我们可以使用实体类的属性名,使得代码更加简洁和可读。

        4、 LambdaUpdateWrapper

        与LambdaQueryWrapper 一样,用法与UpdateWrapper 也都一样,只是默认实现了Lambda语法。

        条件构造器的详细用法放下下一篇单独写。

六、分页查询

         mybatisplus有自己的内置分页插件,用起来非常方便,不像mybatis还需要引入第三方依赖。

        使用步骤非常简单,只要两步即可:

        1、配置拦截器组件
/*** 注册插件*/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
​MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();// 设置请求的页面大于最大页后操作,true调回到首页,false继续请求。默认falsepageInterceptor.setOverflow(false);// 单页分页条数限制,默认无限制pageInterceptor.setMaxLimit(500L);// 设置数据库类型pageInterceptor.setDbType(DbType.MYSQL);
​interceptor.addInnerInterceptor(pageInterceptor);return interceptor;
}
        2、直接使用
    // 两个参数:current的值默认是1,从1开始,不是0。size是每一页的条数。// 意思是查询 第一页,每页10条数据Page<User> page = new Page<>(1, 10);userMapper.selectPage(page);page.getRecords().forEach(System.out::println);

        返回结果 第一页 10条数据成功:

         测试第二页 只有一条数据:

七、mybatisplus常用注解

        @TableName

        @TableName注解用于指定实体类对应的数据库表名。使用该注解可以省去手动编写SQL语句的繁琐过程。
        实例:表名为 db_user,对应的实体类 User

@TableName(value = "db_user")
public class User {// 实体类字段
}
        @TableField

         @TableField是MyBatis-Plus中的注解之一,用于在实体类中指定字段与数据库表中字段的映射关系。通过@TableField注解,可以将实体类中的字段与数据库表中的字段进行映射,从而简化数据访问层的开发。

        @TableField注解提供了多个属性,常用的属性包括:

  • value:指定数据库表字段的名称。用于映射非主键字段,还可以解决关键字报错
  • exist:指定该字段是否为数据库表字段,默认为true。是否忽略该字段
  • fill:指定字段填充策略,如插入时自动填充、更新时自动填充等。自动填充,将对象存入数据库的时候,由 MyBatis Plus 自动给某些字段赋值,例如:create_time、update_time
  • select:指定该字段是否参与查询,默认为true。是否查询该字段
  • update: 预处理set字段自定义注入
  • condition:指定该字段在查询条件中的匹配方式,如LIKE、EQUAL等。

        示例:

@Data
@TableName(value = "student")
public class Student {@TableIdprivate Long id;// 当该字段名称与数据库名字不一致@TableField(value = "name")private String name;// 不查询该字段@TableField(select = false)private Integer age;// 当数据库中没有该字段,就忽略@TableField(exist = false)private String gender;// 执行的sql语句就变成`关键字`,这样sql就不会报错了@TableField(value = "`desc`")private string desc// 第一次添加填充@TableField(fill = FieldFill.INSERT)private Date createTime;// 第一次添加的时候填充,但之后每次更新也会进行填充@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateTime;}

        自动填充演示:

        1、第一步像上面一样先添加注解,@TableField(fill = FieldFill.INSERT) 代表当数据第一次添加时更新,@TableField(fill = FieldFill.INSERT_UPDATE) 代表数据添加或者更新时都更新该字段。
        2、创建自动填充处理器

// 加入注解才能生效
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}@Overridepublic void updateFill(MetaObject metaObject) {this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}}

        3、测试就忽略了,可以自己试一下当调用update和save的方法时就会自动填充或者更新该字段。

        condition 预处理演示:

    /*** 角色名称*/@TableField(condition = SqlCondition.LIKE)private String name;输出 SQL 为:select 表 where name LIKE CONCAT('%',值,'%')

        意思是说当我们将实体类的这个字段加上这个注解时,在使用该实体类作为条件 构建条件构造器时,会自动为我们拼接一个模糊查询的条件。

        例如:

        User user = new User();user.setName("张三");LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(user);System.out.println(userService.list(wrapper));

 

         update 预处理set字段:

         比如我们使用mybatisplus自带的insert()方法向数据库插入数据时,假设我们给age字段赋值为1,但是我们在age字段上的@TableField注解里面加了update="%s+1",那么真真插入到数据库的值就是age=2,而不是age+1了)

例如:@TableField(.. , update="%s+1") 其中 %s 会填充为字段
输出 SQL 为:update 表 set 字段=字段+1 where ...

        如果给某个字段上@TableField注解里面写update=“now()”,那么最后我们使用mybatisplus自带的insert()方法向数据库插入数据时,这个字段插入到数据库中的值就为当前时间,看下面代码的sql语句即可明白

例如:@TableField(.. , update="now()") 使用数据库时间
输出 SQL 为:update 表 set 字段=now() where ...
        @TableId

        作用:用于标记实体类属性对应的数据库主键。

        @TableId是MyBatis-Plus中的注解之一,用于在实体类中指定主键与数据库表中主键的映射关系。通过@TableId注解,可以将实体类中的主键与数据库表中的主键进行映射,从而简化数据访问层的开发。

        使用@TableId注解时,可以指定主键的属性,例如主键的类型、是否为自增、是否为全局唯一标识符等

        试例:

public class User {@TableId(value = "id", type = IdType.ASSIGN_ID)private Long id;// 省略getter和setter方法
}

   value 映射主键字段名 ,type 设置主键类型,主键的生成策略。type有五个常用属性:

     (1)NONE,默认的,数据库主键id自增,使用雪花算法实现,实体类中的主键应设置为long类型,避免生成的主键id长度过长而溢出
(2)input,如果开发者手动赋值,则存入该值,如果开发者没有手动赋值,则数据库通过自增方式给主键赋值
(3)AUTO默认就是数据库自增,开发者无需赋值,如果开发者手动赋值,数据库也不会存入该值
(4)ASSIGN_ID,通过雪花算法自动生成id,生成主键非自增
(5)ASSIGN_UUID,主键类型必须为String类型,雪花算法自动生成
要求数据库字段类型,实体类型必须为String

  • 在某些情况下,我们想提前获取这个ID,调用com.baomidou.mybatisplus.core.toolkit.IdWorker.getId()方法即可

        @TableLogic

        映射逻辑删除,并不是真正的删除

1、数据表添加 deleted 字段,默认是0

2、实体类添加注解

package com.md.entity;import com.baomidou.mybatisplus.annotation.*;
import com.md.enums.StatusEnum;
import lombok.Data;
import java.util.Date;@Data
@TableName(value = "student")
public class Student {@TableIdprivate Long id;@TableField(value = "name")private String name;@TableField(select = false)private Integer age;@TableField(exist = false)private String gender;@TableField(fill = FieldFill.INSERT)private Date createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateTime;@Versionprivate Integer version;private StatusEnum status;@TableLogicprivate Integer deleted;
}

3、主配置文件中添加配置

# 没有删除为0,删除了为1
mybatis-plus:global-config:db-config:logic-not-delete-value: 0logic-delete-value: 1

        删除的时候不是真正的删除数据库表中的数据,而是改变delete字段的值,当然了查询的时候也是查询delete=0,这都是框架自动实现的

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • ROS2常用指令
  • 探索ISP自动曝光技术:工作原理与应用(一)
  • IEEE802网络协议和标准
  • 固废检测算法实际应用方案固废检测算法源码解析
  • ChatGPT 3.5/4.0 新手使用手册
  • 如何为你的SEO策略找到竞争对手的关键词
  • 网络安全学习路线图(2024版详解)
  • 快速上手 STL中 map 和 set 的使用
  • CAN的简介
  • 微服务的负载均衡不同的场景应用
  • Is it possible to modify OpenAI environments?
  • 进程的创建、终止
  • 【安全靶场】-DC-7
  • UE赋予某个C++类tick的能力
  • git错误fatal: Unpack error, check server log
  • ----------
  • canvas 绘制双线技巧
  • CSS实用技巧
  • egg(89)--egg之redis的发布和订阅
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • es6(二):字符串的扩展
  • jquery ajax学习笔记
  • JS+CSS实现数字滚动
  • magento 货币换算
  • nfs客户端进程变D,延伸linux的lock
  • Vue ES6 Jade Scss Webpack Gulp
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 构建工具 - 收藏集 - 掘金
  • ------- 计算机网络基础
  • 近期前端发展计划
  • 微信小程序填坑清单
  • 学习HTTP相关知识笔记
  • 用简单代码看卷积组块发展
  • 原生js练习题---第五课
  • 正则学习笔记
  • mysql面试题分组并合并列
  • python最赚钱的4个方向,你最心动的是哪个?
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • # 职场生活之道:善于团结
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (翻译)terry crowley: 写给程序员
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • (区间dp) (经典例题) 石子合并
  • (转) ns2/nam与nam实现相关的文件
  • (转)母版页和相对路径
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net CHARTING图表控件下载地址
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET Core跨平台微服务学习资源
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET MAUI Sqlite程序应用-数据库配置(一)
  • .NET 反射的使用