Node.js开发笔记——Sequelize(ORM库)

Node.js开发笔记——Sequelize(ORM库)

在 Node.js 项目中可以使用Sequelize这个ORM(对象关系映射)库来将项目中的 Model 和数据库表进行映射以及可以让我们可以使用 JavaScript 的对象和方法来操作数据库(CRUD),而不必编写原生 SQL 语句。

安装

安装 Sequelize

bash
1
npm install -S sequelize

安装对应数据库驱动

bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 安装MySQL驱动
npm install -S mysql2

# 安装PostgreSQL驱动
npm install -S pg pg-hstore

# 安装SQLite驱动
npm install -S sqlite3

# 安装MSSQL驱动
npm install -S tedious

# 安装MariaDB驱动
npm install -S mariadb

# 安装Oracle数据库驱动
npm install -S oracledb

使用

Sequelize提供的大多数方法都是异步的,会返回Promise,所以可以使用Promise API。

创建 Sequelize 实例

创建一个Sequelize实例并连接到数据库:

models/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const { Sequelize } = require("sequelize");

// 创建Sequelize实例,连接到MySQL数据库
const sequelize = new Sequelize("database_name", "username", "password", {
host: "localhost",
dialect: "mysql", // 选择数据库类型:'mysql' | 'postgres' | 'sqlite' | 'mssql'
});

// 测试连接是否成功
sequelize
.authenticate()
.then(() => {
console.log("Connection has been established successfully.");
})
.catch((err) => {
console.error("Unable to connect to the database:", err);
});

// 导出Sequelize实例变量
module.exports = sequelize;

定义模型(Model)

在 Sequelize 中,模型代表数据库中的表。
可以通过定义模型来映射数据库表及其字段。

models/user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const { DataTypes } = require("sequelize");
// 引入前面创建的 Sequelize 实例
const sequelize = require("./index");

// 定义User模型
const User = sequelize.define(
"User",
{
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
},
{
tableName: "users", // 自定义表名,如果不指定,Sequelize 会自动将模型名转换为复数形式作为表名
timestamps: true, // 自动添加 createdAt 和 updatedAt 字段
}
);

module.exports = User;

同步模型与数据库

在项目启动时同步模型和数据库。

在项目入口 js 文件中添加:

index.js
1
2
3
4
5
6
7
8
9
10
11
12
const sequelize = require("./models/index");
const User = require("./models/user");

// 同步模型
sequelize
.sync({ force: false }) // { force: true } 会先删除表然后重新创建(慎用)
.then(() => {
console.log("Database & tables created!");
})
.catch((err) => {
console.error("Failed to sync database:", err);
});

CRUD 操作

可以调用模型的 CRUD 方法操作数据库。

  • Create
js
1
2
3
4
5
6
7
8
9
10
11
User.create({
username: "john_doe",
password: "secret123",
email: "john@example.com",
})
.then((user) => {
console.log("User created:", user.toJSON());
})
.catch((err) => {
console.error("Failed to create user:", err);
});
  • Read
js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
User.findOne({ where: { username: "john_doe" } })
.then((user) => {
if (user) {
console.log("User found:", user.toJSON());
} else {
console.log("User not found");
}
})
.catch((err) => {
console.error("Failed to find user:", err);
});

User.findAll()
.then((users) => {
console.log("All users:", JSON.stringify(users, null, 2));
})
.catch((err) => {
console.error("Failed to find users:", err);
});
  • Update
js
1
2
3
4
5
6
7
User.update({ password: "newpassword123" }, { where: { username: "john_doe" } })
.then((rowsUpdated) => {
console.log("Number of rows updated:", rowsUpdated);
})
.catch((err) => {
console.error("Failed to update user:", err);
});
  • Delete
js
1
2
3
4
5
6
7
User.destroy({ where: { username: "john_doe" } })
.then((rowsDeleted) => {
console.log("Number of rows deleted:", rowsDeleted);
})
.catch((err) => {
console.error("Failed to delete user:", err);
});

记录日志

默认情况下,Sequelize将记录控制台执行的每个SQL查询。可以使用options.logging参数来自定义每次 Sequelize记录某些内容时将执行的函数。默认值为console.log,使用该值时仅显示日志函数调用的第一个参数。例如,对于查询日志记录,第一个参数是原始查询,第二个参数(默认情况下是隐藏的)是Sequelize对象。

js
1
2
3
4
5
6
7
8
const sequelize = new Sequelize('sqlite::memory:', {
// 选择一种日志记录参数
logging: console.log, // 默认值,显示日志函数调用的第一个参数
logging: (...msg) => console.log(msg), // 显示所有日志函数调用参数
logging: false, // 禁用日志记录
logging: msg => logger.debug(msg), // 使用自定义记录器(例如Winston 或 Bunyan),显示第一个参数
logging: logger.debug.bind(logger) // 使用自定义记录器的另一种方法,显示所有消息
});

关系映射

Sequelize 支持定义表之间的关系(一对一、一对多、多对多)。

定义UserPost之间为一对多的关系:

js
1
2
3
4
5
6
7
8
9
10
11
const Post = sequelize.define("Post", {
title: DataTypes.STRING,
content: DataTypes.TEXT,
});

// 一对多关系:一个用户可以有多个帖子
User.hasMany(Post);
Post.belongsTo(User);

// 在同步时,Sequelize 会自动设置外键
sequelize.sync();

查询生成器

Sequelize 支持复杂的查询构建与聚合操作,可以轻松实现分页、排序、分组等操作。

js
1
2
3
4
5
6
7
8
9
10
11
12
User.findAll({
where: { email: { [Op.like]: "%@example.com" } },
order: [["createdAt", "DESC"]],
limit: 10,
offset: 20,
})
.then((users) => {
console.log("Paged users:", JSON.stringify(users, null, 2));
})
.catch((err) => {
console.error("Failed to retrieve users:", err);
});

事务处理(Transactions)

通过sequelize.transaction()来管理事务,确保操作的原子性。

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
sequelize
.transaction(async (t) => {
const user = await User.create(
{
username: "jane_doe",
password: "password123",
email: "jane@example.com",
},
{ transaction: t }
);

await Post.create(
{
title: "Jane's first post",
content: "This is Jane's first post",
userId: user.id,
},
{ transaction: t }
);
})
.then(() => {
console.log("Transaction has been committed");
})
.catch((err) => {
console.error("Transaction has been rolled back:", err);
});

验证与钩子(Hooks)

Sequelize 提供内置的验证机制,并允许你定义生命周期钩子,在模型操作前后执行代码。

js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const User = sequelize.define(
"User",
{
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
len: [4, 20], // 验证用户名长度在 4 到 20 个字符之间
},
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
hooks: {
beforeCreate: (user) => {
// 在创建用户前对密码进行哈希处理
user.password = hashPassword(user.password);
},
},
}
);

配置与环境变量

可以通过环境变量或配置文件管理不同环境下的数据库连接配置:

js
1
2
3
4
5
6
7
8
9
const sequelize = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASSWORD,
{
host: process.env.DB_HOST,
dialect: "mysql",
}
);

迁移与种子数据

Sequelize CLI工具支持数据库迁移和种子数据管理。可以通过命令行生成和应用迁移来管理数据库的演进。

bash
1
2
3
npx sequelize-cli init
npx sequelize-cli model:generate --name User --attributes username:string,email:string
npx sequelize-cli db:migrate

参考

  1. https://www.sequelize.cn/

评论