原文来自微信公众号,点击进入

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

做Java后端的人,ORM框架选型基本逃不出这几个:

MyBatis-Plus,JPA,或者干脆手写SQL。

JPA听起来很美好——全自动Mapping,实体写好就不用管了。但真到复杂查询的时候,JPQL写起来跟手写SQL差不多,还受限于ORM映射模型,调试困难,性能调优更是黑盒。MyBatis生态这么多年依然最活跃,不是没有原因的。

最近有个框架悄悄更新到1.10版本,功能多到让MyBatis-Plus汗颜,但知道的人不多——

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

xbatis,一款基于MyBatis封装的ORM框架。


先看对比,再说话

这是官方整理的和MyBatis-Plus功能对照,重点看我打✅它打❌的地方:

功能xbatisMyBatis-Plus
子查询分页
多表 join(left/inner/union)
多表查询结果自动映射
不同数据库不同ID自增策略
多主键、复合主键支持
局部SQL模板(select/where/groupby)
查询结果自动select列
update/delete RETURNING
单个Mapper走天下
一键忽略null/空字符串条件
非实体类typeHandler复用
Mapper方法拦截器

差距就是这么大。


代码对比,才见真章

基础查询:

xbatis:

List<Employee> employees = QueryChain.of(employeeMapper)
    .like(StringUtils.isNotEmpty(searchWord), Employee::getUserName, "B")
    .eq(Employee::getGender, 1)
    .gt(Employee::getAge, 24)
    .list();

MyBatis-Plus:

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);

xbatis直接调用,少写一步。


聚合查询:

xbatis用Lambda,IDE补全,类型安全:

List<Employee> employees = QueryChain.of(employeeMapper)
    .select(Employee::getId)
    .select(Employee::getUserName, c -> c.max())
    .select(Employee::getBirthday, c -> c.avg().as("sex_avg"))
    .list();

MyBatis-Plus要手写字符串字段名:

QueryWrapper<Employee> queryWrapper = Wrappers.query()
    .select("id", "user_name", "max(birthday)", "avg(birthday) as sex_avg");

字段硬编码容易拼错,IDE不会提示,错了要到运行时才发现。


多表查询:

xbatis支持join,MyBatis-Plus不支持:

Pager<SysUser> pager = QueryChain.of(sysUserMapper)
    .join(SysUser::getRoleId, SysRole::getId)
    .like(SysUser::getUserName, "abc")
    .paging(Pager.of(1));

MyBatis-Plus在这里只能干瞪眼。


部分字段更新:

xbatis可以精准更新指定字段,birthday=null照样传:

Account account = UpdateEntity.of(Account.class);
account.setId(100);
account.setUserName("michael");
account.setAge(18);
account.setBirthday(null);
accountMapper.update(account, Account::getBirthday);

MyBatis-Plus要用UpdateWrapper凑:

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);

字段名又是字符串,容易出错。


一套代码,兼容三种数据库

这是它最狠的地方。

MySQL、Oracle、PostgreSQL同时接入,写一套代码,不用改。

底层自动处理语法差异,逻辑删除、乐观锁、多租户配置一次,全数据库通用。

国产数据库迁移场景下,这个能力太实用了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

轻量到什么程度?

只对MyBatis做了少量扩展,不侵入源码,原有MyBatis配置完全兼容。

spring boot3集成:

<dependency>
  <groupId>cn.xbatis</groupId>
  <artifactId>xbatis-spring-boot3-starter</artifactId>
  <version>1.10.2</version>
</dependency>

配置和MyBatis一模一样:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dbName
    username: dbusername
    password: dbpassword

@MapperScan扫包,完事。


还有些什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • • 多数据源路由:一个方法里切不同数据库
  • • 逻辑删除:注解配置,不用改SQL
  • • 乐观锁:@Version注解,concurrency问题自动解决
  • • 动态默认值:{NOW}、{TODAY}这种占位符,后端自动填充
  • • 代码生成器:实体、Mapper、Service一条龙
  • • 单个Mapper模式:一个BasicMapper走天下

我的看法

xbatis不是要替代MyBatis,而是让MyBatis用起来更爽。

对比MyBatis-Plus,功能更多,API更简洁,类型安全更好。对比JPA,它走的是"半自动"路线——SQL封装成链式API,你能看清每一步在做什么,出了问题debug一目了然,不像JPA那样陷入"全自动黑盒"的调试地狱。

简单说:JPA适合"全自动省事"场景,xbatis适合"我要掌控感"场景。

对于新项目,直接上;对于已有MyBatis的项目,渐进式引入,没压力。

国产数据库迁移、多表复杂查询、追求开发效率——这几个场景重点推荐。

GitHub:https://github.com/xbatis/xbatis
官网:https://xbatis.cn

更多推荐