SpringBoot MybatisPlus教程 简洁没有废话!

如果有不懂的或意见建议 欢迎评论!

文章目录 / 点个赞 点个关注吧


1. MybatisPlus 简介

MybatisPlus是基于Mybatis的封装, Mybatis的加强版, 加强了什么呢? 内部使用动态代理 自动生成增删改查操作

如果使用Mybaits 就得需要手动实现 增删改查sql, 效率低还容易出错!

MybaitPlus可以和Mybatis同时使用, 对于复杂sql, 可用继续写xml。且对于调用者来说用法都是统一的!

下面直接看看怎么用

2. 环境配置

在SpringBoot2下使用

  1. 引入依赖

    <dependency>
    	<groupId>com.baomidou</groupId>
    	<artifactId>mybatis-plus-boot-starter</artifactId>
    	<version>3.1.1</version>
    </dependency>
    
  2. 与SpringBoot集成

    在application.yml 或 application.properties文件中 加入以下配置

    mybatis-plus:
      # 指定mapper.xml文件地址
      mapper-locations: classpath:mapper/*/*Mapper.xml
      # 指定实体类包
      type-aliases-package: cn.wkpower.common.entity
      configuration:
        # 自动将下划线模式 转为 驼峰模式
        map-underscore-to-camel-case: true
    

    在启动类或其他配置类中加入

    import org.mybatis.spring.annotation.MapperScan;
    
    // 指定mapper接口的包
    @MapperScan("cn.wkpower.common.mapper")
    
  3. orm 字段映射

    请先读完这段代码

    import lombok.Data;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    
    
    @Data
    public class UserFeedback {
    
        @TableId(type = IdType.AUTO)
        private Long id;
        
        /**
         * 反馈用户的id
         */
        private Long userId;
    
        /**
         * 图片
         */
        private String img;
        /**
         * 反馈的内容
         */
        private String content;
    
        @TableField(fill = FieldFill.INSERT)
        private LocalDateTime gmtCreate;
    
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private LocalDateTime gmtModified;
    
        // ================= 补充字段区 ===================
        
        @TableField(exist = false)
        private List<String> imgList;
    
    }
    

    是的, 这段代码就完成了ORM数据库映射,Mybaits需要手动写一大串

    注解讲解

    @TableId 指定主键, 参数type为主键值类型, AUTO代表自增, 具体可直接看源码 com.baomidou.mybatisplus.annotation.IdType

类型 含义 备注
AUTO 数据库ID自增 需要数据库设置为自增
ID_WORKER 全局唯一ID (idWorker) 为空时, 框架自动填入
UUID 全局唯一ID (UUID) 为空时, 框架自动填入
ID_WORKER_STR 字符串全局唯一ID (idWorker 的字符串表示) 为空时, 框架自动填入

@TableField 指定普通映射字段

字段 含义 备注
value 数据库中表的字段名 可省略, 会自动取Java字段名
fill 字段自动填充策略 可选值 INSERT插入时填充字段,UPDATE更新时填充字段,INSERT_UPDATE插入和更新时填充字段, 具体填充什么内容呢?见后续
  1. 继承Mapper接口

    泛型为model对象。 BaseMapper这个接口可用点进源码看一看, 定义了很多可用直接用的方法, 在运行时, 这些方法会自动被实现,我们不用管

    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import cn.wkpower.common.entity.userinfo.UserFeedback;
    
    public interface UserFeedbackMapper extends BaseMapper<UserFeedback> {
    
    }
    
    
  2. 控制台打印sql 加入以下配置

        /**
         * sql性能分析插件,输出sql语句及所需时间
         */
        @Bean
        public PerformanceInterceptor performanceInterceptor() {
            return new PerformanceInterceptor();
        }
    
    

3. 查询操作

3.1 根据id查询数据

@Autowired
private UserFeedbackMapper userFeedbackMapper;

public void testSelectById(){
    UserFeedback userFeedback = userFeedbackMapper.selectById(1);
    
}

3.2 查询全部数据

@Autowired
private UserFeedbackMapper userFeedbackMapper;

public void testSelectList(){
    List<UserFeedback> userFeedbacks = userFeedbackMapper.selectList(null);
}

3.3 根据一些条件查询

    @Autowired
    private UserinfoMapper userinfoMapper;

    public void testSelectOne() {
        // 查询单个对象 selectOne返回一个对象, selectList返回一个list, 他们的插叙参数都是一样的写法
        Userinfo selectOne = userinfoMapper.selectOne(
                // 构建查询条件
                new QueryWrapper<Userinfo>().lambda()
                        // age大于等于18 sql为 age >= 18    其他: ge大于等于,gt大于,lt小于,le小于等于
                        .ge(Userinfo::getAge, 18)
                        // username的模糊搜索 sql为 %SUN%  其他: rightLike右模糊 leftLike左模糊
                        .like(Userinfo::getUsername, "SUN")
                        // sex的精确查询  sql为 sex = 1    其他: ne不等于
                        .eq(Userinfo::getSex, 1)
            			// 其他方法可以按提示键自己查看
        );

    }

3.4 根据对象查询

有时候 我们不想构建查询条件, 太麻烦了, 前端接口直接传来了对象,我们可用直接使用该进行查询, 但是每个查询条件都是精确查询 就是 =

    @Autowired
    private UserinfoMapper userinfoMapper;

    public void testSelectObjs() {
        Userinfo userinfo = new Userinfo();
        userinfo.setSex(1);
        userinfo.setAddress("西安");

        // 需强转  sql为 sex = 1 and address = '西安'
        List<Object> objects = userinfoMapper.selectObjs(new QueryWrapper<>(userinfo));
    }

3.5 自定义sql复杂查询

有时sql实在太长太复杂了, 用Java代码写会不易于维护, 必须得写SQL了, 方式如下

  1. 在mapper接口定义方法

     List<UserRelationTypeResponse> listExistRelation(@Param("deviceType")Integer deviceType, @Param("userId") Long userId);
    
  2. 在mapper.xml定义sql

        <select id="listExistRelation" resultType="cn.wkpower.common.vo.userinfo.UserRelationTypeResponse">
            SELECT
                user_relation_type
            FROM
                 <if test="deviceType == 1">
                     bpinfo
                 </if>
                <if test="deviceType == 2">
                    gluinfo
                </if>
    
            GROUP BY userid,user_relation_type
            HAVING userid = #{userId}
    
            UNION
            /* 一定存在本人的记录 */
            SELECT 1
        </select>
    
  3. 使用方式

    @Autowired
    private UserinfoMapper userinfoMapper;

    public void testCustomSql() {
        List<UserRelationTypeResponse> userRelationTypeResponses = userinfoMapper.listExistRelation(1, 1L);
    }

发现了没有, 这完全就是Mybatis啊 !

3.6 分页查询

分页功能需新加配置如下

    /**
     * 分页插件: 配置后就可用使用分页功能了
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

代码

    @Autowired
    private UserinfoMapper userinfoMapper;

    public void testPage() {
        // 查询第1页 每页20条数据, 查询条件为空
        IPage<Userinfo> userinfoIPage = userinfoMapper.selectPage(new Page<>(1, 20), new QueryWrapper<>());
        // 查询第2页 每页20条数据, 查询条件为 id倒叙
        IPage<Userinfo> userinfoIPage2 = userinfoMapper.selectPage(new Page<>(2, 20), new QueryWrapper<Userinfo>().lambda().orderByDesc(Userinfo::getUserid));

        // 获取返回结果
        List<Userinfo> records = userinfoIPage2.getRecords();
        // 获取总记录数
        long total = userinfoIPage2.getTotal();
    }

自定义的sql加入分页功能

  1. 在mapper接口的改动如下

    import com.baomidou.mybatisplus.core.metadata.IPage;
    
    
        /**
         * 第一个参数 加入分页对象
         * 返回参数 使用分页对象进行包装
         */
        IPage<BindUserListVO> unBindUserList(IPage<BindUserListVO> page, @Param("medicalId") Long medicalId, @Param("identity") Integer identity);
    
  2. 对结果的取值与上面的方式一样

    // 获取返回结果
    List<Userinfo> records = userinfoIPage.getRecords();
    // 获取总记录数
    long total = userinfoIPage.getTotal();
    

4. 保存操作 ( 增加 / 更新 )

4.1 插入一条数据

@Autowired
private UserinfoMapper userinfoMapper;

public void testInsert() {
    Userinfo userinfo = new Userinfo();
    userinfo.setAge(1);
    userinfo.setUsername("SUN");
    userinfoMapper.insert(userinfo);
}

4.2 插入数据时自动填充创建时间/更新时间

增加填充策略 配置

/**
 * 自动赋值配置
 */
@Bean
public MetaObjectHandler metaObjectHandlerConfig(){
	return new MetaObjectHandler() {
		// 添加时的策略
		@Override
		public void insertFill(MetaObject metaObject) {              
			// 设置创建时间为当前时间, gmtCreate为我的字段名 如果你写的是别的填写的
			setFieldValByName("gmtCreate", LocalDateTime.now(), metaObject); 
			// 设置修改时间为当前时间, gmtModified为我的字段名 如果你写的是别的填写的
			setFieldValByName("gmtModified", LocalDateTime.now(), metaObject);
		}
        // 更新时的策略
		@Override
		public void updateFill(MetaObject metaObject) {
			// 将修改时间设置为当前
			setFieldValByName("gmtModified",  LocalDateTime.now(), metaObject);
		}
	};
}

model类的更改

// INSERT 会走入 上面配置的insertFill方法
@TableField(fill = FieldFill.INSERT)
private LocalDateTime gmtCreate;

// INSERT_UPDATE 会走入 上面配置的insertFill方法和updateFill方法
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime gmtModified;

使用方式

// 无变化
userInfoMapper.insert(userinfo)

4.3 根据id更新数据

    @Autowired
    private UserinfoMapper userinfoMapper;

    public void testUpdateById() {
        Userinfo userinfo = new Userinfo();
        userinfo.setAge(1);
        userinfo.setUsername("SUN2");
        userinfoMapper.updateById(userinfo);
    }

4.4 更新部分字段

@Autowired
private UserinfoMapper userinfoMapper;

public void testUpdate() {
	Userinfo userinfo = new Userinfo();
	userinfo.setAge(1);
	userinfo.setUsername("SUN2");
        
	// 写法一: 第一个参数传更新的值 , 第二个参数为查询条件 
	// 最终的sql为 set age = 1, username = SUN2 WHERE address = "西安"
	userinfoMapper.update(userinfo,new QueryWrapper<Userinfo>().lambda().eq(Userinfo::getAddress,"西安"));
        
	// 写法二: 第一个参数不穿, 第二个参数为更新规则
	// 最终sql为 set age = 18, username=SUN3 WHERE age = 6
	userinfoMapper.update(null,new UpdateWrapper<Userinfo>().lambda().set(Userinfo::getAge,18).set(Userinfo::getUsername,"SUN3").eq(Userinfo::getAge,6));
    }

5. 删除操作

5.1 根据id删除数据

@Autowired
private UserinfoMapper userinfoMapper;

public void testDeleteById() {
    userinfoMapper.deleteById(1);
}

5.2 根据指定查询规则删除数据

@Autowired
private UserinfoMapper userinfoMapper;

public void testDelete() {
    // 构建一个查询条件, 凡是查出来的都会被删除 , 这个写法会删除 age = 18的数据
    userinfoMapper.delete(new QueryWrapper<Userinfo>().lambda().eq(Userinfo::getAge,18));
}

5.3 逻辑删除

逻辑删除即不删除真实数据, 而使用一个字段来表示此条记录是否被删除,常见的实现方式为手动维护 比如 select xxx where isdel = 1 / update xx set isdel = 1

但是MybatisPlus已经支持了此功能, 来看看最优雅的写法!

  1. 首先是Model类的改动

    import com.baomidou.mybatisplus.annotation.TableLogic;
    
    /**
     * 是否删除 1是 0否
     */
    @TableLogic(value = "0", delval = "1")
    private Integer isdel;
    

    字段上加了@TableLogic 注解 value表示没有被删除的值,delval表示被删除的值

  2. 删除数据的写法

    @Autowired
    private UserinfoMapper userinfoMapper;
    
    public void testDelete() {
        userinfoMapper.deleteById(1);
    }
    

    可以看见, 写法没有发生任何改变!

    实际上, 在执行以上代码时, 真正的sql将变为 UPDATE userinfo SET isdel = 1 WHERE id = 1 , 删除操作变为了对isdel字段的更新操作

    还有一个好处是:普通的查询, 例如以下代码 会自动加上 isdel = 0 查出未删除的数据!

    userinfoMapper.selectList(null);
    
上一篇:多列布局


下一篇:Netfilter是如何工作的(三) 规则的匹配(match)