• 【Java开发】 Springboot集成Mybatis-Flex


    1 Mybatis-Flex 介绍


    1.1简介

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

    1.2特征

            1.轻量:除了 MyBatis,没有任何第三方依赖、没有任何拦截器,在执行的过程中,没有任何的 Sql 解析(Parse)。 这带来了几个好处:极高的性能、极易对代码进行跟踪和调试、把控性更高。
            2.灵活:支持 Entity 的增删改查、以及分页查询的同时,MyBatis-Flex 提供了 Db + Row 工具,可以无需实体类对数据库进行增删改查以及分页查询。 与此同时,MyBatis-Flex 内置的 QueryWrapper 可以轻易的帮助我们实现 多表查询、链接查询、子查询 等等常见的 SQL 场景。
            3.强大:支持任意关系型数据库,还可以通过方言持续扩展,同时支持 多(复合)主键、逻辑删除、乐观锁配置、数据脱敏、数据审计、 数据填充 等等功能。


    简单来说,Mybatis-Flex 相比 Mybatis-Plus 等框架 速度更快、功能更多、代码更简洁~

    1.3Mybatis-Flex和同类框架对比

    1)功能对比:

    2)性能对比:
    这里直接贴测试结果:

    MyBatis-Flex 的查询单条数据的速度,大概是 MyBatis-Plus 的 5 ~ 10+ 倍。
    MyBatis-Flex 的查询 10 条数据的速度,大概是 MyBatis-Plus 的 5~10 倍左右。
    Mybatis-Flex 的分页查询速度,大概是 Mybatis-Plus 的 5~10 倍左右。
    Mybatis-Flex 的数据更新速度,大概是 Mybatis-Plus 的 5~10+ 倍。

     

    2 准备工作

    官方文档:快速开始 - MyBatis-Flex

    以 Spring Boot + Maven + Mysql 项目做演示

    2.1 数据库中创建表及插入数据

    此处省略~

    2.2 Spring Boot 项目初始化

    此时需要创建 Spring Boot 项目,并添加 Maven 依赖;此处我通过 IDEA 使用 Spring Initializer 快速初始化一个 Spring Boot 工程。

    项目创建省略~

    2.3 添加 Maven 主要依赖

    往 pom.xml 文件中添加以下依赖。

    1. org.springframework.boot
    2. spring-boot-starter-jdbc
    3. org.springframework.boot
    4. spring-boot-starter-web
    5. org.springframework.boot
    6. spring-boot-starter-test
    7. test
    8. mysql
    9. mysql-connector-java
    10. com.mybatis-flex
    11. mybatis-flex-spring-boot-starter
    12. 1.7.3
    13. com.mybatis-flex
    14. mybatis-flex-processor
    15. 1.7.3
    16. provided
    17. org.projectlombok
    18. lombok
    19. com.github.pagehelper
    20. pagehelper
    21. 5.3.0
    22. true
    23. org.apache.commons
    24. commons-lang3
    25. 3.12.0

    2.4 配置数据源

    在 application.properties 或 application.yml 中配置数据源:

    1. server.port=8999
    2. spring.application.name=mybatisPlus
    3. spring.datasource.username=root
    4. spring.datasource.password=root3306
    5. spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
    6. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

    3 Mybatis-Flex 实践

    3.1 编写实体类和 Mapper 接口

    📌 User 实体类

    • 使用 @Table("flex_user") 设置实体类与表名的映射关系
    • 使用 @Id(keyType = KeyType.Auto) 标识主键为自增
    1. package com.mybatisflex.flex.domain;
    2. import com.mybatisflex.annotation.Column;
    3. import com.mybatisflex.annotation.Table;
    4. import lombok.AllArgsConstructor;
    5. import lombok.Builder;
    6. import lombok.Data;
    7. import lombok.NoArgsConstructor;
    8. import java.io.Serializable;
    9. import java.util.Date;
    10. /**
    11. */
    12. @Data
    13. @Builder
    14. @NoArgsConstructor
    15. @AllArgsConstructor
    16. //使用 @Table("tb_account") 设置实体类与表名的映射关系
    17. @Table("user")
    18. public class User implements Serializable {
    19. private Integer id;
    20. @Column(value = "name")
    21. private String name;
    22. @Column(value = "age")
    23. private Integer age;
    24. @Column(value = "email")
    25. private String email;
    26. @Column(value = "create_time", onInsertValue = "now()")
    27. private Date createTime;
    28. @Column(value = "update_time", onUpdateValue = "now()")
    29. private Date updateTime;
    30. @Column(value = "del_flag")
    31. private int delFlag;
    32. @Column(value = "dept_code")
    33. private String deptCode;
    34. }

    📌 Mapper 接口继承 BaseMapper 接口

    1. package com.mybatisflex.flex.mapper;
    2. import com.mybatisflex.core.BaseMapper;
    3. import com.mybatisflex.flex.domain.User;
    4. /**
    5. *
    6. */
    7. public interface UserMapper extends BaseMapper {
    8. }

    3.2 在主启动类添加 @MapperScan 注解

    用于扫描 Mapper 文件夹:

    1. package com.mybatisflex.flex;
    2. import org.mybatis.spring.annotation.MapperScan;
    3. import org.springframework.boot.SpringApplication;
    4. import org.springframework.boot.autoconfigure.SpringBootApplication;
    5. @SpringBootApplication
    6. @MapperScan("com.mybatisflex.flex.mapper")
    7. public class FlexApplication {
    8. public static void main(String[] args) {
    9. SpringApplication.run(FlexApplication.class, args);
    10. }
    11. }

    3.3 创建service

    1. package com.mybatisflex.flex.service;
    2. import com.mybatisflex.core.query.QueryWrapper;
    3. import com.mybatisflex.core.update.UpdateChain;
    4. import com.mybatisflex.flex.domain.User;
    5. import com.mybatisflex.flex.domain.UserDto;
    6. import com.mybatisflex.flex.domain.table.SysDeptTableDef;
    7. import com.mybatisflex.flex.domain.table.UserTableDef;
    8. import com.mybatisflex.flex.mapper.UserMapper;
    9. import com.mybatisflex.spring.service.impl.ServiceImpl;
    10. import org.springframework.stereotype.Service;
    11. import java.util.List;
    12. /**
    13. * @Description:
    14. * @Date Create in 10:39 2023/11/22
    15. * @Modified By:
    16. */
    17. @Service
    18. public class UserService extends ServiceImpl {
    19. /**
    20. * 查询全部
    21. * @return
    22. */
    23. public List selectAll(){
    24. return this.getMapper().selectAll();
    25. }
    26. public List selectList(){
    27. QueryWrapper wrapper = QueryWrapper.create()
    28. // 这里可以指定查询字段
    29. .select()
    30. // sql from表名
    31. .from(User.class)
    32. .where(User::getName).like("徐")
    33. .or(UserTableDef.USER.ID.in(2,3).and(UserTableDef.USER.NAME.like("o")));
    34. return this.getMapper().selectListByQuery(wrapper);
    35. }
    36. /**
    37. * 根据userId获取User数据
    38. * @param userId
    39. * @return
    40. */
    41. public User listById(Integer userId){
    42. QueryWrapper wrapper = QueryWrapper.create()
    43. // 这里可以指定查询字段
    44. .select()
    45. // sql from表名
    46. .from(User.class)
    47. .where(User::getId).eq(userId).and(User::getName).like("徐");
    48. return this.getMapper().selectOneByQuery(wrapper);
    49. }
    50. /**
    51. * 关联查询--链式查询
    52. */
    53. public List getInfo(Integer userId){
    54. QueryWrapper query = QueryWrapper.create()
    55. .select(UserTableDef.USER.ALL_COLUMNS)
    56. .select(SysDeptTableDef.SYS_DEPT.DEPT_NAME)
    57. .from(UserTableDef.USER).as("u")
    58. .leftJoin(SysDeptTableDef.SYS_DEPT).as("d").on(UserTableDef.USER.DEPT_CODE.eq(SysDeptTableDef.SYS_DEPT.DEPT_CODE))
    59. .where(UserTableDef.USER.ID.eq(userId));
    60. return this.getMapper().selectListByQueryAs(query,UserDto.class);
    61. }
    62. /**
    63. * 新增
    64. * @param user
    65. */
    66. public void insert(User user){
    67. this.getMapper().insert(user);
    68. }
    69. /**
    70. * 更新User
    71. * @param user
    72. */
    73. public void updateEntity(User user){
    74. this.getMapper().update(user);
    75. }
    76. /**
    77. * 局部更新
    78. * @param userId
    79. * @param userName
    80. */
    81. public void updateRow(Integer userId, String userName){
    82. UpdateChain.of(User.class)
    83. .set(User::getName, userName)
    84. .where(User::getId).eq(userId).update();
    85. }
    86. /**
    87. * 删除
    88. * @param userName
    89. */
    90. public void deleteByWrapper(String userName){
    91. QueryWrapper queryWrapper = QueryWrapper.create().where(User::getName).eq(userName);
    92. this.getMapper().deleteByQuery(queryWrapper);
    93. }
    94. }

    3.4创建Controller接口测试

    1. package com.mybatisflex.flex.controller;
    2. import com.mybatisflex.flex.domain.User;
    3. import com.mybatisflex.flex.domain.UserDto;
    4. import com.mybatisflex.flex.page.TableDataInfo;
    5. import com.mybatisflex.flex.service.UserService;
    6. import com.mybatisflex.flex.utils.ResponseUtils;
    7. import org.springframework.web.bind.annotation.GetMapping;
    8. import org.springframework.web.bind.annotation.RequestMapping;
    9. import org.springframework.web.bind.annotation.RestController;
    10. import javax.annotation.Resource;
    11. import java.util.List;
    12. /**
    13. * @Author: best_liu
    14. * @Description:
    15. * @Date Create in 10:33 2023/11/22
    16. * @Modified By:
    17. */
    18. @RestController
    19. @RequestMapping("/user")
    20. public class SysUserController {
    21. @Resource
    22. private UserService userService;
    23. /**
    24. * 查询全部
    25. * @return
    26. */
    27. @GetMapping("listall")
    28. public List listall(){
    29. return userService.selectAll();
    30. }
    31. /**
    32. * 分页查询
    33. * @return
    34. **/
    35. @GetMapping("/page")
    36. public TableDataInfo findPage() {
    37. ResponseUtils.startPage();
    38. return ResponseUtils.getDataTable(userService.selectAll());
    39. }
    40. /**
    41. * 按条件查询
    42. * @return
    43. */
    44. @GetMapping("getList")
    45. public List selectList(){
    46. return userService.selectList();
    47. }
    48. /**
    49. * 按userId查询
    50. * @return
    51. */
    52. @GetMapping("listById")
    53. public User listById(){
    54. return userService.listById(0);
    55. }
    56. /**
    57. * 按userId关联查询部门
    58. * @return
    59. */
    60. @GetMapping("getInfo")
    61. public List getInfo(){
    62. return userService.getInfo(0);
    63. }
    64. /**
    65. * 新增
    66. * @return
    67. */
    68. @GetMapping("insert")
    69. public Boolean insert(){
    70. User user = User.builder().id(10).name("张三").age(100).email("zhangsan@163.com").build();
    71. userService.insert(user);
    72. return Boolean.TRUE;
    73. }
    74. /**
    75. * 更新
    76. * @return
    77. */
    78. @GetMapping("update")
    79. public Boolean update(){
    80. userService.updateRow(10, "张三三");
    81. return Boolean.TRUE;
    82. }
    83. /**
    84. * 删除
    85. * @return
    86. */
    87. @GetMapping("delete")
    88. public Boolean delete(){
    89. userService.deleteByWrapper("张三三");
    90. return Boolean.TRUE;
    91. }
    92. }

    4 链式查询

    若想使用链式查询还得需要 APT 配置,MyBatis-Flex 使用了 APT(Annotation Processing Tool)技术,在项目编译的时候,会自动根据 Entity/pojo 类定义的字段帮你生成 "USER" 类(可用于链式查询)

    通过开发工具构建项目(如下图),或者执行 maven 编译命令: mvn clean package 都可以自动生成。

    正常情况下,会在 target 包下生成如下资源

    若生成该资源并导入成功,那么此时,可使用链式查询

    1. /**
    2. * 关联查询
    3. */
    4. public List getInfo(Integer userId){
    5. QueryWrapper query = QueryWrapper.create()
    6. .select(UserTableDef.USER.ALL_COLUMNS)
    7. .select(SysDeptTableDef.SYS_DEPT.DEPT_NAME)
    8. .from(UserTableDef.USER).as("u")
    9. .leftJoin(SysDeptTableDef.SYS_DEPT).as("d").on(UserTableDef.USER.DEPT_CODE.eq(SysDeptTableDef.SYS_DEPT.DEPT_CODE))
    10. .where(UserTableDef.USER.ID.eq(userId));
    11. return this.getMapper().selectListByQueryAs(query,UserDto.class);
    12. }

    总的来说,MyBatis-Flex 的链式查询相比 MyBatis-Plus 多了一步配置环节,目前来看其他步骤类似。

    MyBatis-Flex/Plus 代码对比

    接下来看一下MyBatis-Flex  MyBatis-Plus 各部分功能代码的差别,Employee、Account、Article 都是实体类。

    5.1 基础查询

    MyBatis-Flex:

    1. QueryWrapper query = QueryWrapper.create()
    2. .where(EMPLOYEE.LAST_NAME.like(searchWord)) //条件为null时自动忽略
    3. .and(EMPLOYEE.GENDER.eq(1))
    4. .and(EMPLOYEE.AGE.gt(24));
    5. List employees = employeeMapper.selectListByQuery(query);

    MyBatis-Plus:

    1. QueryWrapper queryWrapper = Wrappers.query()
    2. .like(searchWord != null, "last_name", searchWord)
    3. .eq("gender", 1)
    4. .gt("age", 24);
    5. List employees = employeeMapper.selectList(queryWrapper);
    6. //lambda 写法:
    7. LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery()
    8. .like(StringUtils.isNotEmpty(searchWord), Employee::getUserName,"B")
    9. .eq(Employee::getGender, 1)
    10. .gt(Employee::getAge, 24);
    11. List employees = employeeMapper.selectList(queryWrapper);

    5.2 集合查询

    MyBatis-Flex:

    1. QueryWrapper query = QueryWrapper.create()
    2. .select(
    3. ACCOUNT.ID,
    4. ACCOUNT.USER_NAME,
    5. max(ACCOUNT.BIRTHDAY),
    6. avg(ACCOUNT.SEX).as("sex_avg")
    7. );
    8. List employees = employeeMapper.selectListByQuery(query);

    MyBatis-Plus:

    1. QueryWrapper queryWrapper = Wrappers.query()
    2. .select(
    3. "id",
    4. "user_name",
    5. "max(birthday)",
    6. "avg(birthday) as sex_avg"
    7. );
    8. List employees = employeeMapper.selectList(queryWrapper);

    缺点:字段硬编码,容易拼错。无法使用 IDE 的字段进行重构,无法使用 IDE 自动提示,发生错误不能及时发现,不过MyBatis-Plus的 lambdawrapper 也是能解决这个问题。

    5.3 and(...) 和 or(...)

    假设我们要构建如下的 SQL 进行查询(需要在 SQL 中添加括号)。

    1. SELECT * FROM tb_account
    2. WHERE id >= 100
    3. AND (sex = 1 OR sex = 2)
    4. OR (age IN (18,19,20) AND user_name LIKE "%michael%" )

    MyBatis-Flex:

    1. QueryWrapper query = QueryWrapper.create()
    2. .where(ACCOUNT.ID.ge(100))
    3. .and(ACCOUNT.SEX.eq(1).or(ACCOUNT.SEX.eq(2)))
    4. .or(ACCOUNT.AGE.in(18, 19, 20).and(ACCOUNT.USER_NAME.like("michael")));

    MyBatis-Plus:

    1. QueryWrapper query = Wrappers.query()
    2. .ge("id", 100)
    3. .and(i -> i.eq("sex", 1).or(x -> x.eq("sex", 2)))
    4. .or(i -> i.in("age", 18, 19, 20).like("user_name", "michael"));
    5. // or lambda
    6. LambdaQueryWrapper query = Wrappers.lambdaQuery()
    7. .ge(Employee::getId, 100)
    8. .and(i -> i.eq(Employee::getSex, 1).or(x -> x.eq(Employee::getSex, 2)))
    9. .or(i -> i.in(Employee::getAge, 18, 19, 20).like(Employee::getUserName, "michael"));

    5.4 多表查询

    MyBatis-Flex:

    1. QueryWrapper query = QueryWrapper.create()
    2. .select().from(ACCOUNT)
    3. .leftJoin(ARTICLE).on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID))
    4. .where(ACCOUNT.AGE.ge(10));
    5. List accounts = mapper.selectListByQuery(query);
    1. QueryWrapper query = new QueryWrapper()
    2. .select(
    3. ACCOUNT.ID
    4. , ACCOUNT.USER_NAME
    5. , ARTICLE.ID.as("articleId")
    6. , ARTICLE.TITLE)
    7. .from(ACCOUNT.as("a"), ARTICLE.as("b"))
    8. .where(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID));

    MyBatis-Plus:不支持

    5.5 部分字段更新

    假设一个实体类 Account 中,我们要更新其内容如下:

    • userName 为 "michael"
    • age 为 "18"
    • birthday 为 null

    其他字段保持数据库原有内容不变,要求执行的 SQL 如下:

    1. update tb_account
    2. set user_name = "michael", age = 18, birthday = null
    3. where id = 100

    MyBatis-Flex 代码如下:

    1. Account account = UpdateEntity.of(Account.class);
    2. account.setId(100); //设置主键
    3. account.setUserName("michael");
    4. account.setAge(18);
    5. account.setBirthday(null);
    6. accountMapper.update(account);

    MyBatis-Plus 代码如下(或可使用 MyBatis-Plus 的 LambdaUpdateWrapper,但性能没有 UpdateWrapper 好):

    1. UpdateWrapper updateWrapper = new UpdateWrapper<>();
    2. updateWrapper.eq("id", 100);
    3. updateWrapper.set("user_name", "michael");
    4. updateWrapper.set("age", 18);
    5. updateWrapper.set("birthday", null);
    6. accountMapper.update(null, updateWrapper);

    如上,MyBatis-Flex 在代码编写来说更加灵活,编写方式更多一些,还是有些优势。

    源码地址:https://download.csdn.net/download/askuld/88561026 

  • 相关阅读:
    键鼠自动化2.0展示
    【技能树笔记】网络篇——练习题解析(九)
    【数学建模】层次分析
    数组、链表、栈、队列、树
    leetcode 29
    Shiro和Spring Security对比
    5-1:什么是Servlet-开发你的第一个动态网站
    LeetCode第14题:最长公共前缀
    Java工具——Eclipse设置字体大小
    django-项目
  • 原文地址:https://blog.csdn.net/askuld/article/details/134552910