前言

mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。

一、mybatis-plus简介:

Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。

二、SpringBoot 整合 Mybatis-plus

在SpringBoot的特性下,整合Mybatis-plus也尤为简单。接下来看具体操作:

1、pom.xml:

核心依赖如下:

<!-- mybatis-plus启动场景 -->
<dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>3.3.0</version>
 </dependency>
 <!--代码生成器,根据mybatis逆向工程-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.3.0</version>
</dependency>
 <!--mysql连接驱动-->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
</dependency>

注意 这里使用的数据库为mysql ,还运用到了日志slf4j、lombok等,可以自行了解

2、application.yml: springboot 启动配置 - 数据源配置
# [] 内需要自己修改
spring:
  datasource:
    username: [数据库账户]
    password: [数据库密码]
    url: jdbc:mysql://[url]/[dbbase]?useUnicode=true&characterEncoding=utf8
    driver-class-name: com.mysql.cj.jdbc.Driver
3、 数据表 User表

id

name

age

email

1

Jone

18

test1@baomidou.com

2

Jack

20

test2@baomidou.com

3

Tom

28

test3@baomidou.com

4

Sandy

21

test4@baomidou.com

5

Billie

24

test5@baomidou.com

对应 schema-user.sql

DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);

对应 data-user.sql

DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

建立好数据,接下来就是java类的配置,可以通过mybatis-plus的代码生成器generator生成,generator生成自行了解;

4 、 entity 对应数据表结构实体类,
@Data 
@TebleName(value = "user")
public class user implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @TableField(value = "name",exist = true)
    private String userName;
    private String age;
    private String email;
}

@Data : lombok(需要安装lombok插件) 自动设置 getter setter toString 保证代码整洁
@TebleName:对应表名,可以不写,默认以驼峰命名法进行表名匹配,还有其他前缀、后缀等匹配方式可以去自行了解,一般直接使用标准驼峰就行
@TableId :id 列,type = IdType.AUTO 当主键为自增时,insert(user) 时,user.id会自动赋值
@TableField:表字段,若没有开启驼峰命名,或者表中列名不符合驼峰规则,可通过该注解指定数据库表中的列名,exist标明数据表中有没有对应列

5、分页插件、mapper扫描配置
@Configuration
@MapperScan({"com.exmple.*.dao"})//扫描dao层接口
public class MybatisPlusConfig {

    //分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        // 设置sql的limit为无限制,默认是500
        return new PaginationInterceptor().setLimit(-1);
    }

}

分页组件

Page<User> page = new Page<>(current,size);//当前页与页面数量
6、dao 持久层
public interface UserDao extends BaseMapper<User> {
	@Select("select u.id as `id` .... from user u left join .. where..")
	@ResultType(UserVo.class)
	public UserVo getOne();

	public UserInfo selectUserInfo(@Param("query")User user);
}

在dao层可以进行多种方式定义sql操作,

  1. 直接使用@Select、@Insert、@Update等标签直接写入使用拼接,用 <script></script>包裹可以使用如xml里写法的<if><where>等标签
  2. 原始的写法用映射Mapper.xml的方式进行使用
  3. 定义sql拼接的方法类进行处理,这里不做演示

BaseMapper里 定义了大量CRUD的方法,可直接使用,不用再去定义基础CRUD的sql

public interface BaseMapper<T> extends Mapper<T> {
	/** 按entity 字段插入数据 */
    int insert(T entity);
    /** 根据id删除   sql为 deleted from tablename where id = #{id} */
    int deleteById(Serializable id);
	/** 根据map 中定义的 key与value 作为条件 删除数据 */ 		
    int deleteByMap(@Param("cm") Map<String, Object> columnMap);
    /** 根据Wrapper(条件构造器) 删除数据 */
    int delete(@Param("ew") Wrapper<T> wrapper);
    /** 根据id集 批量删除数据 */
    int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
    /** 根据id 修改数据 */
    int updateById(@Param("et") T entity);
    /** 根据Wrapper(条件构造器) 修改数据 */
    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
    /** 根据id 查询数据 */
    T selectById(Serializable id);
    /** 根据id集 查询数据 */
    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
    /** 根据map 中定义的 key与value 作为条件 查询数据 */
    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
    /** 根据Wrapper(条件构造器) 查询单条数据 */
    T selectOne(@Param("ew") Wrapper<T> queryWrapper);
    /** 根据Wrapper(条件构造器) 统计数据*/
    Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
    /** 根据Wrapper(条件构造器) 查询数据*/
    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
    /** 根据Wrapper(条件构造器) 查询数据*/
    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
    /** 根据Wrapper(条件构造器) 查询数据*/
    List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
    /** 根据Wrapper(条件构造器) 分页查询数据*/
    <E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
    /** 根据Wrapper(条件构造器) 分页查询数据*/
    <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
7、Mapper.xml 映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.exmple.admin.dao.UserDao">
	<resultMap id="userInfoMap" type=".....UserInfo">
        <id column="id" property="userId" />
        .....
    </resultMap>
    
	<select id = 'selectUserInfo' resultMap = 'userInfoMap' >
		select ... from user u left join ...
		<where>
			u.id = #{query.id} ... 
		</where>
	</select>
</mapper>

在Mapper.xml 里可以写复杂sql,利用自定义返回map进行数据封装返回

8、Service 逻辑层
//定义逻辑层接口,继承IService
public interface UserService extends IService<User> {
	@Transactional(rollbackFor = {Exception.class})
	boolean deleteUsers(List<Integer> uids);
}
//定义逻辑层实现类,继承ServiceImpl
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
	//UserDao为baseMapper,导入其他数据库服务资源
    @Resource
    private  RoleDao roleDao;
    @Override
    public boolean deleteUsers(List<Integer> uids){
        uids.forEach(id ->{
        	baseMapper.deleteById(id);
        	//TODO 删除其他关联属性
        	roleDao.......;
        })
    }
}

@Transactional 开启事务控制,rollbackFor指定异常回滚类型
这里的baseMapper 就是 UserDao;

IService 也内置了大量CRUD操作方法,ServiceImpl 根据内置 BaseMapper( 这里是UserDao)实现了 IService 方法,
ServiceImpl 默认装在了baseMapper

public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
    protected Log log = LogFactory.getLog(this.getClass());
    @Autowired
    protected M baseMapper;

    public ServiceImpl() {
    }

    public M getBaseMapper() {
        return this.baseMapper;
    }

   .....
}
8. 条件构造器 Wrapper

Wrapper 可作为条件拼接对应的sql帮助我们实现一些稍微复杂的CRUD操作,并且不用去自己编写SQL,通过链式调用实现SQL拼接,减少手写sql的麻烦

//QueryWrapper 查询条件wrapper 可用于 单表查询、删除查询
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda() //一般统一使用lambda表达式
                .like(username != null,User::getName,username)//username != null 条件成立才进行拼接,名字模糊查询 
                .lt(User::getAge, 18)//年纪小于18
                .eq(..)//相等查询
                .....;
    Page<User> users = userService.page(page,queryWrapper)
 //UpdateWrapper 修改wrapper 可用于 修改
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();       
        queryWrapper.lambda() //一般统一使用lambda表达式
        .set(!StringUtils.isEmpty(emailStr),User::getEmail, emailStr)//邮箱不为空时,修改有效
        .eq(User::getId,id);//根据Id修改
    userService.update(updateWrapper);
9 坑补充
if test
  1. 当参数为数字型时,如果为0 ,会与 ‘’ 空字符串相等
<if test = "query.status != null and query.status != '' "> <!--status = 0 flase-->
</if>
当status 为数字型 应该写成
<if test = "query.status != null"> <!--status = 0  true-->
</if>
  1. 当判断参数相等时,要使用双引号 “”
<if test = "query.name == '张三'  "> <!--不生效-->
</if>
应该写成
<if test = 'query.name == "张三"'> 
</if>
jdbcType使用

当值为null 时,无法转换类型,

t.id = #{query.id,jdbcType = VARCHAR}
若希望使用null,不要加jdbcType  
t.id = #{query.id}
warpper中 like

使用MP中 QueryWrapper 中like 会发现他是将 % + val + % (val为用户的参数)作为参数进行sql注入

springboot 整合db2 springboot 整合mybatis-plus_构造器


如果val 传入的是 % ,_ , \ 等特殊字符,会发现不会被转义 ,生成的SQL为

like '%%%'  查询出所有数据
like '%_%'   查询出所有数据
like '%\%'   查询出所有以%结尾的数据

这样就不是我们想要查询的结果。
处理方式:

  1. 每次在使用like命令入参时,对特殊字符转义处理
  2. 设置自定义拦截器

总结:

以上便是个人对mybatis-plus的使用的总结,主要基于SpringBoot配置、;介绍了通用crud的使用、全局策略的配置以及条件构造器的使用,但是这并不是MP的所有内容,其强大不限于此。