一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

MyBatis 该退休了?看看 dbVisitor 如何用重塑 DAL 层

时间:2026-08-19 09:24:01 编辑:袖梨 来源:一聚教程网

你是否经历过这样的绝望:

为了给一个简单的查询加个status != -1的条件,你不得不在 XML 里写一堆标签?或者,为了同时查询 MySQL 和 MongoDB,你的 Service 层里充斥着风格迥异的UserMapperMongoTemplate代码?

MyBatis 很好,陪伴了我们十年。它稳定、强大,是 Java 该领域的绝对霸主。但面对现在的多数据源架构轻量化开发需求,这艘巨轮是不是显得有点“重”了?dbVisitor 的诞生并非为了重复造轮子,而是为了在保持 MyBatis 核心开发习惯(Mapper/XML)的同时,解决那些让你头疼已久的痛点。

tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
tt

功能体验

tt
tt

MyBatis

tt
tt

MyBatis-Plus

tt
tt

dbVisitor

tt
tt

备注

tt
tt

Mapper 接口开发

tt
tt

tt
tt

tt
tt

tt
tt

都支持定义 Interface 自动代理

tt
tt

XML SQL 定义

tt
tt

tt
tt

tt
tt

tt
tt

标签结构高度兼容 (ResultMap/select...)

tt
tt

注解 SQL 定义

tt
tt

tt
tt

tt
tt

tt
tt

@Select / @Insert 等注解支持

tt
tt

DTO/Bean 映射

tt
tt

tt
tt

tt
tt

tt
tt

自动驼峰转换、ResultMap 映射

tt
tt

Lambda 链式调用

tt
tt

tt
tt

tt
tt

tt
tt

类型安全的 CRUD 构建器

tt
tt

分页查询

tt
tt

tt
tt

tt
tt

tt
tt

直接在 API 或 SQL 中控制分页

tt
tt

即时 SQL 执行

tt
tt

tt
tt

tt
tt

tt
tt

无需定义 Mapper 也能直接运行 SQL

tt
tt

动态规则 (Rules)

tt
tt

tt
tt

tt
tt

tt
tt

脚本式动态 SQL@{and ...}

tt
tt

NoSQL 支持

tt
tt

tt
tt

tt
tt

tt
tt

一套 API 操作 MySQL/Mongo/ES

tt

通过对比 dbVisitor 和 MyBatis 的 XSD 定义文件,可以发现惊人的相似性(两者都以为根节点,核心标签 SELECT * FROM user WHERE id = #{id}

dbVisitor (UserMapper.xml)

    

1.3 注解 SQL 定义

MyBatis

@Select("SELECT * FROM user WHERE name = #{name}")User selectByName(String name);

dbVisitor

@Query("SELECT * FROM user WHERE name = #{name}")User selectByName(@Param("name") String name);

1.4 DTO/Bean 映射

在字段名不一致(如 DB 是user_name,Java 是name)的场景下,映射方式的繁简程度决定了开发效率。

MyBatis (XML 派)

MyBatis 倾向于通过 XML 中的ResultMap来解决字段映射问题。虽然开启驼峰配置(mapUnderscoreToCamelCase)能解决简单场景,但面对差异较大的字段名,开发者不得不编写冗长的resultMap标签。

        

MyBatis-Plus (注解派)

MP 引入了注解驱动,允许直接在实体类上定义映射关系,从而摆脱对ResultMap的依赖。

public class User {    @TableField("user_name") // 使用注解解决映射    private String name;}

dbVisitor (全兼容)

dbVisitor 选择了“我全都要”的兼容策略,你可以在三种模式中任意切换:

  1. 自动映射(默认):内置智能的驼峰转换,90% 的场景无需任何配置。

  2. 注解模式(MP 风格):使用@Column注解定义特定字段,无需 XML。

    public class User {    @Column("user_name") // 类似 MP 的 @TableField    private String name;}
  3. ResultMap 模式(MyBatis 风格):完全兼容 MyBatis 的标签。如果你正在迁移旧项目,或者需要非常复杂的嵌套映射,直接把旧的 XML 拿来用即可。

        

1.5 Lambda 链式调用

dbVisitor 提供了一套类型安全的 Lambda 构建器,它的核心价值不仅仅是像 MyBatis-Plus 那样避免手写 SQL,更在于它实现了“One API Access Any DataBase”的理念。无论底层是 MySQL、Oracle 还是 MongoDB、Elasticsearch,你都可以使用同一套 Lambda API 进行操作。这意味着你的团队只需要掌握一种 CRUD 语法。

用法对比

  • MyBatis-Plus:强依赖Mapper接口,API 设计主要面向 SQL 数据库。

  • dbVisitor:基于LambdaTemplate,无需定义接口即可直接使用。

// 统一入口:无论操作什么数据库,起点都是 template new 出来即可JdbcTemplate template = ...;

场景 1:标准 SQL 查询 (MySQL/PG)

// 使用 Java 方法引用避免字段拼写错误UserInfo user = template.lambdaQuery(UserInfo.class)    .eq(UserInfo::getType, "admin")    .gt(UserInfo::getAge, 18)    .list();

场景 2:统一关系型非关系型数据库

神奇之处在于,完全相同的代码,也可以用于操作 Elasticsearch 或 MongoDB,dbVisitor 会自动将查询条件转译为对应的 DSL。

// 操作 Elasticsearch (自动转换为 DSL)// GET /user_index/_search { "query": { "bool": ... } }EsUser user = template.lambdaQuery(EsUser.class)    .eq(EsUser::getId, "1001") // 通过 EsUser 的字段映射为 _id    .one();
// 操作 MongoDB// db.access_log.insert({ ... })template.lambdaInsert(AccessLog.class)    .applyEntity(new AccessLog(...))    .executeSumResult();

这种统一性极大地降低了多数据源混合架构的维护成本。

2.1 即时 SQL 执行

即时 SQL 执行能力不仅是“能执行 SQL”,更代表了框架在不同抽象层级上的灵活度。dbVisitor 允许你在三种层级上自由切换,无需被 XML 束缚。

A. 纯血 SQL

这是dbVisitor最基础的模式。它高度复刻了 Spring JDBC 的能力(如queryForList,query,execute等)

// 1. 获取 TemplateJdbcTemplate jdbc = ...;// 2. 直接执行 SQL,利用 dbVisitor 强大的 Mapper 映射结果List users = jdbc.queryForList(            "select * from user where age > ?", UserInfo.class, 18);// 3. 甚至执行脚本jdbc.execute("delete from user where age < 10");

B. Lambda API 上使用 SQL

LambdaTemplate虽然主打类型安全的构建器,但它同样允许你在 Lambda 中直接执行原生 SQL。

LambdaTemplate lambda = ...;lambda.jdbc().queryForList("select * from user where status = ?", User.class, 1);

C. Mapper 接口上使用 SQL

这是MyBatisMyBatis-Plus不具备的,同时也被诟病最多的地方。

  • 用户:我就是想用一下 SQL 不要给我搞注解、搞 XML 好不好!

  • MyBatis/MP:抱歉不行!

  • dbVisitor:没问题马上安排!

@SimpleMapperpublic interface UserMapper extends BaseMapper {    // 方式 1: 传统的注解模式    @Query("select * from user where type = #{type}")    List findByType(@Param("type") String type);    // 方式 2: default 方法 + 内置 JDBC 能力    // 适合:逻辑复杂,不想写 XML,但又想封装在 Mapper 里的场景    default List findActiveUsers() {        return this.jdbc().queryForList(                "select * from user where active = 1", UserInfo.class);    }}

2.2 动态规则

本质是对动态 SQL 拼接的一种创新解决方案。它改变了 MyBatis 系列中标签泛滥的问题。

  • MyBatis 系列:依赖 XML 标签(,,)来实现动态 SQL,导致 XML 结构臃肿且难以维护。

  • dbVisitor:引入@{…}语法,将条件动态嵌入 SQL 字符串中,极大简化了动态 SQL 的编写。

还能这么用?

// 在 SQL 中使用JdbcTemplate jdbc = ...;List users = jdbc.queryForList(            "SELECT * FROM user @{and name = :name} @{and age > :age}",            UserInfo.class, 18);
// 在 Mapper 接口注解中用@SimpleMapperpublic interface UserMapper extends BaseMapper {    @Query("SELECT * FROM user @{and name = :name} @{and age > :age}")    List findByType(UserInfo info);}

优势总结

  • 极简主义:没有,没有Wrapper,只有纯粹的 SQL。

  • 直观:看一眼就知道这段 SQL 包含哪些条件逻辑。

  • 复用性:这行 SQL 字符串可以写在 XML 里,也可以写在注解里,甚至写在纯血 SQL 里面。

仅仅十年前,一个 MySQL 可能就承载了一个系统的所有数据。但现在的应用架构往往是混合的。

❌ MyBatis/MP 的困境:割裂

MyBatis 设计之初就是为了 RDBMS(SQL)服务的。在一个混合架构(MySQL 存用户,MongoDB 存日志,ES 存商品)中,代码往往是分裂的:

// 1. MySQL (MyBatis) - 面向 MapperuserMapper.selectById(1L);// 2. MongoDB (Spring Data) - 面向 Repository/TemplateQuery query = new Query(Criteria.where("userId").is(1L));mongoTemplate.find(query, UserLog.class);// 3. Elasticsearch (RestHighLevelClient) - 面向 Request 构建SearchRequest request = new SearchRequest("goods");request.source(new SearchSourceBuilder().query(QueryBuilders.matchQuery("name", "手机")));client.search(request, RequestOptions.DEFAULT);

痛点

  • 认知负荷高:团队需要掌握 3 套不同的 API 风格(Mapper, Criteria, Builder)。

  • 维护困难:无法统一处理事务、日志坚控和异常体系。

  • 代码割裂:业务逻辑中充斥着不同风格的 DAL 代码。

✅ dbVisitor 的解法:统一

dbVisitor 通过双层适配器设计实现了“One API Access Any DataBase”。无论是关系型数据库还是 NoSQL,你都可以用完全相同的 Lambda 语法进行操作。

同一套 API,操作所有数据源:

// 1. MySQL - 查用户// 生成 SQL: select * from user where id = 1UserInfo user = template.lambdaQuery(UserInfo.class)    .eq(UserInfo::getId, 1)    .one();// 2. MongoDB - 查日志// 生成 Mondo Shell: db.user_log.find({ "user_id": 1 })List logs = template.lambdaQuery(UserLog.class)    .eq(UserLog::UserId, 1)    .list();// 3. Elasticsearch - 查商品// 生成 DSL: { "query": { "term": { "name": "手机" } } }List goods = template.lambdaQuery(Goods.class)    .eq(Goods::getName, "手机")    .list();

优势

  • 零学习成本:只要会写 MySQL 查询,就会写 ES 查询。

  • 统一管控:所有的查询(无论底层是 SQL 还是 DSL)都走统一的执行链路,这意味着可以轻松实现统一的 SQL 耗时打印、慢查询报警。

回到最初的问题:dbVisitor 和 MyBatis 你会怎么选?

  • 坚守 MyBatis 的理由

      t
    • t

      你的项目是单纯的RDBMS(关系型数据库)项目,且团队成员对 MyBatis 倒背如流。

      t
    • t
    • t

      你需要极其精细的 SQL 控制能力,或者项目依赖了大量基于 MyBatis 的老旧插件(如特定的 PageHelper 版本)。

      t
    • t
    • t

      追求绝对的稳健,认为“也是一种美”,不愿意尝试新框架。

      t
  • 拥抱 dbVisitor 的理由

      t
    • t

      你的项目是混合架构(MySQL + MongoDB/ES),你受够了在 Mapper、Repository 和各种 Client 之间精神分裂般的切换。

      t
    • t
    • t

      你厌倦了 MyBatis 繁琐的 XML标签,渴望更现代、更简洁的动态 SQL 写法。

      t
    • t
    • t

      你需要更高的灵活性,比如在 Service 层直接执行 SQL,或者不写 XML 直接用 Lambda 嗦哈。

      t
    • t
    • t

      你是一个追求开发效率的“实用主义者”,希望用20% 的代完成 80% 的工作

      t

一句话总结:如果你想要 MyBatis 的,请继续使用 MyBatis;如果你想要 MyBatis 的,再加上 Spring Data 的和 Lambda 的,那么 dbVisitor 是你当下最好的选择。

  • 项目首页:https://www.dbvisitor.net/

  • 项目源码:https://gitee.com/zycgit/dbvisitor/

",

热门栏目