导读: 若依(RuoYi)是国内使用广泛的 Java 快速开发框架,默认依赖 MySQL。但在演示环境、非专业研发人员使用、轻量级部署场景下,安装和维护 MySQL 显得过于"重"。本文记录了将若依项目改造为使用 H2 内嵌数据库的完整过程,包括踩坑记录与解决方案,供有同样需求的开发者参考。
一、为什么选择 H2?
H2 是一款纯 Java 编写的内嵌关系型数据库,具备以下优势:
-
零安装
:随 JAR 包启动,无需独立安装数据库服务
-
兼容 MySQL 语法
:通过
MODE=MYSQL配置可兼容大部分 MySQL 语法 -
自带 Web 控制台
:方便开发调试,无需额外工具
-
适合轻量部署
:演示环境、CI/CD 流水线、本地开发首选
二、依赖配置
在 pom.xml 中添加 H2 相关依赖:
【特别注意】RuoYi v4.8.3 使用的spring-boot最新版本4.0.3,h2-console需单独引用
<!-- H2 数据库驱动 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!-- H2 控制台(Spring Boot 集成) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-h2console</artifactId>
</dependency>
三、数据源配置
修改 application.yml,将数据源切换为 H2:
spring:
h2:
console:
enabled:true # 开启 H2 Web 控制台
datasource:
druid:
master:
driverClassName:org.h2.Driver
url:jdbc:h2:file:./data/h2db;MODE=MYSQL # 文件模式 + MySQL 兼容
username:sa
password:password
说明:
jdbc:h2:file:./data/h2db表示数据库以文件形式持久化存储在./data/目录下,重启后数据不丢失。MODE=MYSQL开启 MySQL 兼容模式。
四、接入 H2 控制台
若依框架有权限控制,直接访问 /h2-console 会被拦截。需要新增一个控制器做跳转:
@Controller
@RequestMapping("/tool/h2")
publicclassH2ConsoleControllerextendsBaseController {
@RequiresPermissions("tool:h2:view")
@GetMapping()
public String index() {
return"redirect:/h2-console";
}
}
同时在系统菜单 中添加菜单项,路径配置为 /tool/h2,即可通过若依的权限体系访问 H2 控制台。
五、建表 SQL 的坑与解决方案
将 MySQL 的建表 SQL 迁移到 H2 时,使用AI生成适配的SQL文件,如下图所示:

AI 生成的 SQL 文件(ry_20260319_h2.sql、quartz_h2.sql)存在以下几类问题:
1. 转义字符问题
| 问题 | MySQL 写法 | H2 正确写法 |
|---|---|---|
| 单引号转义 | \' |
'' (两个单引号) |
| 双引号 | \" |
" (无需反斜杠) |
2. 自增主键序列问题
初始化 SQL 中包含带主键值的 INSERT 语句,导致 H2 的自增序列不会自动更新。后续通过页面新增数据时,主键从 1 开始,与已有数据冲突。
解决方案: 在初始化 SQL 末尾追加序列重置语句:
ALTER TABLE SYS_CONFIG ALTERCOLUMN config_id RESTART WITHSELECTMAX(config_id)+1FROM SYS_CONFIG;
ALTER TABLE SYS_DEPT ALTERCOLUMN dept_id RESTART WITHSELECTMAX(dept_id)+1FROM SYS_DEPT;
ALTER TABLE SYS_DICT_DATA ALTERCOLUMN dict_code RESTART WITHSELECTMAX(dict_code)+1FROM SYS_DICT_DATA;
ALTER TABLE SYS_DICT_TYPE ALTERCOLUMN dict_id RESTART WITHSELECTMAX(dict_id)+1FROM SYS_DICT_TYPE;
ALTER TABLE SYS_JOB ALTERCOLUMN job_id RESTART WITHSELECTMAX(job_id)+1FROM SYS_JOB;
ALTER TABLE SYS_MENU ALTERCOLUMN menu_id RESTART WITHSELECTMAX(menu_id)+1FROM SYS_MENU;
ALTER TABLE SYS_NOTICE ALTERCOLUMN notice_id RESTART WITHSELECTMAX(notice_id)+1FROM SYS_NOTICE;
ALTER TABLE SYS_POST ALTERCOLUMN post_id RESTART WITHSELECTMAX(post_id)+1FROM SYS_POST;
ALTER TABLE SYS_ROLE ALTERCOLUMN role_id RESTART WITHSELECTMAX(role_id)+1FROM SYS_ROLE;
ALTER TABLE SYS_USER ALTERCOLUMN user_id RESTART WITHSELECTMAX(user_id)+1FROM SYS_USER;
3. MySQL 函数替换
H2 不支持部分 MySQL 专有函数,需逐一替换:
① 当前时间函数
-- MySQL
sysdate()
-- H2 替换为
CURRENT_TIMESTAMP()
② 时间范围查询
-- MySQL(date_format 函数 H2 不支持)
AND date_format(create_time,'%Y%m%d') >= date_format(#{params.beginTime},'%Y%m%d')
AND date_format(create_time,'%Y%m%d') <= date_format(#{params.endTime},'%Y%m%d')
-- H2 替换为(直接字符串拼接时间范围)
AND create_time >= concat(#{params.beginTime},' 00:00:00')
AND create_time <= concat(#{params.endTime},' 23:59:59')
③ CAST 类型转换
-- MySQL(cast as char 在 H2 中不兼容)
CAST(notice_content ASchar)
-- H2 替换为(直接使用字段名)
notice_content
④ FIND_IN_SET 函数
-- MySQL(H2 不支持 FIND_IN_SET)
find_in_set(#{deptId}, ancestors)
-- H2 替换为(使用 INSTR 模拟)
INSTR(CONCAT(ancestors,','), CONCAT(#{deptId},','))
原理说明:
FIND_IN_SET是 MySQL 专有函数,用于在逗号分隔的字符串中查找指定值。H2 中可用INSTR函数替代------通过在ancestors末尾追加逗号,再查找deptId,的位置,避免子串误匹配(如1匹配到10、11等)。
六、暂不改造的部分
代码生成器目前暂未进行 H2 适配,如需使用代码生成功能,切换回 MySQL 数据源即可。后续有时间再研究。
七、总结
| 改造项 | 状态 | 备注 |
|---|---|---|
| 依赖引入 | ✅ 完成 | 添加 H2 驱动和控制台依赖 |
| 数据源配置 | ✅ 完成 | 文件模式 + MySQL 兼容 |
| H2 控制台接入 | ✅ 完成 | 通过权限控制器跳转 |
| 建表 SQL 迁移 | ✅ 完成 | 修复转义、序列、函数问题 |
| 代码生成器 | ⏳ 待改造 | 暂时使用 MySQL |
整体改造工作量不大,主要精力在 SQL 兼容性处理上。改造完成后,项目可以做到开箱即用、无需安装任何外部数据库,非常适合演示和轻量化部署场景。
如果本文对你有帮助,欢迎点赞收藏,有问题欢迎在评论区交流 👇