sequelize在koa中的使用

这篇文章主要是记录在项目过程中使用sequelize对数据库进行操作的感受和经验


一、sequelize

Sequelize 是一个基于 promise 的 Node.js ORM 工具, 目前支持 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server, Amazon Redshift 和 Snowflake’s Data Cloud. 它具有强大的事务支持, 关联关系, 预读和延迟加载,读取复制等功能。
sequelize将sql查询语句分装成一个个方法调用,使用起来非常便捷。

二、sequelize连接Mysql

安装

npm install sequelize
yarn add sequelize

实例化,seq连接MySQL数据库

const Seq = require('sequelize')

// 实例化seq对象
// 参数依次为:要导入的数据库名,账号,密码
const seq = new Seq(
  SQLConfig.database.DATABASE, // 数据库名称
  SQLConfig.database.USERNAME, // 账号
  SQLConfig.database.PASSWORD, // 密码
  {
    host: SQLConfig.database.HOST,
    dialect: 'mysql',
    define: { // 模型定义的默认选项
      timestamps: false,
    },
    pool: { // 连接池属性
      max: 5,
      min: 0,
      idle: 30000
    }
  }
)

三、sequelize的使用

sequelize在使用的基本步骤
1.安装sequelize
2. 构建需要的数据库
3. 创建连接数据库的seq实例
4. 按照seq构建模型的方式,将数据库的表都映射成一个个seq模型
5. 将模型导出,使用模型实例的方法来对数据进行增删查改的操作。

模型构建

// 引入构建好的seq实例,将模型挂载在上面
import seq from "../config/sequelizeBase" 
const Sequelize = require('sequelize')

//使用define的方法定义模型
const bookingModel = seq.define(
  'booking', // 模型名称,seq会在别名的基础上识别真实表名,一般是添加上‘s’,即此处seq会识别此模型对于的表名为'bookings'
  { // 分别描述表里每一列的数据特性
    id: {
      type: Sequelize.INTEGER(10), // 数据类型
      primaryKey: true, // 是否为主键
      allowNull: false, // 是否允许为null,默认为true
      autoIncrement: true // 字段是否自增
    },
    Uid: {
      type: Sequelize.STRING(11),
      allowNull: false
    },
    Hid: {
      type: Sequelize.INTEGER(11),
      allowNull: false
    },
    viewDate: {
      type: Sequelize.TEXT
    },
    deleted: {
      type: Sequelize.INTEGER
    },
    createTime: {
      type: Sequelize.BIGINT
    }
  }
)
export default bookingModel

注意事项

  1. 默认情况下, 构建模型时只提供模型名称,Sequelize 会自动将模型名复数并将其用作表名. 想要强制表名称和模型名称相等则需要设置freezeTableName: true 参数停止 Sequelize 执行自动复数化.
sequelize.define('booking', {
  // ... (属性)
}, {
  freezeTableName: true
});

也可以直接提供表名

sequelize.define('booking', {
  // ... (属性)
}, {
  tableName: 'Employees'
});
  1. 字段类型需要和数据库中列的类型保持一致。
  2. seq没有设置外键的选项,表与表之间的联系需要通过表关联相关方法进行设置

sequelize的数据类型

DataTypes.STRING             // VARCHAR(255)
DataTypes.STRING(1234)       // VARCHAR(1234)
DataTypes.STRING.BINARY      // VARCHAR BINARY
DataTypes.TEXT               // TEXT
DataTypes.TEXT('tiny')       // TINYTEXT
DataTypes.INTEGER            // INTEGER

DataTypes.BOOLEAN            // TINYINT(1)
DataTypes.INTEGER            // INT
DataTypes.BIGINT             // BIGINT
DataTypes.BIGINT(11)         // BIGINT(11)

DataTypes.FLOAT              // FLOAT
DataTypes.FLOAT(11)          // FLOAT(11)
DataTypes.FLOAT(11, 10)      // FLOAT(11,10)

DataTypes.DATE       // DATETIME 适用于 mysql / sqlite, 带时区的TIMESTAMP 适用于 postgres
DataTypes.DATE(6)    // DATETIME(6) 适用于 mysql 5.6.4+. 支持6位精度的小数秒
DataTypes.DATEONLY   // 不带时间的 DATE

如果数据库中表与模型不一致,想要以模型为主可以可以通过调用一个异步函数(返回一个Promise)model.sync(options)来实现模型同步
这个过程只改变数据库端的表

插入、更新、删除

const result = await bookingModel.create({...request}) // 向bookings表中插入一条数据
await bookingModel.update({ viewDate: "2022-06-01" }, {
  where: {
    Uid:'159'
  }
}); // 更新bookings表里Uid为159行viewDate列的数据
await bookingModel.destroy({
  where: {
    Uid:'159'
  }
}); // 删除bookings表里Uid为159行数据记录

// 使用模型实例来对数据进行删除或者更新
result.viewDate = "2022-06-01" // result为上文插入数据的返回实例,只指向一行数据
await result.save() // 便可更新result实例的viewDate字段
await result.destroy() // 删除result对应的行数据

查询

// 查询表booking中一个匹配项,有则获得一个数据实例无则返回null
const result = await bookingModel.findOne({
          where: {// 查询条件
            id: request.id
          }attributes: ['id', 'Uid', 'blockName', 'doorNumber'] // 指定需要获取的数据列,不设置则为全字段获取
        })
// 查询表booking中所以匹配项,有则获得一个数据实例数组无则返回[]      
const result = await bookingModel.findAll({
            where: {
              viewDate: {
                [Op.like]: `${request.viewDate}%`
              },
              Uid,
              deleted:0
            },
            attributes: ['viewDate', 
            // 使用sequelize.fn进行数据聚合
            [sequelize.fn('COUNT', sequelize.col('viewDate')), 'count']
            ],
            group: 'viewDate' // 以字段‘viewDate’进行聚合查询
          })

Op

OpSequelize 提供的数据查询运算符

 	[Op.and]: [{ a: 5 }, { b: 6 }],            // (a = 5) AND (b = 6)
    [Op.or]: [{ a: 5 }, { b: 6 }],             // (a = 5) OR (b = 6)
      // 基本
      [Op.eq]: 3,                              // = 3
      [Op.ne]: 20,                             // != 20
      [Op.is]: null,                           // IS NULL
      [Op.not]: true,                          // IS NOT TRUE
      [Op.or]: [5, 6],                         // (someAttribute = 5) OR (someAttribute = 6)
      // 数字比较
      [Op.gt]: 6,                              // > 6
      [Op.gte]: 6,                             // >= 6
      [Op.lt]: 10,                             // < 10
      [Op.lte]: 10,                            // <= 10
      [Op.between]: [6, 10],                   // BETWEEN 6 AND 10
      [Op.notBetween]: [11, 15],               // NOT BETWEEN 11 AND 15
      
      [Op.in]: [1, 2],                         // IN [1, 2]
      [Op.notIn]: [1, 2],                      // NOT IN [1, 2]

      [Op.like]: '%hat',                       // LIKE '%hat'
      [Op.notLike]: '%hat',                    // NOT LIKE '%hat'

高级查询

where条件动态组合

下面将通过两个例子来展示如何使用变量动态生成where查询条件
场景1:多条件搜索查询,根据用户传来的查询条件参数不同设置不同的查询条件

知识点:findAndCountAll方法返回的数据结构为

  • count : 一个整数 - 与查询匹配的记录总数
  • rows : 一个数组对象 - 获得的记录
 // 将查询条件转存
      let where = {}
 // 根据不同的查询场景,动态生成查询条件
      if (request.keyword) {
        request.keyword && (searchController.keyword = request.keyword)
 // 将查询条件看做对象进行赋值设置
        where[Op.or] = [
          {
            address: {
              [Op.like]: `%${searchController.keyword}%`
            }
          },
          {
            blockName: {
              [Op.like]: `%${searchController.keyword}%`
            }
          }
        ]
      }
      if (request.district) {
        where["district"] = request.district
      }
      if (request.price) {
        const price = request.price.split('-')
        where["price"] = {
          [Op.between]: price
        }
      }
      if (request.houseType) {
        where['houseType'] = {
          [Op.like]: `${request.houseType}%`
        }
      }
      if (request.rentalType) {
        where['rentalType'] = request.rentalType
      }
      where['state'] = 0
      where['deleted'] = 0
  // 分页查询
     const result = await houseModel.findAndCountAll({
          where,
          limit: request.limit || 10,
          offset: request.offset,
        })

场景2:查询房东所有房源的预约信息列表
解决思路:先获取房东拥有的房源id集,将其作为作为某一查询条件的数据集进行查询获取

// 查询房东拥有的房源数据
  const house = await houseModel.findAll({
      where: {
        Uid
      }
    })
    let list: Object[] = []
    if (house.length) {
      // 将查询结果转换成普通对象数组,便于作为查询条件
      house.map((val: any) => {
        let array = { Hid: 0 }
        array.Hid = val.id
        list.push(array)
      }, list)

    }
    // 不可以直接将查询结果作为查询条件列表,必须是普通对象数组
          if (list.length) {
            // 根据房源id获取相应由预约的日期
            const bookingRecord: DataList<any> = await bookingModel.findAll({
              where: {
                [Op.or]: list,
                deleted: 0,
                bookingWay: 1,
                viewDate: {
                  [Op.like]: `${request.viewDate}%`
                },
              }
            })
          }

order

根据某一字段对查询数据进行排序,使用如下:

order: seq.literal('updateTime DESC')

表关联

Sequelize 提供了 四种 关联类型,并将它们组合起来以创建关联:

  • HasOne 一对一 ,关联关系(外键)存在于目标模型中。
  • BelongsTo 一对一,关联关系(外键)存在于源模型中。
  • HasMany 一对多,关联关系(外键)存在于目标模型中。
  • BelongsToMany 多对多
    下面以两个例子来说明关联的建立
// bookingModle为源模型,houseModel为目标模型
// 一个源模型外键对应于一个目标模型中的数据
bookingModel.belongsTo(houseModel, {
  as: 'houseBooking', // 联合表名
  foreignKey: 'Hid', // 源模型的外键字段
  targetKey: 'id', // 对应于目标模型中的字段
})
// 一个用户数据可以有多条评论数据
userModel.hasMany(commentModel, {
  as: "user",
  foreignKey: 'Uid', // 目标模型中的外键
  targetKey: 'UId', // 对应于源模型中的字段
})

联合查询

以获取预定信息时,同时获取预定房源的相关信息的联合查询为例,展示sequelize联合查询的使用。

// 用户查看预约事宜
          const bookingRecord: DataList<any> = await bookingModel.findAndCountAll({
            where: {
              Uid,
              deleted: 0,
              bookingWay: 1,
              viewDate: request.viewDate
            },
            attributes: ['viewTime', 'Hid', 'Uid', 'id'],
            offset: request.offset,
            limit: request.limit || 10,
            // 联合查询
            include: [
              {
              	// 关系别名,具有唯一性
                association: 'houseBooking',
                // 获取目标模型的那些字段
                attributes: ['blockName', 'Uid']
              }]
          })

注意:设置了关联外键的表的数据列不可以随意删除,会产生错误。

事务查询

sequelize的事务概念与数据库的事务管理一致,主要是为了保证操作过程中数据修改的一致性,避免在数据更改中应错误而导致数据不一致问题。在一个事务中,只用当所有的数据库操作都正常执行成功后,才会结束。如果中途出现错误,则会撤销前面的操作回滚至初识状态。具体使用如下:

// 托管事务会自动处理提交或回滚事务
await seq.transaction(async () => {
          const UId = verify(ctx)
          const result = await bookingModel.findOne({
            where: {
              id: request.id
            }
          })
          const now = new Date().getTime()
          // 在约定的时间一天前 取消预约扣除信誉分2
          if (now - result.updateTime < 24 * 60 * 1000) {
            const update = await userModel.findOne({
              where: {
                UId
              }
            })
          // 给房东发送消息
          await bookingController.setMessage(result, 0)
          result.deleted = 1
          result.save()
        })
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现隶属于美国甲骨文公司(Oracle)。自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用程序、企业级解决方案以及其他各种数据处理场景的首选数据库平台之一。 以下是对MySQL数据库的详细介绍: 核心特性与优势 开源与跨平台 MySQL遵循GPL开源协议,这意味着任何人都可以免费下载、使用和修改其源代码。这种开放性促进了广泛的社区支持和第三方插件、工具的发展。此外,MySQL支持多种操作系统,包括Windows、Linux、macOS、Solaris等,确保了其在不同环境下的兼容性和部署灵活性。 关系型模型与SQL支持 MySQL基于关系型数据库模型,数据以表格形式组织,并通过预定义的键(如主键、外键)在表之间建立关联。它完全支持结构化查询语言(SQL),允许用户进行数据查询、插入、更新、删除、创建和管理数据库结构等操作。SQL标准的广泛支持使得MySQL易于学习,且与其他关系型数据库系统有良好的互操作性。 存储引擎 MySQL支持多种存储引擎,如InnoDB、MyISAM、MEMORY等,每种引擎都有特定的优势和适用场景。例如,InnoDB提供事务安全、行级锁定和外键约束,适合处理高并发事务性的应用;MyISAM则更侧重于读取密集型操作,提供全文索引支持,适用于读多写少的场景。这种多引擎架构使得MySQL能够适应不同业务需求,提供高度定制化的存储解决方案。 性能与可扩展性 MySQL通过高效的缓存机制、查询优化器以及对硬件资源的有效利用,保证了在高负载情况下的稳定性和快速响应。它支持水平扩展(如通过分片、复制等技术)和垂直扩展(如增加硬件资源),以应对大规模数据存储和高并发访问的需求。 安全性与管理工具 MySQL提供了一系列安全措施,如用户账户管理、访问权限控制、SSL/TLS加密连接、审计日志等功能,确保数据的安全性和合规性。同时,MySQL附带了一系列管理工具,如MySQL Server、MySQL Workbench、MySQL Shell等,便于用户进行数据库配置、监控、备份、恢复、迁移等工作。 社区与生态系统 MySQL拥有庞大的开发者社区和丰富的第三方插件、库、间件支持,提供了丰富的文档、教程、论坛以及专业服务,极大地简化了开发、运维和故障排查过程。 关键组件与日志 系统数据库 MySQL内部包含几个特殊的系统数据库,如: information_schema:提供关于所有数据库、表、列、索引等元数据信息,是查询数据库结构的标准接口。 mysql:存储MySQL自身的系统信息,如用户权限、服务器配置、事件调度等。 performance_schema:自MySQL 5.5版本引入,用于收集服务器性能数据,帮助诊断和优化系统性能。 test(非必要):默认提供的测试数据库,通常用于学习和实验,生产环境可考虑删除。 sys(自MySQL 5.7版本):提供更易用的视图来访问performance_schema的信息,简化性能分析工作。 日志文件 MySQL通过日志记录来保证数据一致性、支持故障恢复和审计需求,主要包括: 错误日志(Error Log):记录MySQL服务器运行期间的严重错误、警告和其他重要事件。 二进制日志(Binary Log,binlog):记录对数据库进行数据更改(如INSERT、UPDATE、DELETE)的操作序列,用于数据复制和恢复。 查询日志(query log):可选地记录所有发送到MySQL服务器的SQL查询,用于调试和审计。 慢查询日志(slow query log):记录执行时间超过指定阈值的查询,帮助识别和优化性能瓶颈。 应用场景 MySQL广泛应用于各种规模和类型的项目,包括但不限于: Web应用程序:作为众多网站和Web服务(如电子商务、社交媒体、内容管理系统等)的后台数据库。 数据分析与报表:与数据仓库技术结合,支持OLAP(在线分析处理)和数据可视化。 移动应用与物联网(IoT):作为数据存储层,支撑大量设备的数据采集、存储和查询需求。 嵌入式系统:在资源有限的环境,作为轻量级数据库解决方案。 总之,MySQL凭借其开源、跨平台、高性能、灵活扩展、丰富功能集和庞大社区支持等特点,成为现代数据管理领域不可或缺的一部分,适用于各种行业和业务场景的数据库需求。
Koa2是一个基于Node.js的Web开发框架,它使用了ES6的语法特性,提供了一种更简洁、更优雅的方式来构建Web应用程序。Sequelize是一个强大的Node.js ORM(Object-Relational Mapping)库,它提供了对多种数据库的支持,包括SQLite、MySQL、PostgreSQL等。SQLite是一种轻量级的嵌入式数据库引擎,它不需要独立的服务器进程,可以直接嵌入到应用程序使用Koa2结合Sequelize和SQLite可以实现一个简单的Web应用程序。首先,你需要安装koa2、sequelize和sqlite3这三个npm包。然后,你可以创建一个Koa2应用程序,并配置Sequelize连接到SQLite数据库。接下来,你可以定义模型(Model)来映射数据库表,并使用Sequelize提供的API进行数据的增删改查操作。 下面是一个简单的示例代码: ```javascript const Koa = require('koa'); const Sequelize = require('sequelize'); const app = new Koa(); // 配置Sequelize连接到SQLite数据库 const sequelize = new Sequelize({ dialect: 'sqlite', storage: 'path/to/database.sqlite' // SQLite数据库文件路径 }); // 定义模型 const User = sequelize.define('user', { name: Sequelize.STRING, age: Sequelize.INTEGER }); // 同步模型到数据库 sequelize.sync().then(() => { console.log('Database synced'); }).catch((error) => { console.error('Error syncing database:', error); }); // 在路由使用模型进行数据操作 app.use(async (ctx) => { // 创建用户 const user = await User.create({ name: 'John', age: 25 }); // 查询用户 const users = await User.findAll(); // 更新用户 user.age = 26; await user.save(); // 删除用户 await user.destroy(); ctx.body = users; }); app.listen(3000, () => { console.log('Server started on port 3000'); }); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值