MyBatis-Plus 3.5.17 支持 GraalVM Native Image:CRUD 工具链开始向原生镜像靠拢

2026-07-09 34 预计阅读时间: 1 分钟
来源: oschina.net AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

MyBatis-Plus 3.5.17 的一个关键信号是:它开始支持 GraalVM Native Image。对依赖 MyBatis-Plus 做单表 CRUD、XML 配置加载和动态 SQL 注入的 Java 项目来说,这意味着原生镜像部署不再只是框架层面的事情,数据访问增强工具也需要进入 AOT 约束下的运行模型。

为什么这个版本值得后端团队关注

MyBatis-Plus 的定位一直很明确:它不是替代 MyBatis,而是在 MyBatis 之上减少样板代码。常见的 BaseMapper、条件构造器、通用 Service、分页插件,都是为了让团队少写重复 CRUD,把精力放在业务规则上。

这类工具在普通 JVM 下运行得很自然:启动时读取 XML、扫描 Mapper、注入单表 SQL、拼装动态 SQL 脚本。问题在于,GraalVM Native Image 对运行时反射、动态代理、资源加载和类路径扫描都有更严格的要求。一个库如果没有考虑 Native Image,常见结果是:JVM 模式正常,打成原生镜像后 Mapper 找不到、XML 没被打包、反射访问失败。

3.5.17 支持 GraalVM Native Image,说明 MyBatis-Plus 正在补齐这条链路。它对云原生、Serverless、CLI 工具、低内存容器环境都更有意义:启动更快、镜像运行时内存更低,但构建约束也更硬。

Native Image 会放大哪些 MyBatis 使用习惯

MyBatis-Plus 在启动阶段会做不少工作:基于实体和 Mapper 注入单表 SQL 操作,加载 XML 配置,生成动态 SQL 脚本。这些能力正是它提升生产率的来源。

放到 Native Image 里,开发者需要多看几个边界:

  • XML Mapper 是否作为资源进入原生镜像;
  • 实体类、Mapper、插件相关类型是否涉及反射;
  • 动态 SQL 是否依赖运行时无法分析的类加载行为;
  • 数据库驱动是否支持或适配 GraalVM Native Image;
  • 构建插件是否和当前 Spring Boot、MyBatis、MyBatis-Plus 版本匹配。

也就是说,MyBatis-Plus 3.5.17 的支持降低了库层面的障碍,但项目仍要把资源、驱动、配置一起纳入验证。Native Image 不是把 java -jar 换成一个二进制文件那么简单。

可以这样实践:准备一个最小 Spring Boot + MyBatis-Plus Native 构建

下面示例不是官方声明的唯一方式,而是一个可改造的实践骨架。你需要根据自己的 Spring Boot 版本、数据库驱动和 GraalVM 环境调整版本号。

pom.xml 可以从这样的结构开始:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>mp-native-demo</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <properties>
    <java.version>17</java.version>
    <spring-boot.version>3.3.5</spring-boot.version>
    <mybatis-plus.version>3.5.17</mybatis-plus.version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
      <version>${mybatis-plus.version}</version>
    </dependency>

    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <scope>runtime</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring-boot.version}</version>
        <configuration>
          <image>
            <builder>paketobuildpacks/builder-jammy-tiny</builder>
            <env>
              <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
            </env>
          </image>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.graalvm.buildtools</groupId>
        <artifactId>native-maven-plugin</artifactId>
        <version>0.10.3</version>
      </plugin>
    </plugins>
  </build>
</project>

一个最小实体和 Mapper:

package com.example.demo;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

@TableName("users")
public class User {
    @TableId
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.example.demo;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

应用入口和一个简单接口:

package com.example.demo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@SpringBootApplication
@MapperScan("com.example.demo")
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@RestController
class UserController {
    private final UserMapper userMapper;

    UserController(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @GetMapping("/users")
    List<User> users() {
        return userMapper.selectList(null);
    }
}

配套资源文件:

spring:
  datasource:
    url: jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1
    driver-class-name: org.h2.Driver
    username: sa
    password:
  sql:
    init:
      mode: always

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
CREATE TABLE users (
  id BIGINT PRIMARY KEY,
  name VARCHAR(64) NOT NULL
);

INSERT INTO users(id, name) VALUES (1, 'Ada'), (2, 'Linus');

本地先跑 JVM 模式,再构建 Native Image:

mvn spring-boot:run
curl http://localhost:8080/users

mvn -Pnative native:compile
./target/mp-native-demo
curl http://localhost:8080/users

如果你使用 XML Mapper,务必确认 XML 被放进镜像资源。可以在 src/main/resources/mapper/UserMapper.xml 下放文件,并在配置中声明路径:

mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml

Native 构建失败时,不要只看最后一行错误。重点搜索 reflectionresourceproxyClassNotFoundExceptionNoSuchMethodException 这些关键词,通常能定位到缺少反射配置、资源没打包或驱动不兼容。

迁移时别只盯着“能不能编过”

引入 Native Image 支持后,最容易犯的错是把构建成功当成上线就绪。数据访问层更适合用一组小而硬的验证来兜底:

  • 用真实数据库驱动跑一次集成测试,不只用 H2;
  • 覆盖 BaseMapper 的增删改查,以及你项目里的自定义 XML SQL;
  • 检查分页、乐观锁、逻辑删除、自动填充等 MyBatis-Plus 插件是否在 Native 镜像下行为一致;
  • 记录 Native 构建时间和 CI 资源消耗,避免拖慢主干流水线;
  • 对比 JVM 与 Native 的启动时间、RSS 内存、首个请求延迟,而不是只看理论收益。

MyBatis-Plus 3.5.17 对 GraalVM Native Image 的支持,是一个很实际的基础设施进展。它让熟悉 MyBatis-Plus 的团队有机会把同一套 CRUD 开发体验带到原生镜像部署里。但 Native Image 的收益来自完整链路:框架、ORM 增强、数据库驱动、资源配置、测试流水线都要一起过关。稳妥的做法是先挑一个边界清晰的服务试点,再把经验沉淀成项目模板和 CI 检查项。


相关推荐