【RuoYi-Eggjs】:多数据库与 MyBatis 特性详解

简介: RuoYi-Eggjs 是企业级 Node.js 框架,支持 MySQL、PostgreSQL、SQLite 一键切换,通过 MyBatis XML 风格实现 SQL 与业务分离,内置动态 SQL、自动代码生成与读写分离,助力高效开发。

【RuoYi-Eggjs】:多数据库与 MyBatis 特性详解

在企业级应用开发中,数据库的选择往往需要根据项目规模、性能需求、部署环境等因素灵活调整。RuoYi-Eggjs 项目通过精心设计的数据库抽象层,实现了 一行配置切换数据库 的能力,同时引入了 Java 开发者熟悉的 MyBatis XML 风格来编写 SQL,让业务逻辑与数据访问完美分离。

GitHub:https://github.com/undsky/RuoYi-Eggjs

核心特性

🔌 多数据库支持

项目原生支持三种主流数据库:

数据库 插件 适用场景
MySQL ruoyi-eggjs-mysql 生产环境首选,功能完善
PostgreSQL ruoyi-eggjs-pgsql 复杂查询、地理数据
SQLite ruoyi-eggjs-sqlite 开发测试、轻量部署

🗄️ MyBatis XML 风格

  • 业务逻辑与 SQL 完全分离
  • 支持动态 SQL 标签(if、where、set、foreach 等)
  • 参数化查询,自动防 SQL 注入
  • SQL 片段复用,提高可维护性

数据库映射配置

一行配置,轻松切换

config/config.default.js 中,只需修改 driver 字段即可切换数据库:

// 数据库映射配置
config.database = {
   
  master: {
   
    driver: "mysql",    // 切换为 "pgsql" 或 "sqlite" 即可
    instance: "ruoyi",  // 数据库实例名称
  },
  slave: {
   
    driver: "mysql",    // 从库配置(读操作)
    instance: "ruoyi",
  },
  readWriteSplit: false, // 是否启用读写分离
};

切换数据库只需三步:

  1. 修改 driver 为目标数据库类型
  2. config.local.js 中配置对应的数据库连接
  3. 重启应用

读写分离支持

对于高并发场景,可以启用读写分离:

config.database = {
   
  master: {
   
    driver: "mysql",
    instance: "ruoyi_master",  // 主库(写操作)
  },
  slave: {
   
    driver: "mysql",
    instance: "ruoyi_slave",   // 从库(读操作)
  },
  readWriteSplit: true,        // 启用读写分离
};

数据库连接配置

MySQL 配置

// config/config.local.js
config.mysql = {
   
  camelCase: true,  // 自动驼峰转换:user_name -> userName
  clients: {
   
    ruoyi: {
   
      host: "127.0.0.1",
      user: "root",
      password: "your_password",
      database: "ruoyi",
    },
  },
};

PostgreSQL 配置

config.pgsql = {
   
  camelCase: true,
  clients: {
   
    ruoyi: {
   
      host: "127.0.0.1",
      user: "ruoyi",
      password: "your_password",
      database: "ruoyi",
    },
  },
};

SQLite 配置

config.sqlite = {
   
  camelCase: true,
  clients: {
   
    ruoyi: {
   
      database: "./ruoyi.db",  // 数据库文件路径
    },
  },
};

MyBatis XML 映射

目录结构

项目采用分数据库类型的目录结构,便于管理不同数据库的 SQL 差异:

mapper/
├── mysql/           # MySQL 专用 SQL
│   └── ruoyi/
│       ├── SysUserMapper.xml
│       ├── SysRoleMapper.xml
│       └── ...
├── pgsql/           # PostgreSQL 专用 SQL
│   └── ruoyi/
│       └── ...
└── sqlite/          # SQLite 专用 SQL
    └── ruoyi/
        └── ...

XML 映射文件示例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper/mysql/ruoyi/SysUserMapper.xml">

    <!-- SQL 片段复用 -->
    <sql id="selectUserVo">
        select u.user_id, u.user_name, u.nick_name, u.email, 
               u.phonenumber, u.status, u.create_time
        from sys_user u
        left join sys_dept d on u.dept_id = d.dept_id
    </sql>

    <!-- 动态条件查询 -->
    <selects id="selectUserList" resultMap="SysUserResult">
        <include refid="selectUserVo"/>
        where u.del_flag = '0'
        <if test="userName != null and userName != ''">
            AND u.user_name like concat('%', #{userName}, '%')
        </if>
        <if test="status != null and status != ''">
            AND u.status = #{status}
        </if>
        <if test="params.beginTime != null and params.beginTime != ''">
            AND u.create_time &gt;= #{params.beginTime}
        </if>
    </selects>

    <!-- 动态更新 -->
    <update id="updateUser">
        update sys_user
        <set>
            <if test="nickName != null and nickName != ''">
                nick_name = #{nickName},
            </if>
            <if test="email != null">email = #{email},</if>
            <if test="status != null and status != ''">
                status = #{status},
            </if>
            update_time = sysdate()
        </set>
        where user_id = #{userId}
    </update>

    <!-- 批量删除 -->
    <delete id="deleteUserByIds">
        update sys_user set del_flag = '2' where user_id in
        <foreach collection="array" item="userId" 
                 open="(" separator="," close=")">
            #{userId}
        </foreach>
    </delete>

</mapper>

支持的动态 SQL 标签

标签 说明 示例
<if> 条件判断 <if test="userName">...</if>
<where> 智能 WHERE 子句 自动处理首个 AND/OR
<set> 智能 SET 子句 自动处理末尾逗号
<foreach> 循环遍历 IN 查询、批量操作
<choose> 多条件选择 类似 switch-case
<sql> SQL 片段定义 提取公共 SQL
<include> 引用 SQL 片段 复用公共 SQL

自动代码生成

Service 层自动生成

项目配套的 CLI 工具可以根据 XML Mapper 自动生成 Service 层代码:

# 启动代码生成器(自动监听模式)
npm run mapper

# 或手动执行
psy mapper

生成效果:

mapper/mysql/ruoyi/SysUserMapper.xml
        ↓ 自动生成
app/service/db/mysql/ruoyi/SysUserMapper.js

生成的 Service 代码

const Service = require('egg').Service;

class SysUserMapperService extends Service {
   
    mapper(sqlid, values, params) {
   
        return this.app.mapper(
            'mapper/mysql/ruoyi/SysUserMapper.xml', 
            sqlid, values, params
        );
    }

    db() {
   
        return this.app.mysql.get('ruoyi');
    }

    // 查询用户列表
    async selectUserList(values, params) {
   
        return await this.db().selects(
            this.mapper('selectUserList', values, params)
        );
    }

    // 更新用户
    async updateUser(values, params) {
   
        return await this.db().update(
            this.mapper('updateUser', values, params)
        );
    }

    // 批量删除
    async deleteUserByIds(values, params) {
   
        return await this.db().del(
            this.mapper('deleteUserByIds', values, params)
        );
    }
}

module.exports = SysUserMapperService;

实际使用

Controller 调用示例

// app/controller/system/user.js
class UserController extends Controller {
   

    async list() {
   
        const {
    ctx } = this;
        const params = ctx.request.body;

        // 调用自动生成的 Service
        const users = await ctx.service.db.mysql.ruoyi
            .sysUserMapper.selectUserList(
                ctx.helper.page(params),  // 自动分页
                params
            );

        ctx.body = {
    code: 200, data: users };
    }

    async update() {
   
        const {
    ctx } = this;
        const user = ctx.request.body;

        await ctx.service.db.mysql.ruoyi
            .sysUserMapper.updateUser([user.userId], user);

        ctx.body = {
    code: 200, msg: '更新成功' };
    }
}

分页查询

内置分页辅助方法,自动计算 LIMIT 参数:

// 请求参数
{
   
    "currentPage": 2,
    "pageSize": 20,
    "userName": "张三"
}

// 使用 ctx.helper.page() 自动注入分页参数
const sql = app.mapper(
    'namespace',
    'selectUserList',
    ctx.helper.page(params),  // 自动计算 [offset, limit]
    params
);

参数占位符

#{} - 预编译参数(推荐)

自动转义,防止 SQL 注入:

<select id="selectUser">
    SELECT * FROM sys_user WHERE user_name = #{userName}
</select>

${} - 直接替换

用于表名、字段名等不可参数化的部分(注意安全性):

<select id="selectByColumn">
    SELECT * FROM sys_user ORDER BY ${orderColumn} ${orderType}
</select>

开发工作流

推荐流程

# 1. 启动开发环境(自动生成 Mapper + 调试)
npm run dev

# 2. 编写/修改 XML Mapper 文件
# 3. CLI 自动检测变化并重新生成 Service
# 4. 在 Controller 中调用 Service

package.json 脚本

{
   
  "scripts": {
   
    "dev": "npm-run-all -p mapper debug",
    "mapper": "psy mapper",
    "debug": "egg-bin debug",
    "start": "egg-scripts start",
    "stop": "egg-scripts stop"
  }
}

数据库切换实战

场景:从 MySQL 切换到 SQLite

步骤 1:修改数据库映射配置

// config/config.default.js
config.database = {
   
  master: {
   
    driver: "sqlite",   // 改为 sqlite
    instance: "ruoyi",
  },
  slave: {
   
    driver: "sqlite",
    instance: "ruoyi",
  },
  readWriteSplit: false,
};

步骤 2:配置 SQLite 连接

// config/config.local.js
config.sqlite = {
   
  camelCase: true,
  clients: {
   
    ruoyi: {
   
      database: "./ruoyi.db",
    },
  },
};

步骤 3:导入数据

sqlite3 ruoyi.db < sql/sqlite/ry_20250522.sql

步骤 4:重启应用

npm run dev

总结

RuoYi-Eggjs 通过以下设计实现了灵活的多数据库支持:

  1. 统一的数据库映射配置 - 一行配置切换数据库类型
  2. MyBatis XML 风格 - 业务逻辑与 SQL 分离,支持动态 SQL
  3. 自动代码生成 - 根据 XML 自动生成 Service 层代码
  4. 分数据库目录结构 - 便于管理不同数据库的 SQL 差异

这种设计让开发者可以:

  • 开发阶段使用 SQLite 快速迭代
  • 测试阶段切换到 MySQL/PostgreSQL 验证兼容性
  • 生产环境根据需求选择最合适的数据库

真正实现了 一套代码,多库运行 的目标。

相关链接

目录
相关文章
|
2月前
|
XML Java 数据库连接
【RuoYi-Eggjs】:告别手写,自动生成代码
【RuoYi-Eggjs】是一款面向 Egg.js 项目的自动化代码生成工具,通过解析 MyBatis 风格的 XML Mapper 文件,智能生成标准化的 Service 层代码,彻底告别重复手写。支持实时监听、多数据库映射与内网穿透,提升开发效率与规范性。
145 7
|
2月前
|
SQL XML JavaScript
【RuoYi-Eggjs】:将若依带入 Node.js 世界的企业级后台管理系统
RuoYi-Eggjs 是基于 Egg.js 的企业级后台系统,100% 复刻若依功能,支持 MyBatis XML 风格 SQL、多数据库、JWT 认证、权限控制与代码自动生成,完美对接 RuoYi-Vue3 前端,助力 Node.js 开发者高效构建管理系统。
224 5
|
人工智能 监控 网络协议
【网络技术】心跳机制(入门讲解)
【网络技术】心跳机制(入门讲解)
|
2月前
|
运维 JavaScript Java
Java精品项目:基于SaaS的多租户ERP系统源码(含生产、财务、OA)
云ERP是面向小微企业的SaaS多租户管理系统,集成进销存、MRP生产、品质、仓储、财务、CRM、OA等一体化功能。基于SpringBoot+Vue架构,支持云端一键部署,具备高度集成、实时协同、灵活配置与安全可靠等核心优势,助力企业数字化转型。
203 0
|
缓存 Java Spring
07HandlerMapping中用到的RequestMappingInfo和RequestCondition
RequestCondition(请求匹配条件)体系。 上面提到的RequestMapping注解申明的属性与之呼应的就是spring中RequestCondition的实现体系。 RequestMappingInfo体系 RequestMappingInfo是请求映射信息的描述,维护了一个请求所匹配的各种条件。即一个请求是有很多匹配条件的都放在了RequestMappingInfo中 RequestMappingInfo的生成、存放、和获取
1838 0
|
2月前
|
数据采集 机器学习/深度学习 人工智能
大模型训练全解析:从数据“喂养”到智能涌现
本文深入浅出地讲解大模型训练的核心原理与实操步骤,从数据准备、Transformer架构到预训练与微调,结合代码示例手把手教你打造专属AI模型,并展望未来发展趋势,助力开发者快速入门并应用大模型技术。
|
7月前
|
人工智能 数据可视化 算法
企业想做数智化,数据仓库架构你得先搞懂!
在数智化浪潮下,数据驱动已成为企业竞争力的核心。然而,许多企业在转型过程中忽视了数据仓库这一关键基础。本文深入解析数据仓库的重要性,厘清其与数据库的区别,详解ODS、DWD、DWS、ADS分层逻辑,并提供从0到1搭建数据仓库的五步实战方法,助力企业夯实数智化底座,实现数据治理与业务协同的真正落地。
企业想做数智化,数据仓库架构你得先搞懂!
|
4月前
|
人工智能 监控 安全
2025年国内主流数据治理与数据中台产品大全,国内数据治理厂商推荐
在数字化转型加速的背景下,数据治理与数据中台成为企业释放数据价值的关键。本文聚焦国内市场,精选10款代表性产品——包括瓴羊Dataphin、腾讯WeData、华为DataArts Studio、字节Dataleap、网易数帆EasyData、奇点云DataSimba、袋鼠云DTinsight、亚信AISWare DataOS、星环TDS和数澜Datahub,从核心能力、架构特点与适用场景等维度进行解析。这些产品各具优势,文章建议企业结合自身规模、业务特性与技术基础,选择匹配的数据平台,以实现数据驱动的高质量发展。
2025年国内主流数据治理与数据中台产品大全,国内数据治理厂商推荐
|
网络协议 关系型数据库 MySQL
【Linux环境】Centos7.x 安装MySQL,使用Navicat等远程连接工具报2003-Can‘t connect to MySQL server on(10060 Unknown err)
【Linux环境】Centos7.x 安装MySQL,使用Navicat等远程连接工具报2003-Can‘t connect to MySQL server on(10060 Unknown err)
1055 0
|
iOS开发 MacOS Python
【Python】已解决:(Pycharm切换Python版本后报错)No Python at “C:\Program Files\Python39\python.exe”
【Python】已解决:(Pycharm切换Python版本后报错)No Python at “C:\Program Files\Python39\python.exe”
1531 0
【Python】已解决:(Pycharm切换Python版本后报错)No Python at “C:\Program Files\Python39\python.exe”

热门文章

最新文章