第4章:ORM框架-Sequelize

ORM框架

OMR框架全程是Object Relational Mapping 对象-关系-映射。ORM框架就是将关系型数据库映射成面向对象模型,方便我们以操作对象的方式操作数据库。

ORM框架特点

  1. ORM框架的内部逻辑会实现sql防注入,对数据库操作只需要调用框架提供对应api即可,不需要担心原生sql问题。
  2. 可以提升开发效率,不需要写繁琐重复的sql语句。
  3. 调试sql会比较麻烦,但是很多框架都支持写原生sql。
  4. 复杂的sql语句,很难通过框架语法写出来,故可以用原生sql。

node主流的ORM框架

node的优秀ORM框架有很多,在这只列举主流的三种

TypeORM:支持 Active Record (活动记录)和 Data Mapper(数据映射) 模式;支持多种数据库;对 TS 的高度支持、简洁、支持装饰器语法;官网:https://typeorm.bootcss.com/

Prisma:官方文档维护活跃、文档教程清晰;支持数据库较少;是对TypeScript支持最好的ORM;官网:https://prisma.yoga

Sequelize:基于 promise 的 Node.js 的 ORM;支持多种数据库;具有强大的事务支持,关联关系,预读和延迟加载等功能;官网:https://www.sequelize.com.cn

Sequelize基本介绍

Sequelize是单纯使用js开发;基于 promise 的 Node.js 的 ORM,目前支持 Mysql等多种数据库;具有强大的事务支持。其官方网站为:https://www.sequelize.cn/core-concepts/getting-started

首先我们需要安装Sequelize

yarn add sequelize@6.24.0

如何再安装mysql数据库安装驱动程序

yarn add mysql2@2.3.3

配置数据库连接

在config\sequelize.js里面编写

const {Sequelize} = require('sequelize')

const sequelize = new Sequelize('database', 'username', 'password', {
  host: 'localhost',
  dialect: 'mysql',
  port:''
})

database // 数据库名字

username // 用户名

password // 密码

host // 数据库运行的服务器ip地址

dialect // 数据库类型

port //端口号

将测试连接的这段代码加入到里面,再使用node config/sequelize.js启动项目,发现出现以下问题使用await但是没有添加异步导致出错,所有在外层添加async,改变后代码如下

(async function () {
    try {
      await sequelize.authenticate();
      console.log('数据库链接成功');
    } catch (error) {
      console.error('数据库链接失败:', error);
    }
  })()

定义数据表模型同步和初试操作

创建数据库表:通过Sequelize框架创建数据库的表,此方法创建字段比可视化工具中慢,而且不清晰。

const { Sequelize, DataTypes } = require("sequelize");
const sequelize = require("../config/sequelize");

const User = sequelize.define(
  "User",
  {
    id: {
      type: DataTypes.INTEGER,
      primaryKey: true,
      autoIncrement: true,
    },
    username: {
      type: DataTypes.STRING,
      allowNull: false,
    },
  },
  {
    tableName: "user",
    timestamps: false,
  }
);

(async () => {
  await User.sync({ alter: true });
  console.log("成功同步");
})();

module.exports = User;

模型同步

User.sync() 							 		
  - 如果表不存在,则创建该表,否则,不执行任何操作

User.sync({ force: true }) 	
  - 将创建表,如果表已经存在,则将其首先删除

User.sync({ alter: true }) 	
  - 这将检查数据库中表的数据,然后在表中进行必要的更改以使其与模型匹配

模型简单插入操作

const express = require("express");
const app = express();
const cors = require("cors");
const User = require("./models/user");

app.use(cors());

app.get("/user", async(req, res) => {
  await User.create({
    username: "李四",
  });
  res.send("创建成功");
});

app.listen(8081, () => {
  console.log("server is running at http://127.0.0.1:8081");
});

提高模型同步的开发效率

当我们数据库表中的字段如果非常多,有十几个二十几个字段的时候,如果一一创建模型,是不是过于繁琐和困难,这时候我们就想到了是否有这样的一个工具,可以根据我们的数据库表自动创建我们所需要的模型?这时候就要用到了SequelizeAuto。

官网地址:https://github.com/sequelize/sequelize-auto

安装方法:

yarn add sequelize-auto

运行命令:

node ./node_modules/sequelize-auto/bin/sequelize-auto -o "./models" -d test -h 127.0.0.1 -u root -p 3306 -x 123456 -e mysql

在package.json中编写以下代码,简化运行命令

"scripts": {
  "models": "sequelize-auto -e mysql -h 127.0.0.1 -p 3306 -u root -x 123456"
}

然后使用这个命令

yarn models -d test --cm p

--cm p // 帕斯卡命名法(将所有单词首字母大写连接)

改变app.js里面的文件

const express = require("express");
const app = express();
const cors = require("cors");
const modules = require("./models/init-models.js");
const sequelize = require("./config/sequelize.js");

app.use(cors());

app.get("/user", async(req, res) => {
  await modules(sequelize).User.create({
    username: "老王",
  });
  res.send("创建成功");
});

app.listen(8081, () => {
  console.log("server is running at http://127.0.0.1:8081");
});

请求该接口:http://127.0.0.1:8081/user,然后查看数据库观察是否添加数据成功。

Promise异步实现数据库增和查操作

const { Sequelize } = require("sequelize");
const initModules = require("../models/init-models.js");

const sequelize = new Sequelize("test", "root", "123456", {
  host: "127.0.0.1",
  dialect: "mysql",
  port: 3306,
});

(async function () {
  try {
    await sequelize.authenticate();
    console.log("数据库链接成功");
  } catch (error) {
    console.error("数据库链接失败:", error);
  }
})();

const modules = initModules(sequelize);

module.exports = {sequelize, ...modules}
const express = require("express");
const app = express();
const cors = require("cors");
const {User} = require("./config/sequelize.js");

app.use(cors());

app.get("/user", async(req, res) => {
  await User.create({
    username: "老王",
  });
  res.send("创建成功");
});

app.listen(8081, () => {
  console.log("server is running at http://127.0.0.1:8081");
});

通过Sequelize插入数据的操作(增)

app.get("/user", async(req, res) => {
  await User.create({
    username: "老王",
  });
  res.send("创建成功");
});

User.create()插入

Sequelize查询数据的操作(查)

app.get("/find", async(req, res) => {
  await User.findAll({
    where:{
      username: "王",
      age: 20
    }
  });
  res.send("创建成功");
});

通过定义变量放回给前端的数据

通过控制台打印的数据

Executing (default): SELECT `id`, `username` FROM `user` AS `User` WHERE `User`.`username` = '王';
[
  User {
    dataValues: { id: 13, username: '王' },
    _previousDataValues: { id: 13, username: '王' },
    uniqno: 1,
    _changed: Set(0) {},
    _options: {
      isNewRecord: false,
      _schema: null,
      _schemaDelimiter: '',
      raw: true,
      attributes: [Array]
    },
    isNewRecord: false
  }
]

在where的同一级添加一个raw:true即可将控制台里面的数据打印为数组的格式

[ { id: 13, username: '王' } ]

也可以使用操作符形式,但是比较麻烦一般不使用

// Op操作符
const { Op } = require("sequelize");
DB.Account.findAll({
  where: {
    username: {
      [Op.eq]: '老王'
    }
  }
});

Promise异步实现数据库改和删操作

Sequelize更新数据的操作(改)

王改为王老板

app.get("/update", async(req, res) => {
  await User.update({
    username:"王老板"
  },{
  where:{
    username: "王",
  }
  }),
  res.send("创建成功");
});

Sequelize删除数据的操作(删)

app.get("/del", async(req, res) => {
  await User.destroy({
    where:{
      username: "王",
    }
  });
  res.send("删除成功");
});

Promise一对一和一对多关系表关联和查询

一对一模型

// app.js
const express = require('express');
const app = express();
const cors = require('cors');
const { Desk, Student } = require('./config/sequelize.js')
app.use(cors());

app.get('/desk', async (req, res) => {
  const resData = await Desk.findAll({
    include: [{ model: Student, as: 'studentDetail' }]
  })
  res.send(resData)
});

app.listen(8081, () => {
  console.log('服务启动在:http://127.0.0.1:8081')
})

一对多模型

// app.js
const express = require('express');
const app = express();
const cors = require('cors');
const { Class, Student } = require('./config/sequelize.js')
const { Op } = require('sequelize')
app.use(cors());

// 查学生表
app.get('/student_class', async (req, res) => {
  const resData = await Student.findAll({
    include: [{ model: Class, as: 'classDetail' }]
  })
  res.send(dbRes)
});

// 查班级表
app.get('/class', async (req, res) => {
  const resData = await Class.findAll({
    include: [{ model: Student, as: 'studentList' }]
  })
  res.send(resData)
});

app.listen(8081, () => {
  console.log('服务启动在:http://127.0.0.1:8081')
})

Sequelize的Mysql事务

事务:有多个对数据库的操作sql语句,要么多个操作都成功,要么有一个失败就一起回滚

事务的四大特性ACID

Atomicity(原子性):
   一个事务必须是不可分割的最小工作单元,整个操作要么全部成功,要么全部失败,一般就是通过commit和rollback来控制(开启:start transaction或者begin)
   
 Consistency(一致性):
   数据库总能从一个一致性的状态转换到另一个一致性的状态,比如老王减少100元,冰冰增加200元就是不符合一致性,但是符合原子性
   
 Isolation(隔离性):
   一个事务相对于另一个事务是隔离的,一个事务所做的修改是在最终提交以前,对其他事务是不可见的   读未提交、读已提交、可重复度、可串行化
   
 Durability(持久性):
   一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失

Sequelize执行事务

非托管事务:提交和回滚事务由用户手动完成

// 评论
 app.get('/comment', async (req, res) => {
   // 1.开始一个事务并将其保存到变量中
   const t = await sequelize.transaction()
   try {
     // 2.事务作为参数传递到数据库操作中
     await Comment.create({ content: '课程讲解得很详细', order_num: '345' }, { transaction: t })
     await ProductOrder.update({ is_comment: 1 }, { where: { order_num: '345' }, transaction: t })
     // 3.如没有引发任何错误,提交事务
     await t.commit()
     res.send('成功')
   } catch (err) {
     // 3.如引发错误,回滚事务
     await t.rollback()
     res.send('失败')
   }
 });
  • 托管事务:提交和回滚事务由Sequelize 自动完成
try {
   await sequelize.transaction(async (t) => {
     await Comment.create({ content: '课程讲解得很详细', order_num: '345' }, { transaction: t })
     await ProductOrder.update({ is_comment: 1 }, { where: { order_num: '345' }, transaction: t })
   });
 } catch (error) {}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值