03. Springboot集成Mybatis-flex(一)

1、前言

现在主流的Mybatis增强框架有很多,当然项目中最经常使用的还是MybatisPlus为主。但是用过MybatisPlus的小伙伴也知道,对于单表操作,链式的编码方式以及提供的Lambda支持可以简化很多代码量,但是如果多表操作,就显得心有余而力不足了。因此大多数项目中对于多表操作,仍然选择采用XML的编写方式。那么这里介绍一款Mybatis增强框架,号称集成了MybatisPlus等多个框架的优点。那就是Mybatis-Flex。

2、MyBatis-Flex 是什么?

官网地址:MyBatis-Flex - MyBatis-Flex 官方网站

与Mybatis Plus类似,Mybatis Flex也是基于Mybatis的一个增强的ORM框架。但是相比之前更轻量,更灵活,性能更高。

以下摘抄自官网: MyBatis-Flex 是一个优雅的 MyBatis 增强框架,它非常轻量、同时拥有极高的性能与灵活性。我们可以轻松的使用 Mybaits-Flex 链接任何数据库,其内置的 QueryWrapper帮助我们极大的减少了 SQL 编写的工作的同时,减少出错的可能性。

总而言之,MyBatis-Flex 能够极大地提高我们的开发效率和开发体验,让我们有更多的时间专注于自己的事情。

3、框架功能对比

MyBatis-Flex 和同类框架「功能」对比 - MyBatis-Flex 官方网站

功能或特点

MyBatis-Flex

MyBatis-Plus

Fluent-MyBatis

对 entity 的基本增删改查

分页查询

分页查询之总量缓存

分页查询无 SQL 解析设计(更轻量,及更高性能)

多表查询: from 多张表

多表查询: left join、inner join 等等

多表查询: union,union all

单主键配置

多种 id 生成策略

支持多主键、复合主键

字段的 typeHandler 配置

除了 MyBatis,无其他第三方依赖(更轻量)

QueryWrapper 是否支持在微服务项目下进行 RPC 传输

未知

逻辑删除

乐观锁

SQL 审计

数据填充

数据脱敏

✔️(收费)

字段权限

✔️(收费)

字段加密

✔️(收费)

字典回写

✔️(收费)

Db + Row

Entity 监听

多数据源支持

借助其他框架或收费

多数据源是否支持 Spring 的事务管理,比如@Transactional和TransactionTemplate等

多数据源是否支持 "非Spring" 项目

多租户

动态表名

动态 Schema

4、性能对比

MyBatis-Flex 和同类框架「性能」对比 - MyBatis-Flex 官方网站

可以看下具体的性能对比(我这边没有具体测试过),这里直接给出官网的结论:

5、快速使用

5.1、Maven添加依赖

代码语言:javascript
复制
<dependencies>
    <!-- 这里为mybatis-flex依赖 -->
    <dependency>
        <groupId>com.mybatis-flex</groupId>
        <artifactId>mybatis-flex-spring-boot-starter</artifactId>
        <version>1.6.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-configuration-processor&lt;/artifactId&gt;
    &lt;optional&gt;true&lt;/optional&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;com.alibaba&lt;/groupId&gt;
    &lt;artifactId&gt;druid-spring-boot-starter&lt;/artifactId&gt;
    &lt;version&gt;1.2.8&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;com.baomidou&lt;/groupId&gt;
    &lt;artifactId&gt;dynamic-datasource-spring-boot-starter&lt;/artifactId&gt;
    &lt;version&gt;3.5.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;com.mysql&lt;/groupId&gt;
    &lt;artifactId&gt;mysql-connector-j&lt;/artifactId&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
    &lt;artifactId&gt;lombok&lt;/artifactId&gt;
    &lt;version&gt;1.18.24&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;cn.hutool&lt;/groupId&gt;
    &lt;artifactId&gt;hutool-all&lt;/artifactId&gt;
    &lt;version&gt;5.8.21&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-validation&lt;/artifactId&gt;
&lt;/dependency&gt;

</dependencies>

5.2、数据源配置

这里多数据源使用SpringBoot的多数据源,Mybatis-Flex也支持多数据源配置。

代码语言:javascript
复制
server:
port: 8080

spring:
application:
name: springboot-mybatis-flex
profiles:
active: dev
jackson:
# 不要全局限制,避免字段格式不一致
date-format: "yyyy-MM-dd HH:mm:ss"
locale: zh_CN
time-zone: GMT+8

druid config

datasource:
dynamic:
primary: primary
datasource:
primary:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost/my-game?useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: root

type: com.alibaba.druid.pool.DruidDataSource
druid:
  validation-query: SELECT 1
  initial-size: 10
  min-idle: 10
  max-active: 20
  min-evictable-idle-time-millis: 180000
  test-on-borrow: false
  test-while-idle: true
  remove-abandoned: true
  remove-abandoned-timeout-millis: 1800
  log-abandoned: true
  pool-prepared-statements: true
  max-open-prepared-statements: 100
  filter:
    slf4j:
      enabled: false
  web-stat-filter:
    enabled: false

autoconfigure:
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure

5.3、创建实体类和表

实体类User:

代码语言:javascript
复制
package org.shamee.demo.entity;

import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.keygen.KeyGenerators;
import lombok.*;

import java.io.Serializable;
import java.util.Date;

/**

  • @Table 注解自动映射实体类和表字段
    */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Table("t_user")
    public class User implements Serializable {

    /**

    • 声明主键ID,并指定生成器为雪花ID
      */
      @Id(keyType = KeyType.Generator, value = KeyGenerators.snowFlakeId)
      private String id;

    /**

    • Column声明字段名称,onInsertValue 自动填充时间
      */
      @Column(value = "createdTime", onInsertValue = "now()")
      private Date createdTime;

    @Column(value = "updatedTime", onInsertValue = "now()", onUpdateValue = "now()")
    private Date updatedTime;

    /**

    • Column声明字段名称,isLogicDelete 逻辑删除
      */
      @Column(value = "isDeleted", isLogicDelete = true)
      private Boolean isDeleted = false;

    @Column(value = "userId")
    private String userId;

    @Column(value = "userName")
    private String userName;

    @Column(value = "isUse")
    private Boolean isUse;

    @Column(value = "battleNum")
    private Integer battleNum;

    @Column(value = "atk")
    private Integer atk;

    private String extension;
    }

表t_user:

代码语言:javascript
复制
CREATE TABLE t_user  (
id varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
userId varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
userName varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
isUse tinyint(4) NULL DEFAULT NULL,
battleNum int(11) NULL DEFAULT NULL,
atk int(11) NULL DEFAULT NULL,
extension text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
createdTime datetime(0) NULL DEFAULT NULL,
updatedTime datetime(0) NULL DEFAULT NULL,
isDeleted tinyint(4) NULL DEFAULT NULL,
PRIMARY KEY (id) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;

5.4、创建Dao

代码语言:javascript
复制
package org.shamee.demo.dao;

import com.mybatisflex.core.BaseMapper;
import org.shamee.demo.entity.User;

public interface UserDao extends BaseMapper<User> {
}

5.5、创建Service

代码语言:javascript
复制
package org.shamee.demo.service;

import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.shamee.demo.dao.UserDao;
import org.shamee.demo.entity.User;
import org.shamee.demo.entity.table.UserTableDef;
import org.springframework.stereotype.Service;

import java.util.List;

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

/**
 * 查询全部
 * @return
 */
public List&lt;User&gt; selectAll(){
    return this.getMapper().selectAll();
}

/**
 * 根据userId获取User数据
 * @param userId
 * @return
 */
public User listById(String userId){
    QueryWrapper wrapper = QueryWrapper.create()
            // 这里可以指定查询字段
            .select(UserTableDef.USER.USER_ID, UserTableDef.USER.USER_NAME, UserTableDef.USER.ATK)
            // sql from表名
            .from(User.class)
            // 查询条件,这里的UserTableDef.USER代码自动编译生成,类似lombok
            .where(UserTableDef.USER.USER_ID.eq(userId));
    return this.getMapper().selectOneByQuery(wrapper);
}


/**
 * 新增
 * @param user
 */
public void insert(User user){
    this.getMapper().insert(user);
}

/**
 * 更新User
 * @param user
 */
public void updateEntity(User user){
    this.getMapper().update(user);
}

/**
 * 局部更新
 * @param userId
 * @param userName
 */
public void updateRow(String userId, String userName){
    UpdateChain.of(User.class)
            .set(User::getUserName, userName)
            .where(User::getUserId).eq(userId).update();
}

/**
 * 删除
 * @param userName
 */
public void deleteByWrapper(String userName){
    QueryWrapper queryWrapper = QueryWrapper.create().where(UserTableDef.USER.USER_NAME.eq(userName));
    this.getMapper().deleteByQuery(queryWrapper);
}

}

5.6、创建Controller接口测试

代码语言:javascript
复制
package org.shamee.demo.controller;

import org.shamee.demo.entity.User;
import org.shamee.demo.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/api/demo/user")
public class UserController {

@Resource
private UserService userService;


/**
 * 查询全部
 * @return
 */
@GetMapping(&#34;listall&#34;)
public List&lt;User&gt; listall(){
    return userService.selectAll();
}

/**
 * 按userId查询
 * @return
 */
@GetMapping(&#34;listById&#34;)
public User listById(){
    return userService.listById(&#34;zhangsan&#34;);
}

/**
 * 新增
 * @return
 */
@GetMapping(&#34;insert&#34;)
public Boolean insert(){
    User user = User.builder().userId(&#34;zhangsan&#34;).userName(&#34;张三&#34;).atk(100).battleNum(200).build();
    userService.insert(user);
    return Boolean.TRUE;
}

/**
 * 更新
 * @return
 */
@GetMapping(&#34;update&#34;)
public Boolean update(){
    userService.updateRow(&#34;zhangsan&#34;, &#34;张三三&#34;);
    return Boolean.TRUE;
}

/**
 * 删除
 * @return
 */
@GetMapping(&#34;delete&#34;)
public Boolean delete(){
    userService.deleteByWrapper(&#34;张三三&#34;);
    return Boolean.TRUE;
}

}

5.7、测试结果

先执行insert接口插入数据后,调用listall查看数据列表。

6、小结

习惯了Mybatis Plus后,Mybatis Flex上手还是很类似的,就是会有一些语法的差异。如声明主键注解,字段映射注解,QueryWrapper使用差异等等。整体来说是Mybatis增强版,官方也提供了很多高级使用配置,感兴趣的可以探索一下。