# Mybatis-Flex 和同类框架对比 ## 功能对比 MyBatis-Flex 主要是和 `MyBatis-Plus` 与 `Fluent-Mybatis` 对比,内容来源其官网、git 或者 网络文章,若有错误欢迎指正。 - MyBatis-Plus:老牌的 MyBatis 增强框架 - Fluent-Mybatis:阿里云开发的 Mybatis 增强框架(来至于阿里云·云效产品团队) | 功能或特点 | MyBatis-Flex | MyBatis-Plus | Fluent-Mybatis | | -------- | -------- | -------- | -------- | | 对 entity 的基本增删改查 | ✅ | ✅ | ✅ | | 分页查询 | ✅ | ✅ | ✅ | | 分页查询之总量缓存 | ✅ | ❌ | ❌ | | 分页查询无 SQL 解析设计(更轻量,及更高性能) | ✅ | ❌ | ✅ | | 多表查询: from 多张表 | ✅ | ❌ | ❌ | | 多表查询: left join、inner join 等等 | ✅ | ❌ | ✅ | | 单主键配置 | ✅ | ✅ | ✅ | | 多种 id 生成策略 | ✅ | ✅ | ✅ | | 支持多主键、复合主键 | ✅ | ❌ | ❌ | | 字段的 typeHandler 配置 | ✅ | ✅ | ✅ | | 除了 Mybatis,无其他第三方依赖(更轻量) | ✅ | ❌ | ❌ | | QueryWrapper 是否支持在微服务项目下进行 RPC 传输 | ✅ | ❌ | 未知 | | 逻辑删除 | ✅ | ✅ | ✅ | | 乐观锁 | ✅ | ✅ | ✅ | | SQL 审计 | ✅ | ❌ | ❌ | | 数据填充 | ✅ | ✔️ **(收费)** | ✅ | | 数据脱敏 | ✅ | ✔️ **(收费)** | ❌ | | 字段权限 | ✅ | ✔️ **(收费)** | ❌ | | 字段加密 | ✅ | ✔️ **(收费)** | ❌ | | 字典回显 | ✅ | ✔️ **(收费)** | ❌ | | Db + Row | ✅ | ❌ | ❌ | | Entity 监听 | ✅ | ❌ | ❌ | | 多数据源支持 | ✅ | ✅ | ❌ | | 多租户 | ✅ | ✅ | ❌ | > 以上内容来自第三方相关产品的官方文档或第三方平台,若有错误,欢迎指正。 ## 基础查询 **MyBatis-Flex:** ````java QueryCondition condition = EMPLOYEE.LAST_NAME.like("B") .and(EMPLOYEE.GENDER.eq(1)) .and(EMPLOYEE.AGE.gt(24)); List employees = employeeMapper.selectListByCondition(condition); ```` **MyBatis-Plus:** ````java QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper .like("last_name","B") .eq("gender",1) .gt("age",24); List employees = employeeMapper.selectList(queryWrapper); ```` 或者 MyBatis-Plus 的另一种写法: ```java LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper .like(Employee::getUserName,"B") .eq(Employee::getGender,1) .gt(Employee::getAge,24); List employees = employeeMapper.selectList(queryWrapper); ``` **Fluent-MyBatis:** ````java EmployeeQuery query = new EmployeeQuery() .where.lastName().like("B") .and.gender().eq(1) .and.age().gt(24) .end(); List employees = employeeMapper.listEntity(query); ```` ## 查询集合函数 **MyBatis-Flex:** ````java QueryWrapper query = new QueryWrapper() .select( ACCOUNT.ID, ACCOUNT.USER_NAME, max(ACCOUNT.BIRTHDAY), avg(ACCOUNT.SEX).as("sex_avg") ); List employees = employeeMapper.selectListByQuery(query); ```` **MyBatis-Plus:** ````java QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper .select( "id" ,"user_name" ,"max(birthday)" ,"avg(birthday) as sex_avg" ); List employees = employeeMapper.selectList(queryWrapper); ```` > 缺点:字段硬编码,容易错处。无法使用 ide 的字段进行重构,无法使用 IDE 自动提示,发生错误不能及时发现。 **Fluent-MyBatis:** ````java EmployeeQuery query = new EmployeeQuery() .select .id() .userName() .max.birthday() .avg.sex("sex_avg") .end() List employees = employeeMapper.listEntity(query); ```` >缺点:编写内容不符合 sql 直觉。 ## and(...) 和 or(...) 假设我们要构建如下的 SQL 进行查询(需要在 SQL 中添加括号)。 ```sql SELECT * FROM tb_account WHERE id >= 100 AND (sex = 1 OR sex = 2) OR (age IN (18,19,20) AND user_name LIKE "%michael%" ) ``` **MyBatis-Flex:** ```java QueryWrapper query = QueryWrapper.create() .where(ACCOUNT.ID.ge(100)) .and(ACCOUNT.SEX.eq(1).or(ACCOUNT.SEX.eq(2))) .or(ACCOUNT.AGE.in(18,19,20).and(ACCOUNT.USER_NAME.like("michael"))); ``` **MyBatis-Plus:** ```java QueryWrapper query = new QueryWrapper<>(); queryWrapper.ge("id",100) .and(i->i.eq("sex",1).or(x->x.eq("sex",2))) .or(i->i.in("age",{18,19,20}).like("user_name","michael")); ``` **Fluent-Mybatis:** ```java AccountQuery query = new AccountQuery() .where.id().ge(100) .and( new AccountQuery().where.sex().eq(1).or( new AccountQuery().where.sex().eq(2).end() ).end()) .or( new AccountQuery().where.age.in(18,19,20) .and.userName().like("michael").end() ) .end(); ``` > 缺点:许多 `.end()` 方法调用,容易忘记出错(或者是我写错了?欢迎指正)。 ## 多表查询 1 **MyBatis-Flex:** ````java QueryWrapper query = QueryWrapper.create() .select().from(ACCOUNT) .leftJoin(ARTICLE).on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID)) .where(ACCOUNT.AGE.ge(10)); List accounts = mapper.selectListByQuery(query); ```` **MyBatis-Plus:** ````java // 不支持~~~~ ```` **Fluent-MyBatis:** ````java StudentQuery leftQuery = new StudentQuery("a1").selectAll() .where.age().eq(34) .end(); HomeAddressQuery rightQuery = new HomeAddressQuery("a2") .where.address().like("address") .end(); IQuery query = leftQuery .join(rightQuery) .on(l -> l.where.homeAddressId(), r -> r.where.id()).endJoin() .build(); List entities = this.mapper.listEntity(query); ```` >缺点:编写内容不符合 sql 直觉。同时在编写 `end()` 和 `endJoin()` 容易忘记。 ## 多表查询 2 假设查询的 SQL 如下: ```sql SELECT a.id, a.user_name, b.id AS articleId, b.title FROM tb_account AS a, tb_article AS b WHERE a.id = b.account_id ``` **MyBatis-Flex:** ````java QueryWrapper query = new QueryWrapper() .select( ACCOUNT.ID , ACCOUNT.USER_NAME , ARTICLE.ID.as("articleId") , ARTICLE.TITLE) .from(ACCOUNT.as("a"), ARTICLE.as("b")) .where(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID)); ```` **MyBatis-Plus:** ````java // 不支持~~~~ ```` **Fluent-MyBatis:** ````java // 不支持~~~~ ```` >PS:也有可能是我自己不知道如何支持,而非 Fluent-MyBatis 原因,有知道的同学可以给下示例代码。 ## 部分字段更新 假设一个实体类 Account 中,我们要更新其内容如下: - `userName` 为 "michael" - `age` 为 "18" - `birthday` 为 null 其他字段保持数据库原有内容不变,要求执行的 SQL 如下: ```sql update tb_account set user_name = "michael", age = 18, birthday = null where id = 100 ``` **Mybatis-Flex** 代码如下: ```java Account account = UpdateEntity.of(Account.class); account.setId(100); //设置主键 account.setUserName("michael"); account.setAge(18); account.setBirthday(null); accountMapper.update(account); ``` **Mybatis-Plus** 代码如下: ```java UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", 100); updateWrapper.set("user_name", "michael"); updateWrapper.set("age", 18); updateWrapper.set("birthday", null); accountMapper.update(null, updateWrapper); ``` **Fluent-Mybatis** 代码如下: ```java AccountUpdate update = new AccountUpdate() .update.userName().is("michael") .age().is(18) .birthday().is(null) .end() .where.id().eq(100) .end(); accountMapper.updateBy(update); ```