璀璨之星 xbatis,横扫java界的ORM来了


做Java后端的人,ORM框架选型基本逃不出这几个:
MyBatis-Plus,JPA,或者干脆手写SQL。
JPA听起来很美好——全自动Mapping,实体写好就不用管了。但真到复杂查询的时候,JPQL写起来跟手写SQL差不多,还受限于ORM映射模型,调试困难,性能调优更是黑盒。MyBatis生态这么多年依然最活跃,不是没有原因的。
最近有个框架悄悄更新到1.10版本,功能多到让MyBatis-Plus汗颜,但知道的人不多——

xbatis,一款基于MyBatis封装的ORM框架。
先看对比,再说话
这是官方整理的和MyBatis-Plus功能对照,重点看我打✅它打❌的地方:
| 功能 | xbatis | MyBatis-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
更多推荐
所有评论(0)