既生瑜何生亮,浅析下层出不穷的新ORM框架: MyBatis-Flex,可看可不看!!!
1.概述
这里先说说我的观点哈,仅是个人观点哦,不喜勿喷。现在这些框架层出不穷,其实吧个人感觉没必要过度关注,因为这些框架并没有完完全全做到推陈出新,反倒是有一点互相“学习copy”的感觉,并没有那么新颖强大、从无到有的一个过程。那说回今天的主题ORM框架,在Java后端技术栈里面我们都知道
MyBatis-Plus: MyBatis-plus最详细的入门使用教程
一文带你掌握MyBatis-Plus的plus高级功能点如何使用,plus就该有plus的玩法
咋说呢,
Fluent-MyBatis: FluentMybatis: 基于mybatis但青出于蓝
阿里云开发的 MyBatis 增强框架(来自于阿里云·云效产品团队),只是感觉使用的人没那么多,感觉没那么有名气。
tk-mybatis:
MyBatis-Flex: 今天我们浅析的主人公,它一个优雅的 MyBatis 增强框架,当下比较新,有点热度,github上有1k多的star,当然现在star的数量已经不一定是真实的啦,不再是权威指标考量了,官网地址:mybatis-flex.com/
红色框里面是官网给出该框架的特征所在,优势所在,厉害所在~~~
2. MyBatis-Flex 和同类框架对比
2.1 功能对比
既生瑜何生亮??? MyBatis-Flex 主要是和
- MyBatis-Plus:老牌的 MyBatis 增强框架,开源于 2016 年。
- Fluent-MyBatis:阿里云开发的 MyBatis 增强框架(来自于阿里云·云效产品团队)
功能或特点 | 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 的事务管理,比如 |
? | ? | ? |
多数据源是否支持 “非Spring” 项目 | ? | ? | ? |
多租户 | ? | ? | ? |
动态表名 | ? | ? | ? |
动态 Schema | ? | ? | ? |
以上内容来自第三方相关产品的官方文档或第三方平台,若有错误,欢迎纠正。
2.2 使用案例对比
2.2.1 基础查询
MyBatis-Flex:
ini复制代码QueryWrapper query = QueryWrapper.create() .where(EMPLOYEE.LAST_NAME.like(searchWord)) //条件为null时自动忽略 .and(EMPLOYEE.GENDER.eq(1)) .and(EMPLOYEE.AGE.gt(24)); List<Employee> employees = employeeMapper.selectListByQuery(query);
MyBatis-Plus:
perl复制代码QueryWrapper<Employee> queryWrapper = Wrappers.query() .like(searchWord != null, "last_name", searchWord) .eq("gender", 1) .gt("age", 24); List<Employee> employees = employeeMapper.selectList(queryWrapper);
或者 MyBatis-Plus 的 lambda 写法:
scss复制代码LambdaQueryWrapper<Employee> queryWrapper = Wrappers.<Employee>lambdaQuery() .like(StringUtils.isNotEmpty(searchWord), Employee::getUserName,"B") .eq(Employee::getGender, 1) .gt(Employee::getAge, 24); List<Employee> employees = employeeMapper.selectList(queryWrapper);
Fluent-MyBatis:
scss复制代码EmployeeQuery query = new EmployeeQuery() .where.lastName().like(searchWord, If::notNull) .and.gender().eq(1) .and.age().gt(24) .end(); List<Employee> employees = employeeMapper.listEntity(query);
2.2.2 查询集合函数
MyBatis-Flex:
ini复制代码QueryWrapper query = QueryWrapper.create() .select( ACCOUNT.ID, ACCOUNT.USER_NAME, max(ACCOUNT.BIRTHDAY), avg(ACCOUNT.SEX).as("sex_avg") ); List<Employee> employees = employeeMapper.selectListByQuery(query);
MyBatis-Plus:
erlang复制代码QueryWrapper<Employee> queryWrapper = Wrappers.query() .select( "id", "user_name", "max(birthday)", "avg(birthday) as sex_avg" ); List<Employee> employees = employeeMapper.selectList(queryWrapper);
缺点:字段硬编码,容易拼错。无法使用 ide 的字段进行重构,无法使用 IDE 自动提示,发生错误不能及时发现。
Fluent-MyBatis:
scss复制代码EmployeeQuery query = new EmployeeQuery() .select .id() .userName() .max.birthday() .avg.sex("sex_avg") .end() List<Employee> employees = employeeMapper.listEntity(query);
缺点:编写内容不符合 sql 直觉。
2.2.3 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:
perl复制代码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:
perl复制代码QueryWrapper<Employee> query = Wrappers.query() .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")); // or lambda LambdaQueryWrapper<Employee> query = Wrappers.<Employee>lambdaQuery() .ge(Employee::getId, 100) .and(i -> i.eq(Employee::getSex, 1).or(x -> x.eq(Employee::getSex, 2))) .or(i -> i.in(Employee::getAge, 18, 19, 20).like(Employee::getUserName, "michael"));
Fluent-MyBatis:
scss复制代码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() 方法调用,容易忘记出错(或者写错了?欢迎纠正)。
2.2.4 多表查询
MyBatis-Flex:
scss复制代码QueryWrapper query = QueryWrapper.create() .select().from(ACCOUNT) .leftJoin(ARTICLE).on(ACCOUNT.ID.eq(ARTICLE.ACCOUNT_ID)) .where(ACCOUNT.AGE.ge(10)); List<Account> accounts = mapper.selectListByQuery(query);
MyBatis-Plus:
arduino 复制代码// 不支持~~~~
Fluent-MyBatis:
scss复制代码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<StudentEntity> entities = this.mapper.listEntity(query);
缺点:编写内容不符合 sql 直觉。同时在编写
end() 和endJoin() 容易忘记。
2.2.5 多表查询
假设查询的 SQL 如下:
css复制代码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:
csharp复制代码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:
arduino 复制代码// 不支持~~~~
Fluent-MyBatis:
arduino 复制代码// 不支持~~~~
PS:也有可能是笔者自己不知道如何支持,而非 Fluent-MyBatis 原因,有知道的同学可以给下示例代码。
2.2.6 部分字段更新
假设一个实体类 Account 中,我们要更新其内容如下:
userName 为 “michael”age 为 “18”birthday 为 null
其他字段保持数据库原有内容不变,要求执行的 SQL 如下:
ini复制代码update tb_account set user_name = "michael", age = 18, birthday = null where id = 100
MyBatis-Flex 代码如下:
ini复制代码Account account = UpdateEntity.of(Account.class); account.setId(100); //设置主键 account.setUserName("michael"); account.setAge(18); account.setBirthday(null); accountMapper.update(account);
MyBatis-Plus 代码如下(或可使用 MyBatis-Plus 的
vbscript复制代码UpdateWrapper<Account> 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 代码如下:
scss复制代码AccountUpdate update = new AccountUpdate() .update.userName().is("michael") .age().is(18) .birthday().is(null) .end() .where.id().eq(100) .end(); accountMapper.updateBy(update);
项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用
Github地址:github.com/plasticene/…
Gitee地址:gitee.com/plasticene3…
微信公众号:Shepherd进阶笔记
交流探讨qun:Shepherd_126
3.Spring Boot快速整合MyBatis-Flex框架
和整合
第 1 步:创建数据库表
sql复制代码CREATE TABLE IF NOT EXISTS `tb_account` ( `id` INTEGER PRIMARY KEY auto_increment, `user_name` VARCHAR(100), `age` INTEGER, `birthday` DATETIME ); INSERT INTO tb_account(id, user_name, age, birthday) VALUES (1, '张三', 18, '2020-01-11'), (2, '李四', 19, '2021-03-21');
第 2 步:创建 Spring Boot 项目,并添加 Maven 依赖
可以使用 Spring Initializer 快速初始化一个 Spring Boot 工程。
需要添加的 Maven 主要依赖示例:
xml复制代码<dependencies> <dependency> <groupId>com.mybatis-flex</groupId> <artifactId>mybatis-flex-spring-boot-starter</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> <!-- for test only --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
第 3 步:对 Spring Boot 项目进行配置
在 application.yml 中配置数据源:
yaml复制代码# DataSource Config spring: datasource: url: jdbc:mysql://localhost:3306/flex_test username: root password: 123456
在 Spring Boot 启动类中添加
less复制代码@SpringBootApplication @MapperScan("com.mybatisflex.test.mapper") public class MybatisFlexTestApplication { public static void main(String[] args) { SpringApplication.run(MybatisFlexTestApplication.class, args); } }
第 4 步:编写实体类和 Mapper 接口
这里使用了 Lombok 来简化代码。
kotlin复制代码@Data @Table("tb_account") public class Account { @Id(keyType = KeyType.Auto) private Long id; private String userName; private Integer age; private Date birthday; }
- 使用
@Table("tb_account") 设置实体类与表名的映射关系 - 使用
@Id(keyType = KeyType.Auto) 标识主键为自增
Mapper 接口继承 BaseMapper 接口:
csharp复制代码public interface AccountMapper extends BaseMapper<Account> { }
这部分也可以使用 MyBatis-Flex 的代码生成器来生,功能非常强大的。详情进入:代码生成器章节 了解。
第 5 步:开始使用
添加测试类,进行功能测试:
scss复制代码import static com.mybatisflex.test.entity.table.AccountTableDef.ACCOUNT; @SpringBootTest class MybatisFlexTestApplicationTests { @Autowired private AccountMapper accountMapper; @Test void contextLoads() { QueryWrapper queryWrapper = QueryWrapper.create() .select() .where(ACCOUNT.AGE.eq(18)); Account account = accountMapper.selectOneByQuery(queryWrapper); System.out.println(account); } }
控制台输出:
ini 复制代码Account(id=1, userName=张三, age=18, birthday=Sat Jan 11 00:00:00 CST 2020)
4.总结
以上全部就是今天对于