转载

springboot+mybatis+mybaits plus 整合与基本应用

springboot+mybatis+mybaits plus 整合与基本应用

引言

spring framework 所支持的 orm 框架中, mybatis 相比 hibernatespring 本身提供的支持是相对少的,这在开发过程中对使用 mybatis 进行开发的程序员来说无疑产生很多难处。

为此,开源上也产生了很多三方对 mybatis 的一些增强工具,比如 ourbatismybatis-generator 等等。这篇我们主要来说下功能丰富、现在还在迭代的一款国人开发的增强工具 mybatis-plus 。就像官方文档说的那样

我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

可以看出, mybatis-plus 是了为了提高效率和简化配置而生的。下面就来展示下在 springboot 下如何整合 mybatis-plus

准备工作

首先是创建一个 springboot 工程

springboot+mybatis+mybaits plus 整合与基本应用

引入相关依赖( springboot 相关、 mybaitsmybatis-plus 等等)

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- springboot对mybaits的自动配置依赖 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- mybatis-plus相关依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
    </dependencies>

使用 mybaits-plus 的代码生成器映射生成代码,我们这里所使用的数据库为 mysql 。这个在另外一篇文章上说明,这里就不讲述了。

在这里, mybaits-plus 提供了 BaseMapperBaseService 这些基类来提供一些操作的支持,比如

save(T t)
saveOrUpdate(T t)
update(T t, Wrapper<T> wrapper)
page(IPage<T> page, Wrapper<T> queryWrapper)

等等。

下面,我们就简单介绍下 springboot 中怎么运用 mybaits-plus

配置

首先是说到配置,这里默认以 yml 文件来进行对 mybaits-plus 的配置。

mybatis-plus:
  #MyBatis Mapper 所对应的 XML 文件位置
  mapper-locations: classpath*:mapper/*.xml
  #  MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,
  #注册后在 Mapper 对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名)
  typeAliasesPackage: com.luwei.models
  # 与 typeAliasesPackage 一起使用,仅扫描以该类作为父类的类
  # type-aliases-super-type: java.lang.Object
  # 配置扫描通用枚举,配置该属性,会对枚举类进行注入
  typeEnumsPackage: com.luwei.demo.mybatisplusdemo.envm
  # 该包下的类注册为自定义类型转换处理类,用于属性类型转换
  # type-handlers-package: com.luwei.demo.mybatisplusdemo.handler
  # 指定 mybatis 处理器
  # executorType: simple
  
  configuration:
    #使用驼峰法映射属性,配置这个resultType可以映射
    map-underscore-to-camel-case: true
  global-config:
    db-config:
      # 配置表明前缀,例如表设计时表名为tb_manager,对应entity为Manager
      table-prefix: tb_
      #逻辑已删除值
      logic-delete-value: 1 
      #逻辑未删除值
      logic-not-delete-value: 0 
      # 是否开启like查询,即对 stirng 字段是否使用 like,默认不开启
      # column-like: false
      
logging:
  level:
      # 日志级别,显示操作sql
    com.luwei.demo.mybatisplusdemo.mapper: debug

基本上这些配置都能满足一般的应用了。

CRUD 接口

上面说到, BaseMapperBaseService 已经实现了一些基本操作,下面简单说下这些接口的用法

查询

查询中 Mybatis-plus 提供多种封装好的方式,包括对主键查询、指定条件查询、分页查询等。

Manager manager1 = managerService.getById(1);
Assert.assertNotNull(manager1);

LambdaQueryWrapper<Manager> wrapper = new LambdaQueryWrapper<Manager>().like(Manager::getName, "na");
List<Manager> managerList = managerService.list(wrapper);
Assert.assertFalse(managerList.isEmpty());

//先配置page分页插件配置
Page page = new Page<>(1, 2);
IPage<Manager> managerPage = managerService.page(page, wrapper);
Assert.assertFalse(managerPage.getRecords().isEmpty());

//获取map对象
Map<String, Object> map = managerService.getMap(wrapper);
System.out.println(map);

Object obj = managerService.getObj(wrapper);
System.out.println(obj);

try {
    //若有多个结果,抛出异常
    managerService.getOne(wrapper, true);
}catch (RuntimeException e) {
    e.printStackTrace();
    System.out.println("异常捕获");
}

增加

save(T t) 方法,实际就是将对象持久化到数据库中,这里会产生一条insert语句,并执行。

@Transactional
public void add() {
    Manager manager = new Manager();
    manager.setAccount("account");
    manager.setRole(RoleEnum.ROOT);
    manager.setPassword("password");
    manager.setName("name");

    save(manager);
}

日志输出:

==>  Preparing: INSERT INTO tb_manager ( account, name, password, role ) VALUES ( ?, ?, ?, ? ) 
==> Parameters: account(String), name(String), password(String), 0(Integer)
<==    Updates: 1

更改

提供的 updateupdateOrSaveupateById 都可以实现数据更新。

各自的区别在于

update
updateOrSave
updateById
@Transactional
public void updateManager() {
    Manager manager = getById(1);
    manager.setName("testUpdate");
    updateById(manager);

    //saveOrUpdate(manager);

    //update(new Manager(), new UpdateWrapper<Manager>().lambda().set(Manager::getName, "test").eq(Manager::getManagerId, 1));
}

删除

在删除中,除了一般的物理删除外, mybaits-plus 还提供了逻辑删除的支持。

如果需要使用逻辑删除,除了上述配置外,还需要添加一个配置bean来装配插件。

@Bean
public ISqlInjector sqlInjector() {
    return new LogicSqlInjector();
}

这样在使用删除时,会对记录中标记为删除标识的字段进行更改,在查询和更新时,也只是针对删除标识为 未删除 的记录。

public void deleteManager() {
    LambdaQueryWrapper<Manager> wrapper = new LambdaQueryWrapper<Manager>().eq(Manager::getManagerId, 4);
    System.out.println(baseMapper.delete(wrapper));

    /*Map<String, Object> deleteMap = new HashMap<>();
    //使用表字段名
    deleteMap.put("manager_id", 4);
    baseMapper.deleteByMap(deleteMap);*/

    /*baseMapper.deleteById(4);*/

    //属于service下的方法
    /*LambdaQueryWrapper<Manager> wrapper = new LambdaQueryWrapper<Manager>().eq(Manager::getManagerId, 4);
    remove(wrapper);*/
}

条件构造器

在查询、更新、删除这些操作中,我们往往需要定义条件或者设置属性,也就是 where 子句和 set 语句,如果不是直接通过sql去处理,在 mybatis-plus 中,也提供了一种包装器来实现。

AbstractWrapper 囊括了几乎满足日常需要的条件操作,和 jpaspecification 一样,它支持动态产生条件,也支持使用 lambda 表达式去组装条件。他是 QueryWrapperUpdateWrapper 的父类

一些常用的 wrapper 方法

Map<String, Object> conditionMap = new HashMap<>();
//使用表字段名
conditionMap.put("name", "name");
conditionMap.put("manager_id", 1);
//allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
//filter:忽略字段
//null2IsNull:为true则在map的value为null时调用 isNull 方法,为false时则忽略value为null的
QueryWrapper<Manager> queryWrapper = new QueryWrapper<Manager>().allEq((r, v) -> r.indexOf("name") > 0, conditionMap, true);
managerService.list(queryWrapper);
//like(R column, Object val) -> column like '%na%'
//likeLeft -> column like '%na'
//likeRight -> column like 'na%'
//and(Function<This, This> func) -> and (column = val)
LambdaQueryWrapper<Manager> lambdaWrapper = new LambdaQueryWrapper<Manager>().like(Manager::getName, "na").and((r) -> r.eq(Manager::getDisabled, false));
managerService.list(lambdaWrapper);
//orderBy(boolean condition, boolean isAsc, R... columns) -> order by columns isAsc
LambdaQueryWrapper<Manager> lambdaWrapper = new LambdaQueryWrapper<Manager>().orderBy(true, false, Manager::getManagerId);
managerService.list(lambdaWrapper);
//select 用于挑选属性
LambdaQueryWrapper<Manager> lambdaWrapper = new LambdaQueryWrapper<Manager>().select(Manager::getName, Manager::getDisabled);
managerService.list(lambdaWrapper);
//set(R column, Object val) -> update T set colunm = val
managerService.update(new Manager(), new UpdateWrapper<Manager>().lambda().set(Manager::getName, "newName").eq(Manager::getManagerId, 4));

诸如还有其他像 eqlteisNullorderByorexists 等限定方法,这里就不一一介绍了。

其他

分页插件

引入分页,除了配置上,还需要添加插件bean

@Bean
public PaginationInterceptor paginationInterceptor() {
    return new PaginationInterceptor();
}

在使用时,自定义查询中,参数中添加 Page 对象,并要求放在参数中的第一位

IPage<ManagerPageVO> selectManagerPage(Page page, @Param("roleEnum")RoleEnum roleEnum, @Param("managerId") Integer managerId, @Param("name") String name);
<select id="selectManagerPage" resultType="com.luwei.pojos.manager.ManagerPageVO">
  <![CDATA[
    select manager_id, account, name, role, disabled, create_time, last_login_time from tb_manager where role = #{roleEnum} and deleted = false
  ]]>
    <if test="name != null">
        <![CDATA[
          and (name like CONCAT('%',#{name},'%') or account like CONCAT('%',#{name},'%'))
        ]]>
    </if>
    <if test="managerId != null">
        <![CDATA[
          and manager_id = #{managerId}
        ]]>
    </if>
</select>
<select id="selectForSpecialCondition" resultType="com.luwei.entity.Manager">
    select
    <include refid="Base_Column_List" />
    from tb_manager
    where name like '%admin%'
</select>

主键配置

mybaits-plus 中,有多种主键生成策略,它们分别是

  • IdType.AUTO:数据库id自增
  • IdType.INPUT:用户输入
  • IdType.ID_WORKER:唯一ID,自动填充(默认)
  • IdType.UUID:唯一ID,自动填充

由于我们公司使用的是 mysql 本身的自增策略,所以选择使用 IdType.AUTO。

@ApiModelProperty(value = "管理员id")
@TableId(value = "manager_id", type = IdType.AUTO)
private Integer managerId;

至于 ID_WORKER 和 UUID 的不同,在于它们的唯一键生成策略不同,ID_WORKER 按照官方的介绍,是使用 Sequence 作为基础产生唯一键。

枚举属性

为了让 mybaits 更好地使用枚举, mybatis-plus 提供了枚举扫描注入

具体配置,首先是配置扫描路径

# 配置扫描通用枚举,配置该属性,会对枚举类进行注入
typeEnumsPackage: com.luwei.demo.mybatisplusdemo.envm

在枚举类中实现接口,用于获取具体值

//实现此接口用于获取值
public interface BaseEnum<E extends Enum<?>, T> {
    T getValue();
    String getDisplayName();
}

这样,基本上就可以在 mybatis 上使用枚举类型了。

总结

上面描述了 mybitis-plus 基本用法,其实除了以上,它还提供了很多方便的插件和应用,包括xml热加载、乐观锁插件、性能分析插件等,这些由于篇幅和主题的原因我就不在这里阐述了。希望这篇可以带你很快地上手这个当前热门的 mybaits 增强工具,提高开发效率。

原文  https://segmentfault.com/a/1190000018041079
正文到此结束
Loading...