在 Express 中集成 MySQL 和 Knex 的完整指南,包含依赖安装、配置方法及 Knex 的详细使用示例:
一、安装依赖
npm install mysql2 knex dotenv
- mysql2: MySQL 驱动(支持 Promise)
- knex: SQL 查询构建器(支持事务、链式调用)
- dotenv: 环境变量管理(用于保护数据库配置)
二、配置 MySQL 连接
1. 创建 .env
文件
在项目根目录新建 .env
,配置数据库信息:
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=your_database
DB_PORT=3306
2. 创建 Knex 配置文件
新建 knexfile.js
:
require('dotenv').config();
module.exports = {
development: {
client: 'mysql2',
connection: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
port: process.env.DB_PORT
},
migrations: {
directory: './db/migrations' // 迁移文件目录
},
seeds: {
directory: './db/seeds' // 种子数据目录
}
}
};
3. 初始化 Knex 实例
新建 db.js
文件:
const knex = require('knex');
const config = require('../knexfile');
const db = knex(config.development);
module.exports = db;
三、Knex 核心使用方法
1. 数据表操作(迁移)
创建迁移文件(需安装 knex
全局命令行工具):
npx knex migrate:make create_users_table
编辑生成的迁移文件(如 db/migrations/202310010000_create_users_table.js
):
exports.up = function(knex) {
return knex.schema.createTable('users', (table) => {
table.increments('id').primary();
table.string('name').notNullable();
table.string('email').unique();
table.timestamps(true, true); // 自动生成 created_at 和 updated_at
});
};
exports.down = function(knex) {
return knex.schema.dropTable('users');
};
执行迁移:
npx knex migrate:latest
2. 增删改查(CRUD)
插入数据
const db = require('./db');
// 插入单条
await db('users').insert({
name: 'Alice',
email: 'alice@example.com'
});
// 批量插入
await db('users').insert([
{ name: 'Bob', email: 'bob@example.com' },
{ name: 'Charlie', email: 'charlie@example.com' }
]);
查询数据
// 查询所有用户
const users = await db('users').select('*');
// 条件查询(单个结果)
const user = await db('users')
.where({ id: 1 })
.first();
// 条件查询(多个结果)
const activeUsers = await db('users')
.where('status', 'active')
.select('id', 'name');
更新数据
await db('users')
.where({ id: 1 })
.update({
name: 'Alice Smith',
email: 'alice.smith@example.com'
});
删除数据
await db('users')
.where({ id: 2 })
.delete();
3. 复杂查询
单表多条件查询
const results = await db('users')
.where('age', '>', 18)
.andWhere('status', 'active')
.orWhere('email', 'like', '%@gmail.com')
.orderBy('created_at', 'desc');
分页查询
const page = 1;
const perPage = 10;
const paginatedData = await db('users')
.select('*')
.offset((page - 1) * perPage)
.limit(perPage)
.orderBy('id', 'asc');
聚合查询
const count = await db('users')
.count('id as total')
.where('status', 'active')
.first();
4. 多表联合查询
内连接(INNER JOIN)
const orders = await db('orders')
.join('users', 'orders.user_id', 'users.id')
.select(
'orders.id as order_id',
'users.name as user_name',
'orders.total_amount'
)
.where('users.status', 'active');
左连接(LEFT JOIN)
const products = await db('products')
.leftJoin('categories', 'products.category_id', 'categories.id')
.select(
'products.name',
'categories.name as category_name'
);
子查询
const topUsers = await db('users')
.whereIn('id', function() {
this.select('user_id')
.from('orders')
.groupBy('user_id')
.havingRaw('SUM(total_amount) > ?', [1000]);
});
5. 事务处理
try {
await db.transaction(async (trx) => {
// 扣减库存
await trx('products')
.where('id', 1)
.decrement('stock', 1);
// 创建订单
const [orderId] = await trx('orders')
.insert({
user_id: 1,
total_amount: 99.99
});
// 提交事务
return orderId;
});
} catch (error) {
console.error('Transaction failed:', error);
}
四、最佳实践
- 参数化查询
始终使用 Knex 的查询构建方法,避免手动拼接 SQL 防止注入。 - 环境分离
在knexfile.js
中配置不同环境(开发、测试、生产)。 - 连接池管理
在 Knex 配置中添加连接池参数:pool: { min: 2, max: 10 }
- 错误处理
使用try/catch
包裹数据库操作,捕获可能的异常。
五、总结
通过 Knex,Express 项目可以高效、安全地操作 MySQL 数据库。其链式 API 支持复杂的查询逻辑,同时保持代码可读性。结合迁移和种子功能,能够实现数据库版本控制和测试数据管理。对于需要更高性能的场景,可进一步探索 Knex 的流式查询(Streams)和原始 SQL 执行能力。
本文使用到的npx,在 npx 的详细说明 中进行了介绍。
在 NodeJS 的Express 中集成 MySQL 和 Knex 的完整指南(二)中记录了Knex怎么在已有表添加新字段以及添加多个新表的操作