nest 基础概念

2023/04/25 后端 共 4365 字,约 13 分钟

快速学习和上手一个框架或者一个技能,将会成为日后混饭吃的本领。对于快速上手一个新的东西或是碰到问题如何快速解决,我曾经一度不知道该如何去做。在职场混了几年后,我好像慢慢找到了一些方法。

看文档,跑最小demo,跑代码看看,点进方法里面去看看里面如何实现,入参返回值等等,完了之后不断总结,这就是一个很不错的学习新东西的技巧。动手动脑子多调试多谷歌,就没啥问题了。

那么如何快速定位问题呢?看重要程度,重要紧急的话,先代码回滚,然后找复现路径和规律,再去排查。

概念解析

守卫只有一个职责。他们决定了请求是否要被路由处理程序处理,取决于运行时某些情况(例如权限,角色,ACL访问控制列表)。这些通常被称作授权

每个守卫必须实现一个canActivate()函数。此函数应该返回一个布尔值,指示是否允许当前请求

中间件和守卫(授权)的差别:守卫有执行上下文,可以很明确的知道接下来要执行什么。中间件只有next() 守卫的执行时期:在所有的中间件之后,在管道之前执行

守卫在每个中间件之后执行,但在任何拦截器或管道之前执行。

请求生命周期

  1. 收到请求

  2. 全局绑定的中间件

  3. 模板绑定的中间件

  4. 全局守卫

  5. 控制层守卫

  6. 路由守卫

  7. 全局拦截器/控制层拦截器/路由拦截器

  8. 全局管道/控制器管道/路由管道/路由参数

  9. 异常过来器/服务器响应

queryRunner查询事物,提供单一数据库连接

QueryBuilder优雅的使用查询语句,就是语法糖

EntityManager是所有实体的集合,查找的方式也不一样,多一个.manager

Repository就是单独的一个实体

import { SetMetadata } from “@nestjs/common”;@SetMetadata() 来将自定义元数据附加在路由处理程序上的能力。元数据提供了我们缺少的一个智能的守卫来做决定需要的角色信息,设置这个这个角色的信息

InjectRepository 是一种依赖注入的技术,用于在程序中自动注入数据库操作的 Repository 实例。 常用在Repository查询语句中

Injectable: Nest.js 框架中的一个装饰器(Decorator),用于将一个类定义为可被依赖注入的类。创建一个 Nest.js 服务类时,我们需要将这个类定义为 Injectable 类型,这样它才能被 Nest.js 容器管理。在 class 前面添加 @Injectable() 装饰器就可以将这个类定义为 Injectable 类型

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; // 操作数据库
import { Repository } from 'typeorm'; // 操作数据表
import { UserEntity } from 'src/common/entity/user.entity';

@Injectable() 
export class UserService {
  constructor(
    @InjectRepository(UserEntity) // 注入用户表(用户实例 用于进行数据库的操作
    private readonly userRepository: Repository<UserEntity>,//表示用户实体的操作类,usersRepository 是自定义的变量名,表示一个 User 实体的 Repository 对象的引用
  ) {}

  async findAll() {
    return await this.userRepository.find();
  }
}

如果在 createQueryBuilder() 查询语句的链式调用中没有跟着 .getOne() 或者 .getMany() 等方法,将无法获得具体的查询结果,而只会返回一个 TypeORM 的 QueryBuilder 实例。

这个实例可以在后续的调用中继续构建查询,加入更多的查询条件、排序规则等等,在最后通过 .getOne() 或 .getMany() 等方法获取查询结果

EntityManager和DataSource 的区别

其实从名字就能看出一些大概来 EntityManager是TypeORM提供的高级API,用于应用程序的数据操纵,而DataSource是用于与数据库建立连接的基础设施组件。(表操作和库操作

DataSource是连接到数据库的核心部分,用于建立与数据库之间的连接,执行查询和获取结果

EntityManager则是用于在应用程序中创建、读取、更新和删除数据的API

DataSource负责处理连接池和连接的创建、释放和管理等基础任务。因此,在大多数情况下,您不需要与DataSource直接交互,而是让TypeORM自动为您处理。

EntityManager则提供面向对象的API,可以让开发者更加方便地进行数据操作。你可以通过它进行各种数据库操作,例如插入、更新、删除和查询等

getManager 和 getConnection 的区别

getManager 用于实体操作,而 getConnection 用于访问更底层的数据库连接和 SQL 操作。可以根据具体的场景来选择使用哪一个方法,或者同时使用它们来实现更复杂的操作。是不是和上面的很相似

getManager 方法返回一个 EntityManager 实例,用于执行实体操作(例如读取、保存等)。EntityManager控制与实体相关的上下文以及实体状态管理,可以使用它来执行数据库操作。

getConnection 方法用于返回连接数据库的底层技术实现。Connection 对象提供了这些数据库连接,可以用它来执行原始 SQL 查询和事务控制等操作。如果想要进行一些特殊的查询操作,或是想要使用原生 SQL 查询来操作数据库,就需要使用 getConnection 获取 Connection 对象操作。

创建事务的两种方式

createQueryRunner创建一个事务,数据库事务代表在数据库管理系统(DBMS)中针对数据库的一组操作,这组操作是有关的、可靠的并且和其他事务相互独立的

使用 EntityManager 的 transaction 方法,如果回调函数中的任何操作抛出异常,则执行自动回滚操作并抛出此异常。如果回调函数成功完成,则事务将被提交

我们使用 EntityManager 对象来执行数据库操作,并使用 queryRunner 属性来手动启动、提交和回滚事务。使用 EntityManager 和 queryRunner 可以更好地控制事务的行为,同时保留了 TypeORM 的高级特性

手动启动、提交和回滚事务

import { getManager } from 'typeorm';

const updateSalaries = async (employees, bonuses) => {
  const entityManager = getManager(); // 它返回一个 EntityManager 对象,从而允许你在你的应用程序的不同位置执行实体操作
  const queryRunner = entityManager.queryRunner;

  // 启动事务
  await queryRunner.startTransaction();

  try {
    // 在事务中更新每个雇员的薪水和奖金
    for (let i = 0; i < employees.length; i++) {
      const employee = employees[i];
      const bonus = bonuses[i];

      employee.salary += bonus;
      employee.bonus = bonus;

      await entityManager.save(employee);
    }

    // 提交事务
    await queryRunner.commitTransaction();
  } catch (err) {
    // 回滚事务
    await queryRunner.rollbackTransaction();
    console.error(err);
  } finally {
    // 清理使用的资源
    await queryRunner.release();
  }
}

where 查询语句的几种实用方式

等值查询:createQueryBuilder(‘user’) .where(‘user.username = :username’, {username: ‘johndoe’});

in 查询:createQueryBuilder(‘user’) .where(‘user.id IN (:…ids)’, { ids: [1, 2, 3] });

not in 查询:createQueryBuilder(‘user’) .where(‘user.id NOT IN (:…ids)’, { ids: [1, 2, 3] });

like 查询:createQueryBuilder(‘user’) .where(‘user.username LIKE :username’, { username: ‘%johndoe%’ });

not like 查询:createQueryBuilder(‘user’) .where(‘user.username NOT LIKE :username’, { username: ‘%johndoe%’ });

between 查询:createQueryBuilder(‘user’) .where(‘user.registeredAt BETWEEN :startDate AND :endDate’, { startDate: ‘2021-01-01’, endDate: ‘2021-12-31’ });

or 查询:createQueryBuilder(‘user’) .where(‘user.username LIKE :username’) .orWhere(‘user.age = :age’) .setParameters({ username: ‘%johndoe%’, age: 30 });

and 查询:createQueryBuilder(‘user’) .where(‘user.username LIKE :username’) .andWhere(‘user.age = :age’) .setParameters({ username: ‘%johndoe%’, age: 30 });

is null 查询:createQueryBuilder(‘user’) .where(‘user.username IS NULL’);

where里面直接设置参数和使用setParameters有啥区别

一是直接将参数写在查询语句中,二是使用 setParameters 方法。这两种方式的区别在于可读性和安全性。使用 setParameters 方法可以想 SQL prepared 语句一样定义参数,这样不仅可以避免 SQL 注入的风险,而且也使查询语句更易于理解和维


在技术的历史长河中,虽然我们素未谋面,却已相识已久,很微妙也很知足。互联网让世界变得更小,你我之间更近。

在逝去的青葱岁月中,虽然我们未曾相遇,却共同经历着一样的情愫。谁的青春不曾迷茫或焦虑亦是无奈,谁不曾年少过

在未来的日子里,让我们共享好的文章,共同学习进步。有不错的文章记得分享给我,我不会写好的文章,所以我只能做一个搬运工

我叫 sunseekers(张敏) ,千千万万个张敏与你同在,18年电子商务专业毕业,毕业后在前端搬砖

如果喜欢我的话,恰巧我也喜欢你的话,让我们手拉手,肩并肩共同前行,相互学习,互相鼓励

文档信息

Search

    Table of Contents