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

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

核心特性

🔌 多数据库支持

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

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

🗄️ MyBatis XML 风格

数据库映射配置

一行配置,轻松切换

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


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

切换数据库只需三步:

  1. 1. 修改 driver 为目标数据库类型
  2. 2. 在 config.local.js 中配置对应的数据库连接
  3. 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. 1. 统一的数据库映射配置 - 一行配置切换数据库类型
  2. 2. MyBatis XML 风格 - 业务逻辑与 SQL 分离,支持动态 SQL
  3. 3. 自动代码生成 - 根据 XML 自动生成 Service 层代码
  4. 4. 分数据库目录结构 - 便于管理不同数据库的 SQL 差异

这种设计让开发者可以:

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

相关链接

引用链接

[1] ruoyi-eggjs: https://github.com/undsky/ruoyi-eggjs
[2] ruoyi-eggjs-mybatis: https://github.com/undsky/ruoyi-eggjs-mybatis
[3] ruoyi-eggjs-mysql: https://github.com/undsky/ruoyi-eggjs-mysql
[4] ruoyi-eggjs-pgsql: https://github.com/undsky/ruoyi-eggjs-pgsql
[5] ruoyi-eggjs-sqlite: https://github.com/undsky/ruoyi-eggjs-sqlite
[6] ruoyi-eggjs-cli: https://github.com/undsky/ruoyi-eggjs-cli