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

SpringBoot+Vue+MySQL 高校学科竞赛平台 完整可运行版(源码+文档) 本项目基于SpringBoot+Vue+MySQL构建高校学科竞赛管理平台,覆盖学生、教师、领队教师、管理员四大角色,实现竞赛发布、报名、刷题、评分、公示等全流程闭环管理。系统架构清晰,技术主流,配套完整源码、数据库脚本、万字论文、开题报告、答辩PPT及部署文档,支持一键运行,适用于毕业设计、课程设计及院系二次开发,真正实现“开箱即用”。 阅读详情

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

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

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

点击获取最新AI资讯、n8n工作流、开发经验分享

核心特性

🔌 多数据库支持

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

数据库插件适用场景
MySQLruoyi-eggjs-mysql生产环境首选,功能完善
PostgreSQLruoyi-eggjs-pgsql复杂查询、地理数据
SQLiteruoyi-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 验证兼容性
  • 生产环境根据需求选择最合适的数据库

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

相关链接

Android GWP-Asan机制详解 基本用途:GWP-ASan是一种原生内存分配器功能,在内存分配时额外记录一些信息,用于检测DOUBLE_FREE、USE_AFTER_FREE、INVALID_FREE、BUFFER_OVERFLOW、BUFFER_UNDERFLOW五种内存错误问题。 阅读详情

相关推荐

实战指南:用Python实现ONVIF WS-Discovery设备发现(附完整代码)

本文提供了一份详细的实战指南,介绍如何使用Python实现基于ONVIF标准的WS-Discovery设备发现协议。文章深入解析了协议原理、网络通信模型,并提供了完整的代码实现,帮助开发者快速构建智能安防和物联网应用中的设备自动发现工具,有效提升网络设备集成与管理的效率。

chair的专栏 1114

【RuoYi-Eggjs】:将若依带入 Node.js 世界的企业级后台管理系统

若依 Nodejs 版本,基于 Eggjs,100% 实现若依(RuoYi-Vue)系统功能。

AI时代超级个体,专注AI应用落地,开发经验分享 1280

首发!谷歌倾斜摄影数据转换生成OSGB格式

全球首发,谷歌倾斜摄影模型文件能直接转换成OSGB格式!

cyber_room的博客 2287

【RuoYi-Eggjs】:让 MySQL 更简单

`ruoyi-eggjs-mysql` 是一款基于 `mysql2` 的 Egg.js 插件,通过提供简洁 API、实时 SQL 监控、智能驼峰转换及事务支持等开箱即用的功能,解决了繁琐的配置痛点,从而显著提升开发效率。

AI时代超级个体,专注AI应用落地,开发经验分享 409

面试题-手撕NMS(非极大值抑制)

非极大值抑制(Non-Maximum Suppression,NMS)是一种常用于目标检测和计算机视觉中的算法,用于去除重叠的边界框,保留最可能是真实目标的边界框。其核心就是对一组检测框,找出其中属于同一个类别且分数最高的那个框,然后把和这个框的IOU值大于阈值的那些框都删掉。

zhaoyqcsdn的博客 1109

ByteTrack参数调优全攻略:从原理到实战(含YOLOv8示例)

本文深入解析了ByteTrack多目标跟踪算法的核心原理与参数调优策略。通过拆解其独特的两阶段关联机制,并结合YOLOv8检测器,提供了针对不同应用场景(如拥挤行人、高速车辆)的精细化参数调整指南与实战示例,旨在帮助开发者解决ID切换、目标丢失等工程落地难题,提升跟踪系统的鲁棒性与实用性。

cheese的博客 323

【RuoYi-Eggjs】:缓存,让你的应用飞起来

为 RuoYi-Eggjs 量身定制的缓存插件,基于强大的 cache-manager 生态,提供了开箱即用的缓存能力

AI时代超级个体,专注AI应用落地,开发经验分享 1288

AGM Supra软件从零到一:国产CPLD工程创建全流程拆解

本文详细拆解了AGM Supra软件从零开始创建国产CPLD工程的全流程,包括开发环境配置、工程创建、Quartus项目转换、TCL脚本执行与编译等关键步骤。特别强调了中文路径避坑、器件型号选择等实用技巧,帮助开发者高效完成CPLD开发任务。

weixin_29158413的博客 410

【RuoYi-Eggjs】:告别手写,自动生成代码

【RuoYi-Eggjs】:告别手写,自动生成代码 , MyBatis 风格的 Service 代码生成器

AI时代超级个体,专注AI应用落地,开发经验分享 597

数据结构之博弈树搜索(深度优先搜索)

数据结构之博弈树搜索(深度优先搜索)

LucianaiB的博客 1526

基于PChmi.dll的PLC报警显示和记录(C#)

本文介绍了如何使用C#编写基于PChmi.dll的程序,实现PLC报警的显示和记录功能。通过订阅PLC的报警事件,我们可以实时显示报警信息,并通过日志文件记录报警历史。PLC(可编程逻辑控制器)在工业自动化领域中扮演着重要的角色,而报警显示和记录是PLC应用中常见的需求。本文将介绍如何使用C#编写基于PChmi.dll的程序,实现PLC报警的显示和记录功能。当然,这只是实现报警显示和记录的基本框架,具体的实现方式可能因不同的PLC和HMI库而有所差异。你需要根据你所使用的具体库和设备进行相应的调整和修改。

ByteLegend的博客 1673

【RuoYi-Eggjs】:限流,为 API 保驾护航

基于 rate-limiter-flexible 的限流插件,用于保护 API 免受恶意请求和过载。

AI时代超级个体,专注AI应用落地,开发经验分享 1002

详解AXI4-Lite接口(3)--AXI4-Lite接口IP源码仿真及分析(Master接口)

通过本文您会学到:1、了解AXI4-Lite_Master接口的逻辑实现;2、加深Xilinx IP、仿真工具的使用;3、提高阅读时序图的能力。

孤独的单刀 6446

【RuoYi-Eggjs】:把 MyBatis 带到 Node.js

MyBatis 风格的 SQL 映射插件,支持使用 XML 文件编写动态 SQL,让 Node.js 开发者也能享受 MyBatis 的便利。

AI时代超级个体,专注AI应用落地,开发经验分享 1044

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

基于Ant Design Vue的ruoyi-ant前端框架终极指南

在当今快速发展的Web开发领域,选择一个合适的前端框架至关重要。ruoyi-ant作为一款基于Ant Design Vue的现代化前端工程框架,为企业级应用开发提供了完美的解决方案。本文将带您深入了解这款框架的核心特性,并分享5分钟快速部署的实战经验。 ## 🚀 为什么选择ruoyi-ant前端框架? ruoyi-ant框架集成了Vue.js的响应式特性和Ant Design Vue的优雅组

gitblog_00131的博客 1031

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Spring Boot 数据源与 MyBatis(-Plus) 自定义配置详解

本文详解 Spring Boot 中单数据源环境下 HikariCP 与 MyBatis-Plus 的自定义配置。通过手动声明 SqlSessionFactory,实现下划线转驼峰、日志输出、一级缓存策略等精细化控制。结合 HikariCP 核心参数调优(如最大连接数、连接生命周期),确保高性能与稳定性。适用于仅需访问单一数据库的场景,避免多数据源复杂性,兼顾性能与可维护性。

BADAO_LIUMANG_QIZHI的博客 208

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

Java EE 进阶:8.MyBatis 操作数据库(入门)(第一弹)

要努力去发光,而不是被照亮~ 147

Docker Compose:搭建本地多服务开发环境

从一个 Java API、PostgreSQL 和 Redis 开始,配置服务名、端口、环境变量、健康检查、数据卷和依赖关系。理解 Compose 文件如何被解析、项目如何隔离,以及哪些数据不能依赖“重建容器”保留,能够把个人开发环境整理成团队可复用的启动入口。

m0_62221377的博客 462

AI全栈实战 | 3.9-01 爬虫入门:requests 加 BeautifulSoup 三分钟跑通,但 90% 的人栽在这 4 个“礼貌“问题上

⚠️:本文内容仅用于。请遵守目标站点的服务条款与相关法律法规,不得对目标服务造成负担,不得采集、传播个人隐私数据。技术是中性的,边界在你手里。爬虫的入门技术(requests 发请求 + BeautifulSoup 解析)三分钟就能学会。真正区分"会用爬虫"和"会做爬虫的人"的,是这篇我们跑通"请求→解析→存储"的最小闭环,然后重点把"合规与礼貌"这根弦给你绷上。

源码获取 | 运行部署 | 定制二开修改,如果回复不及时请耐心等待,请见谅。 422

数据库主键选型指南:BIGINT vs VARCHAR

主键选型关乎数据库性能与架构演进。BIGINT(如雪花算法)在顺序写入、二级索引开销和分布式生成上优势显著,适合高并发核心链路;而传统 VARCHAR UUIDv4 因随机性导致频繁页分裂、存储膨胀,性能堪忧。UUIDv7 通过时间戳有序性实现高效追加写入,结合 BINARY(16) 存储可兼顾性能与安全,成为现代微服务新选择。关键在于:主键应稳定、无业务含义,优先选用趋势递增的紧凑类型,并根据场景合理采用双主键模式或 ULID 等替代方案。

小李同学的博客 306

【基于 WebSocket 的多用户网页五子棋】—— 数据管理模块

但行好事,莫问前程

qq_42996461的博客 229

自动化运维选型:四条技术路线的能力边界,以及它们为什么不能互相替代

自动化运维怎么选型?拆解配置管理、基础设施即代码、作业调度与场景化编排四条技术路线边界,分析账本归属与时间语义差异,给出四种架构组合与判断点,帮企业看清为何不能互相替代。

trainsignalcn的专栏 340

C++算法(七)

C++ stack算法题和一些客观题

2503_94479566的博客 374

不用再为文本搜索单独维护一套系统!全文检索深度解析

为了给商品、客服工单或者企业知识库增加一个搜索框,企业往往需要在业务数据库之外,再部署一套Elasticsearch。数据库保存商品、订单和用户等真实业务数据,搜索引擎保存另一份文本索引;两套系统之间,还需要通过CDC、消息队列或者同步程序持续传输数据。一个看似简单的搜索需求,最后可能变成两套集群、两份数据和一条必须保持稳定的数据链路。由此产生的问题并不少:数据库已经完成更新,搜索结果却可能尚未同步;业务查询同时涉及文本、库存、权限和订单状态时,应用需要在两个系统之间来回组合结果;

TiDB 社区干货传送门 290

IDEA 简介:从零认识 IntelliJ IDEA

IDEA 全称,是由 JetBrains 公司开发的一款主流 Java 集成开发环境(IDE)。它集代码编辑、编译、调试、测试、版本控制、构建管理等功能于一体,被大量 Java 开发者视为日常开发的首选工具。所谓 IDE(Integrated Development Environment,集成开发环境),就是把写代码所需的各类工具整合到同一个界面中。相比只用文本编辑器加命令行编译,IDE 能显著减少重复操作,让开发者把精力集中在业务逻辑上。

ztI10的博客 163

市场调查与统计分析专业大学期间考证怎么安排?

市场调查与统计分析专业的考证规划,适合从一份完整的调查报告倒推:能不能设计问卷、判断样本是否合理、清洗数据,再把分析结果转化为业务建议?围绕这条能力链安排证书,比单纯按“热门程度”报名更有针对性。结合2026年的学习安排,并为2027年的实习、升学和求职预留时间,大学期间可以重点考虑六类证书:全国计算机等级考试证书、大学英语四级或六级成绩报告单、CDA数据分析师、初级统计专业技术资格证书、微软办公软件国际认证中的Excel相关证书,以及软考数据库系统工程师资格证书。

cc572502653的博客 165
上一篇: 【n8n教程】:AI工作流的核心概念与实战应用
下一篇: 【RuoYi-SpringBoot3-Pro】: 三级等保安全配置
undsky_
博客等级 码龄20年 6粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

undsky_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值