Egg-Sequelize食用指南

news2024/9/25 9:35:23
引言

Sequelize 是一个基于 Node.js 的 ORM 库。Egg-Sequelize 是基于egg框架封装Sequelize的一个插件。有了它,我们就可以通过对象的形式操作数据库。


Egg-Sequelize 的用途和优势

Egg-Sequelize可以让我们方便地使用和操作数据库,其支持以下功能:

  1. 简化数据库操作:通过 ORM(对象关系映射),开发者无需编写复杂的 SQL 语句。
  2. 模型定义和管理:通过模型定义数据库表结构,并使用模型方法进行数据操作。
  3. 数据验证和关联:在模型中定义数据验证规则和表之间的关系,确保数据一致性和完整性。
  4. 事务管理:支持数据库事务,确保数据操作的原子性。

有了它我们通过简单的模型定义,可以快速进行 CRUD 操作。且数据模型和业务逻辑分离,代码更加清晰、易于维护。同时它还支持多种数据库(如 MySQL、PostgreSQL、SQLite),提高数据库迁移的便利性。


Egg-Sequelize 的基本使用方式
1. 安装和配置

首先,安装所需的包:

npm install --save egg-sequelize sequelize mysql2

config/plugin.js 中启用插件:

exports.sequelize = {
  enabletrue,
  package'egg-sequelize',
};

config/config.default.js 中配置数据库连接:

exports.sequelize = {
  dialect'mysql',
  host'localhost',
  port3306,
  database'test',
  username'root',
  password'yourpassword',
};
2. 定义模型

app/model 目录下定义模型文件,例如 user.js

module.exports = app => {
  const { STRING, INTEGER, DATE } = app.Sequelize;
  
  const User = app.model.define('user', {
    id: { type: INTEGER, primaryKeytrueautoIncrementtrue },
    name: STRING(30),
    age: INTEGER,
    created_at: DATE,
    updated_at: DATE,
  });

  return User;
};

这里主要声明表的结构以及字段的类型,Sequelize内置了多种字段类型

字符串类型

  • STRING:可变长度字符串,默认长度为 255。
  • STRING(length):指定长度的可变字符串,例如 STRING(100)。
  • TEXT:可变长度文本,不限制长度。
  • CHAR(length):定长字符串,例如 CHAR(10)。

数值类型

  • INTEGER:整数。
  • BIGINT:大整数。
  • FLOAT:浮点数。
  • REAL:双精度浮点数。
  • DOUBLE:双精度浮点数。
  • DECIMAL:高精度定点数。

日期时间类型

  • DATE:日期时间类型。
  • DATEONLY:仅日期类型,不包含时间部分。
  • TIME:仅时间类型,不包含日期部分。

布尔类型

  • BOOLEAN:布尔类型,true 或 false。

二进制类型

  • BLOB:二进制大对象。
3. 使用模型

在控制器中使用模型进行数据库操作,例如 app/controller/user.js

const Controller = require('egg').Controller;

class UserController extends Controller {
  async index() {
    const users = await this.ctx.model.User.findAll();
    this.ctx.body = users;
  }

  async create() {
    const { name, age } = this.ctx.request.body;
    const user = await this.ctx.model.User.create({ name, age });
    this.ctx.body = user;
  }
}

module.exports = UserController;

模型定义好后,我们就可以使用对象的api去调用数据库方法了。上面这里只是一个列子,实际应用中最好不要直接在controller里去做数据查询。

需要注意的是,sequelize会自动添加createdAt和updatedAt字段,如果不需要可以设置timestamps: false选项

const OperatorLog = app.model.define('OperatorLog', {
    ...
  }, {
    timestamps: false,
    tableName: 'tb_operator_log',
  });

复杂用法解析
1. 复杂查询

Sequelize 提供了丰富的查询选项,支持复杂的查询条件和关联查询。例如,查询年龄大于 30 的用户:

const users = await this.ctx.model.User.findAll({
  where: {
    age: {
      [Op.gt]: 30
    }
  }
});
2. 事务管理

在处理多个数据库操作时,事务管理可以确保数据的一致性和完整性。例如,在创建用户和关联数据时使用事务:

const transaction = await this.ctx.model.transaction();
try {
  const user = await this.ctx.model.User.create({ name, age }, { transaction });
  await this.ctx.model.Profile.create({ userId: user.id, bio }, { transaction });
  await transaction.commit();
catch (err) {
  await transaction.rollback();
  throw err;
}
3. 数据验证

Sequelize 提供了丰富的数据验证选项,可以在模型中定义。例如,验证用户名长度:

const User = app.model.define('user', {
  name: {
    type: STRING(30),
    validate: {
      len: [230]
    }
  }
});
4. 数据库迁移

通过 Sequelize 的迁移工具,可以方便地管理数据库的变更。例如,创建一个用户表的迁移文件:

npx sequelize migration:create --name create-user

在生成的迁移文件中定义变更:

module.exports = {
  upasync (queryInterface, Sequelize) => {
    await queryInterface.createTable('users', {
      id: {
        type: Sequelize.INTEGER,
        primaryKeytrue,
        autoIncrementtrue
      },
      name: {
        type: Sequelize.STRING
      },
      created_at: {
        type: Sequelize.DATE
      },
      updated_at: {
        type: Sequelize.DATE
      }
    });
  },
  downasync (queryInterface, Sequelize) => {
    await queryInterface.dropTable('users');
  }
};
5. 数据关联

定义模型之间的关系,例如用户和角色的多对多关系:

const User = app.model.define('user', {/*...*/});
const Role = app.model.define('role', {/*...*/});

User.belongsToMany(Role, { through'UserRole' });
Role.belongsToMany(User, { through'UserRole' });

在使用时进行关联查询:

const users = await this.ctx.model.User.findAll({
  include: [{
    modelthis.ctx.model.Role,
    through: {
      attributes: []
    }
  }]
});

注意事项总结

在实际项目中使用 Sequelize 时,开发者可能会遇到一些常见的坑和问题。了解这些坑并采取相应的措施可以帮助避免潜在的问题。以下是一些常见的坑:

1. 未处理事务错误

如果事务中发生错误,没有正确处理和回滚事务,会导致数据不一致。

解决方案:始终在事务中捕获错误并进行回滚。

const transaction = await sequelize.transaction();
try {
  // Your transactional operations
  await transaction.commit();
catch (error) {
  await transaction.rollback();
  throw error;
}

2. 未正确处理并发

在高并发场景下,可能会遇到数据竞争问题,导致数据不一致或丢失。

解决方案:使用锁(如行级锁)或乐观锁来处理并发问题。

const user = await User.findByPk(1, { locktrue, transaction });

3. N+1 查询问题

当进行关联查询时,容易导致大量的数据库查询,影响性能。

解决方案:使用 include 进行预加载,减少数据库查询次数。

const users = await User.findAll({
  include: [{ model: Profile }]
});

4. 错误的查询优化

没有充分利用数据库索引和优化查询,可能导致性能问题。

解决方案:使用 raw 查询进行复杂查询,并确保数据库索引的合理性。

const users = await sequelize.query('SELECT * FROM users WHERE age > ?', {
  replacements: [30],
  type: sequelize.QueryTypes.SELECT
});

5. 模型同步问题

在生产环境中直接使用 sync 方法同步模型,可能导致数据丢失。

解决方案:在开发环境中使用 sync,在生产环境中使用迁移工具管理数据库变更。

await sequelize.sync({ forcefalse });

6. 未处理数据库连接问题

未处理数据库连接的断开和重连问题,可能导致应用程序崩溃。

解决方案:使用连接池并处理连接事件。

const sequelize = new Sequelize('database''username''password', {
  host'localhost',
  dialect'mysql',
  pool: {
    max5,
    min0,
    acquire30000,
    idle10000
  }
});

sequelize.authenticate().catch(err => {
  console.error('Unable to connect to the database:', err);
});

7. 未处理时间戳问题

未正确处理时间戳格式,可能导致时区问题和数据不一致。

解决方案:使用统一的时间戳格式,并在数据库和应用层处理时区问题。

const User = sequelize.define('user', {
  createdAt: {
    type: Sequelize.DATE,
    defaultValue: Sequelize.NOW
  }
}, {
  timestampstrue,
  timezone'+00:00'
});

8. 错误的数据验证

在模型中未定义或错误定义数据验证规则,可能导致不符合预期的数据写入数据库。

解决方案:在模型中定义详细的验证规则。

const User = sequelize.define('user', {
  name: {
    type: Sequelize.STRING,
    allowNullfalse,
    validate: {
      len: [250]
    }
  },
  email: {
    type: Sequelize.STRING,
    allowNullfalse,
    validate: {
      isEmailtrue
    }
  }
});

9. 过度依赖自动生成的 SQL

过度依赖 Sequelize 自动生成的 SQL 语句,可能导致复杂查询性能低下。

解决方案:在必要时使用自定义查询来优化性能。

const users = await sequelize.query('SELECT * FROM users WHERE age > ?', {
  replacements: [30],
  type: sequelize.QueryTypes.SELECT
});

10. 缺乏适当的测试

缺乏对数据库操作的充分测试,可能导致隐藏的错误。

解决方案:编写单元测试和集成测试,确保数据库操作的正确性。

describe('User model', () => {
  it('should create a user'async () => {
    const user = await User.create({ name'John'age25 });
    expect(user.name).to.equal('John');
  });
});

通过了解和避免这些常见的坑,可以大大提高 Sequelize 在实际项目中的使用效果,确保应用程序的稳定性和性能。

结论

Egg-Sequelize 作为 Egg.js 和 Sequelize 的结合体,为开发者提供了强大的数据库操作能力。通过合理使用其基本功能和复杂用法,可以大大提高开发效率和代码质量。在实际项目中,注意性能优化、安全性和数据库设计等方面,可以更好地发挥 Egg-Sequelize 的优势,为项目保驾护航。

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2163178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu 20.04 内核升级后网络丢失问题的解决过程

在 Ubuntu 系统中,内核升级是一个常见的操作,旨在提升系统性能、安全性和兼容性。然而,有时这一操作可能会带来一些意外的副作用,比如导致网络功能的丧失。 本人本来是想更新 Nvidia 显卡的驱动,使用 ubuntu-drivers …

postman中使用Pre-request Script

一、get方法 get请求时 ,有多个params,并且有一个参数为sign,这个参数是有其他params拼接之后md5加密得到的,如何通过js语句获取params参数并生成sign。 const CryptoJS require(crypto-js); // 引入 CryptoJS 库进行 MD5 加密…

安卓数据存储——SQLite

一、SQLite数据库 创建表 CREATE TABLE IF NOT EXISTS user_info (_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,name VARCHAR NOT NULL,age INTEGER NOT NULL,height LONG NOT NULL,weight FLOAT NOT NULL);注: IF NOT EXISTS:如果该表不存在则创…

Docker更换阿里容器镜像源

以Mac为例, 一、获取阿里容器镜像加速器地址 访问阿里云官网https://cn.aliyun.com/ 登录阿里云,没有账号就注册一个 登录完成后在搜索框搜索,容器镜像服务,并打开 点击管理控制台,进入管理控制台 左侧点击镜像加速…

ubuntu重新安装clickhouse

1.卸载clickhouse 关闭原来的clickhouse sudo systemctl stop clickhouse-server 查看关闭clickhouse是否成功 sudo systemctl status clickhouse-server 备份配置文件 /etc/clickhouse-server/user.xml /etc/clickhouse-server/config.d/metrika.xml /etc/clickhouse…

蚂蚁Raft一致性算法库SOFAJRaft深入分析

大家好,我是 V 哥,SOFAJRaft 是蚂蚁金服开源的一个基于 Raft 共识算法的 Java 实现,它特别适合高负载、低延迟的分布式系统场景。SOFAJRaft 支持 Multi-Raft-Group,能够同时处理多个 Raft 集群,具有扩展性和强一致性保…

实验室ICPR 2024论文分享┆FPMT: 基于增强型半监督模型的交通事件检测(含详细视频解读)

目录 论文分享简介 1. 会议介绍 2. 研究背景及主要贡献 3. 方法 4. 实验 5. 结论 6. 论文介绍视频 论文分享简介 本推文详细介绍了一篇实验室的最新论文成果《FPMT: Enhanced Semi-Supervised Model for Traffic Incident Detection》,该论文已被第27届国际…

尚硅谷———-乐(智)尚代驾~~--------Day5----司机认证篇~

前言: Hello亲爱的uu们,在读过了一个愉快的周末后(摸鱼了一会),我又回来更新啦,感谢uu们的阅读,话不多说~ 司机认证 当司机点击开始接单的时候,会先判断该司机有没有通过认证&…

关于PCA的一份介绍

在这篇文章中,我将介绍机器学习中的一种无监督学习算法——PCA,因为它主要有两种用途,即降维与特征提取,所以我将将围绕这两种用途来介绍它,包括基本概念,应用与代码实践。 一、 PCA 1.1 概念 PCA&#…

dev containers plugins for vscode构建虚拟开发环境

0. 需求说明 自用笔记本构建一套开发环境,用docker 虚拟插件 dev containers,实现开发环境的构建,我想构建一套LLMs的环境,由于环境配置太多,不想污染本地环境,所以选择隔离技术 1. 环境准备 vscodedocker 2. 步骤…

任意长度并行前缀和 扫描算法 《PMPP》笔记

下面的算法针对于任意长度输入 对于大数据集,首先将输入分为几段,每一段放进共享内存并用一个线程块处理,比如一个线程块使用1024个线程的话,每个块最多能处理2048个元素。 在前面代码中,一个块最后的执行结果保存到了…

桥接模式和NET模式的区别

桥接模式和NET模式的区别 NAT模式: NAT:网络地址转换(模式):借助宿主机来上网,没桥接那么麻烦,只用配置DNS即可。 缺点:扎根于宿主机,不能和局域网内其它真实的主机进行…

用Python实现运筹学——Day 2: 线性规划的基本概念

一、学习内容 线性规划的定义: 线性规划(Linear Programming, LP)是一种用于求解约束条件下线性目标函数最优解的方法。线性规划问题通常涉及最大化或最小化一个线性目标函数,目标函数的变量受一组线性不等式或等式的约束。 目标…

C语言 | Leetcode C语言题解之第435题无重叠区间

题目: 题解: int cmp(int** a, int** b) {return (*a)[1] - (*b)[1]; }int eraseOverlapIntervals(int** intervals, int intervalsSize, int* intervalsColSize) {if (intervalsSize 0) {return 0;}qsort(intervals, intervalsSize, sizeof(int*), cm…

【React】Ant Design 5.x版本drawer抽屉黑边问题

环境 antd: ^5.14.1react: ^18 问题情况 <Drawer open{open} closable{false} mask{false} width{680}getContainer{props.getContainer || undefined}><p>Some contents...</p><p>Some contents...</p><p>Some contents...</p> …

[网络] 网络层--IP协议

目录 一、IP协议 1.1 基本概念 1.2 IP协议报头 1.3 如何将报头和有效载荷分离和分用 1.4 分片与组装 1.5 如何减少分片&#xff1f; 1.6 分片和封装的具体过程 二、网段划分 2.1 再次理解IP地址 2.2 了解DHCP 2.3 网络划分方案 2.4 为什么要进行网络划分 2.5 特殊的…

Java基础——字节流和字符流

字节流和字符流的用法几乎完全一样&#xff0c;区别在于字节流和字符流所操作的数据单元不同&#xff0c;字节流操作的单元是数据单元是8位的字节&#xff0c;字符流操作的是数据单元为16位的字符。 为什么要有字符流&#xff1f; Java中字符是采用Unicode标准&#xff0c;Un…

【Go语言】Go语言结构体全面解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

基于 Canvas 的可缩放拖动网格示例(Vue3以及TypeScript )

文章目录 1. 基本知识2. Vue33. TypeScript 1. 基本知识 基本知识讲解&#xff1a; Canvas API&#xff1a; 一种用于在网页上绘制图形的 HTML 元素&#xff0c;使用 JavaScript 的 Canvas API 来进行绘制 使用 getContext(2d) 方法获取 2D 绘图上下文&#xff0c;允许开发者绘…

MySQL数据库备份详解

文章目录 引言● 数据库备份的重要性 MySQL数据库备份的基础知识● 备份类型1、完全备份2、增量备份3、差异备份 ● 备份工具与方法1、逻辑备份工具——mysqldump2、物理备份工具——Xtrabackup3、第三方解决方案 MySQL数据库备份的实施步骤1、环境准备2、选择合适的备份工具与…