npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

ruoyi-eggjs-mysql

v1.1.15

Published

Egg plugin for mysql

Downloads

644

Readme

ruoyi-eggjs-mysql

Egg plugin for mysql

基于 mysql2 的 Egg.js MySQL 插件,提供简单易用的数据库操作接口和连接池管理。

特性

  • ✅ 基于 mysql2 连接池,性能优异
  • ✅ 支持单实例和多实例配置
  • ✅ 提供简洁的 API 封装(select、insert、update、delete)
  • 可选的驼峰命名转换:支持将数据库字段从 snake_case 自动转换为 camelCase(v1.1.7+)
  • ✅ 内置事务支持,自动提交和回滚
  • ✅ 开发环境自动打印 SQL 执行时间
  • ✅ 错误信息包含执行的 SQL 语句
  • ✅ 原生 Promise/Async 支持

安装

$ npm i ruoyi-eggjs-mysql --save

支持的 egg 版本

| egg 3.x | egg 2.x | egg 1.x | | ------- | ------- | ------- | | 😁 | 😁 | ❌ |

开启插件

// {app_root}/config/plugin.js
exports.mysql = {
  enable: true,
  package: "ruoyi-eggjs-mysql",
};

配置

单实例

// {app_root}/config/config.default.js
config.mysql = {
  default: {
    port: 3306,
    charset: "utf8mb4",
    multipleStatements: true,  // 允许执行多条 SQL
    connectionLimit: 100,       // 连接池最大连接数
  },
  client: {
    host: "127.0.0.1",
    user: "root",
    password: "your_password",
    database: "your_database",
  },
};

多实例

// {app_root}/config/config.default.js
config.mysql = {
  default: {
    port: 3306,
    charset: "utf8mb4",
    multipleStatements: true,
    connectionLimit: 100,
  },
  clients: {
    // 主库
    db1: {
      host: "127.0.0.1",
      user: "root",
      password: "password1",
      database: "database1",
    },
    // 从库
    db2: {
      host: "192.168.1.100",
      user: "root",
      password: "password2",
      database: "database2",
    },
  },
};

配置参数说明

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | host | String | - | MySQL 服务器地址 | | port | Number | 3306 | MySQL 端口 | | user | String | - | 数据库用户名 | | password | String | - | 数据库密码 | | database | String | - | 数据库名称 | | charset | String | utf8mb4 | 字符集(推荐 utf8mb4 支持 emoji) | | connectionLimit | Number | 100 | 连接池最大连接数 | | multipleStatements | Boolean | true | 是否允许一次执行多条 SQL | | timezone | String | +08:00 | 时区设置,防止日期时间转换为 UTC(v1.1.14+) | | dateStrings | Boolean | true | 保持日期为字符串格式,不转换为 Date 对象(v1.1.14+) | | camelCase | Boolean | false | 是否自动将字段名转换为驼峰命名(v1.1.7+) |

更多配置选项请参考 mysql2 文档

驼峰命名配置(camelCase)

v1.1.7 开始,支持通过 camelCase 配置项控制是否自动转换字段名:

// {app_root}/config/config.default.js
config.mysql = {
  default: {
    port: 3306,
    charset: "utf8mb4",
    multipleStatements: true,
    connectionLimit: 100,
  },
  // 开启驼峰命名转换
  camelCase: true,  // 将 user_name 转换为 userName
  client: {
    host: "127.0.0.1",
    user: "root",
    password: "your_password",
    database: "your_database",
  },
};

启用后的效果

// camelCase: false (默认)
const user = await app.mysql.select('SELECT user_id, user_name FROM users WHERE id = 1');
console.log(user);
// 返回: { user_id: 1, user_name: '张三' }

// camelCase: true (启用驼峰转换)
const user = await app.mysql.select('SELECT user_id, user_name FROM users WHERE id = 1');
console.log(user);
// 返回: { userId: 1, userName: '张三' }

使用方法

单实例

// 在 controller 或 service 中使用
const { app } = this;

// 单条查询
const user = await app.mysql.select('SELECT * FROM users WHERE id = 1');

// 多条查询
const users = await app.mysql.selects('SELECT * FROM users WHERE age > 18');

// 插入数据(返回新插入行的 ID)
const insertId = await app.mysql.insert("INSERT INTO users (name, age) VALUES ('张三', 25)");

// 更新数据(返回影响的行数)
const affectedRows = await app.mysql.update("UPDATE users SET age = 26 WHERE id = 1");

// 删除数据(返回影响的行数)
const deleted = await app.mysql.del("DELETE FROM users WHERE id = 1");

// 执行任意 SQL
await app.mysql.run("CREATE TABLE IF NOT EXISTS users (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255))");

多实例

// 获取指定数据库实例
const db1 = app.mysql.get('db1');
const db2 = app.mysql.get('db2');

// 从不同数据库查询
const user = await db1.select('SELECT * FROM users WHERE id = 1');
const order = await db2.select('SELECT * FROM orders WHERE id = 1');

API 说明

🎯 驼峰命名转换(可选)

新特性:从 v1.1.7 开始,支持通过配置启用驼峰命名转换。启用后,selectselects 方法会自动将数据库返回的字段名从下划线命名(snake_case)转换为驼峰命名(camelCase),让前端开发更加便捷。

⚙️ 启用方法:在配置文件中设置 camelCase: true

// {app_root}/config/config.default.js
config.mysql = {
  default: {
    port: 3306,
    charset: "utf8mb4",
  },
  camelCase: true,  // 启用驼峰命名转换
  client: {
    host: "127.0.0.1",
    user: "root",
    password: "your_password",
    database: "your_database",
  },
};

📝 使用示例

// 数据库表结构
// CREATE TABLE users (
//   user_id INT PRIMARY KEY,
//   user_name VARCHAR(255),
//   created_at DATETIME,
//   is_active TINYINT
// );

// 启用 camelCase: true 后,查询结果会自动转换字段名
const user = await app.mysql.select('SELECT * FROM users WHERE user_id = 1');
console.log(user);
// 返回: { 
//   userId: 1, 
//   userName: '张三', 
//   createdAt: '2024-01-01 12:00:00',
//   isActive: 1
// }

// 多条查询同样适用
const users = await app.mysql.selects('SELECT user_id, user_name FROM users');
// 返回: [
//   { userId: 1, userName: '张三' },
//   { userId: 2, userName: '李四' }
// ]

🔄 转换规则

  • user_iduserId
  • user_nameuserName
  • created_atcreatedAt
  • is_activeisActive

注意:默认情况下 camelCase: false,字段名保持原样,以确保向后兼容。

select(sql)

执行单条查询,返回第一行数据。如果启用了 camelCase: true,字段名会自动转换为驼峰命名。

const user = await app.mysql.select('SELECT * FROM users WHERE id = 1');
// camelCase: false 时返回: { id: 1, name: '张三', age: 25 } 或 null
// camelCase: true 时返回: { id: 1, name: '张三', age: 25 } 或 null

selects(sql)

执行多条查询,返回所有匹配的行。如果启用了 camelCase: true,字段名会自动转换为驼峰命名。

const users = await app.mysql.selects('SELECT * FROM users WHERE age > 18');
// camelCase: false 时返回: [{ id: 1, name: '张三', age: 25 }, { id: 2, name: '李四', age: 30 }]
// camelCase: true 时返回: [{ id: 1, name: '张三', age: 25 }, { id: 2, name: '李四', age: 30 }]

insert(sql)

执行插入操作,返回新插入行的 insertId

const insertId = await app.mysql.insert("INSERT INTO users (name, age) VALUES ('王五', 28)");
// 返回: 3 (新插入行的自增 ID)

update(sql)

执行更新操作,返回受影响的行数。

const affectedRows = await app.mysql.update("UPDATE users SET age = 26 WHERE id = 1");
// 返回: 1 (受影响的行数)

del(sql)

执行删除操作,返回受影响的行数(实际是 update 的别名)。

const deleted = await app.mysql.del("DELETE FROM users WHERE age < 18");
// 返回: 2 (删除的行数)

run(sql)

执行任意 SQL 语句,返回完整的执行结果。

const [results, fields] = await app.mysql.run("SHOW TABLES");
// results: 查询结果数组
// fields: 字段信息数组

transaction(sqls)

执行事务,传入 SQL 数组,全部成功则自动提交,任一失败则自动回滚。

const results = await app.mysql.transaction([
  "INSERT INTO users (name, age) VALUES ('张三', 25)",
  "INSERT INTO users (name, age) VALUES ('李四', 30)",
  "UPDATE accounts SET balance = balance - 100 WHERE user_id = 1",
  "UPDATE accounts SET balance = balance + 100 WHERE user_id = 2",
]);
// 返回: 所有 SQL 的执行结果数组

如果事务中任何一条 SQL 执行失败,所有更改会自动回滚:

try {
  await app.mysql.transaction([
    "INSERT INTO users (name, age) VALUES ('张三', 25)",
    "INSERT INTO invalid_table (name) VALUES ('test')", // 这条会失败
  ]);
} catch (error) {
  console.log(error.sqls); // 包含所有执行的 SQL
  // 第一条插入会被自动回滚
}

pool

获取原始的 mysql2 连接池对象,用于高级操作。

const pool = app.mysql.pool;
const [rows, fields] = await pool.query('SELECT * FROM users WHERE id = ?', [1]);

开发调试

在非生产环境下,插件会自动在控制台打印每条 SQL 的执行时间:

SELECT * FROM users WHERE id = 1: 1.234ms
INSERT INTO users (name, age) VALUES ('张三', 25): 2.567ms

完整示例

Service 层使用

// app/service/user.js
const { Service } = require('egg');

class UserService extends Service {
  async create(name, age) {
    const insertId = await this.app.mysql.insert(
      `INSERT INTO users (name, age, created_at) VALUES ('${name}', ${age}, NOW())`
    );
    return insertId;
  }

  async findById(id) {
    return await this.app.mysql.select(
      `SELECT * FROM users WHERE id = ${id}`
    );
  }

  async findAll() {
    return await this.app.mysql.selects('SELECT * FROM users ORDER BY id DESC');
  }

  async update(id, data) {
    const affectedRows = await this.app.mysql.update(
      `UPDATE users SET name = '${data.name}', age = ${data.age} WHERE id = ${id}`
    );
    return affectedRows > 0;
  }

  async delete(id) {
    const deleted = await this.app.mysql.del(`DELETE FROM users WHERE id = ${id}`);
    return deleted > 0;
  }

  // 转账示例(事务)
  async transfer(fromUserId, toUserId, amount) {
    return await this.app.mysql.transaction([
      `UPDATE accounts SET balance = balance - ${amount} WHERE user_id = ${fromUserId}`,
      `UPDATE accounts SET balance = balance + ${amount} WHERE user_id = ${toUserId}`,
      `INSERT INTO transactions (from_user, to_user, amount, created_at) 
       VALUES (${fromUserId}, ${toUserId}, ${amount}, NOW())`,
    ]);
  }
}

module.exports = UserService;

使用参数化查询(推荐)

为了防止 SQL 注入,推荐使用参数化查询:

// 使用 pool 进行参数化查询
const pool = app.mysql.pool;

// 查询
const [users] = await pool.query('SELECT * FROM users WHERE age > ?', [18]);

// 插入
const [result] = await pool.query(
  'INSERT INTO users (name, age) VALUES (?, ?)',
  ['张三', 25]
);
const insertId = result.insertId;

// 更新
const [updateResult] = await pool.query(
  'UPDATE users SET age = ? WHERE id = ?',
  [26, 1]
);
const affectedRows = updateResult.affectedRows;

多数据库操作

// app/service/sync.js
class SyncService extends Service {
  async syncUserData(userId) {
    const db1 = this.app.mysql.get('db1'); // 主库
    const db2 = this.app.mysql.get('db2'); // 从库

    // 从主库读取用户数据
    const user = await db1.select(`SELECT * FROM users WHERE id = ${userId}`);

    if (user) {
      // 同步到从库
      await db2.insert(
        `INSERT INTO users (id, name, age) VALUES (${user.id}, '${user.name}', ${user.age})
         ON DUPLICATE KEY UPDATE name = '${user.name}', age = ${user.age}`
      );
    }

    return user;
  }
}

注意事项

  1. SQL 注入防护:示例中为了简洁使用了字符串拼接,生产环境强烈建议使用参数化查询(通过 pool.query() 并传入参数数组)

  2. 连接池管理:插件自动管理连接池,无需手动释放连接(除非使用 transaction 或直接操作 pool

  3. 字符集设置:推荐使用 utf8mb4 字符集以支持 emoji 等特殊字符

  4. 时区问题(重要):

    问题描述:MySQL2 默认会将 DATETIME 字段转换为 UTC 时间,导致日期时间显示不正确。

    // 数据库存储:2025-11-24 12:23:47 (本地时间 UTC+8)
    // 查询结果:  2025-11-24T04:23:47.000Z (UTC+0,相差 8 小时)

    解决方案:从 v1.1.14 开始,默认配置已包含时区设置:

    // {app_root}/config/config.default.js
    config.mysql = {
      default: {
        port: 3306,
        charset: "utf8mb4",
        timezone: '+08:00',    // 设置时区为 UTC+8
        dateStrings: true,     // 保持日期为字符串格式
      },
      client: {
        host: "127.0.0.1",
        user: "root",
        password: "your_password",
        database: "your_database",
      },
    };

    配置选项说明

    • timezone: '+08:00':指定时区为 UTC+8(中国标准时间)
    • timezone: 'local':使用系统本地时区
    • dateStrings: true:将日期保持为字符串格式(推荐),不转换为 Date 对象
    • dateStrings: false:转换为 JavaScript Date 对象

    效果对比

    // 配置 timezone: '+08:00', dateStrings: true
    const user = await app.mysql.select('SELECT create_time FROM users WHERE id = 1');
    console.log(user.create_time);
    // 输出: "2025-11-24 12:23:47" ✅ 正确
       
    // 未配置时区
    const user = await app.mysql.select('SELECT create_time FROM users WHERE id = 1');
    console.log(user.create_time);
    // 输出: "2025-11-24T04:23:47.000Z" ❌ 错误(相差 8 小时)
  5. 事务使用:事务会占用一个独立连接直到提交或回滚,注意连接池大小设置

  6. 错误处理:所有方法都会抛出异常,建议使用 try-catch 捕获

try {
  await app.mysql.insert("INSERT INTO users (name) VALUES ('test')");
} catch (error) {
  console.error('执行失败的 SQL:', error.sql);
  console.error('错误信息:', error.message);
}

性能优化建议

  1. 合理设置连接池大小:根据并发量调整 connectionLimit
  2. 使用索引:确保查询字段有适当的索引
  3. **避免 SELECT ***:明确指定需要的字段
  4. 批量操作:使用事务进行批量插入/更新
  5. 读写分离:使用多实例配置实现主从分离

相关链接


关于 ruoyi-eggjs 项目

本插件是 ruoyi-eggjs 项目的核心组件之一。

ruoyi-eggjs 是一个基于 Egg.js 的企业级后台管理系统,参照若依(RuoYi)架构设计,提供完善的权限管理、用户管理、系统监控等功能,是快速开发企业级应用的最佳选择。

主要特性

  • 🎯 完整的权限系统:基于 RBAC 的权限控制,支持细粒度权限管理
  • 🚀 开箱即用:集成常用功能模块,快速启动项目开发
  • 🔧 MyBatis 风格:采用 XML 风格的 SQL 编写,熟悉的开发体验
  • 📦 模块化设计:松耦合的插件体系,按需使用
  • 🛡️ 企业级安全:XSS 防护、SQL 注入防护、访问控制等
  • 📊 系统监控:在线用户、登录日志、操作日志、定时任务等

项目地址

相关插件

联系方式

贡献指南

欢迎提交 Issue 和 Pull Request!

如果这个项目对你有帮助,请给我们一个 ⭐️ Star 支持一下!


License

MIT