返回介绍

typeorm 使用事务的 3 种方式

发布于 2024-01-18 22:07:39 字数 6797 浏览 0 评论 0 收藏 0

typeorm 使用事务的方式有哪些?如何使用?

事务

  • 在操作多个表时,或者多个操作时,如果有一个操作失败,所有的操作都失败,要么全部成功,要么全部失
  • 解决问题:在多表操作时,因为各种异常导致一个成功,一个失败的数据错误。

例子:银行转账 如果用户 1 向用户 2 转了 100 元,但因为各种原因,用户 2 没有收到,如果没有事务处理,用户 1 扣除的 100 元就凭空消失了 如果有事务处理,只有用户 2 收到 100 元,用户 1 才会扣除 100 元,如果没有收到,则不会扣除。

应用场景

多表的增,删,改操作

nest-typrorm 事务的使用方式

  1. 使用装饰器,在 controller 中编写,传递给 service 使用
  2. 使用 getManagergetConnection ,在 service 中编写与使用
  3. 使用 connectiongetConnection ,开启 queryRunner ,在 service 中编写与使用

方式一:使用装饰器

controller

import {
  Controller,
  Post,
  Body,
  Param,
  ParseIntPipe,
} from '@nestjs/common';
import { Transaction, TransactionManager, EntityManager } from 'typeorm';  开启事务第一步:引入
import { UserService } from './user.service-oto';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) { }

  @Post(':id')
  @Transaction() 开启事务第二步:装饰接口
  async create(
    @Param('id', new ParseIntPipe()) id: number,
    @TransactionManager() maneger: EntityManager,  开启事务第三步:获取事务管理器
  ) {
    return await this.userService.create(id, maneger);  开启事务第四步:传递给 service,使用数据库时调用
  }
}

service

  • 这里处理的是 1 对 1 关系:保存头像地址到 avatar 表,同时关联保存用户的 id
  • 如果你不会 1 对 1 关系,请先去学习对应的知识

import { Injectable } from '@nestjs/common';
import { Repository, EntityManager } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';

import { UsersEntity } from './entities/user.entity';
import { AvatarEntity } from './entities/avatar.entity';
import { ToolsService } from '../../utils/tools.service';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UsersEntity)
    private readonly usersRepository: Repository<UsersEntity>,
    @InjectRepository(AvatarEntity)
    private readonly avatarRepository: Repository<AvatarEntity>,
  ) { }

  async create(id: number, manager: EntityManager) {
    const urlObj = {
      url: `http://www.dmyxs.com/images/${id}.png`,
    };
    const user = await this.usersRepository.findOne({ id });                 先查找用户,因为要保存用户的 id
    if (!user) ToolsService.fail('用户 id 不存在');                              找不到用户抛出异常
    
    const avatarEntity = this.avatarRepository.create({ url: urlObj.url });  创建头像地址的实体
    const avatarUrl = await manager.save(avatarEntity);                      使用事务保存副表
    user.avatar = avatarUrl;                                                 主表和副表建立关系
    await manager.save(user);                                                使用事务保存主表
    return '新增成功';                                                        如果过程出错,不会保存
  }
}

方式二:使用 getManager 或 getConnection

service

import { Injectable } from '@nestjs/common';
import { Connection, Repository, getManager } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { UsersEntity } from './entities/user.entity';
import { AvatarEntity } from './entities/avatar.entity';
import { ToolsService } from '../../utils/tools.service';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UsersEntity)
    private readonly usersRepository: Repository<UsersEntity>,
    private readonly connection: Connection,
  ) { }

  async test(id: string) {
    const urlObj = {
      url: `http://www.dmyxs.com/images/${id}.png`,
    };
    const user = await this.usersRepository.findOne(id);                        先查找用户
    if (!user) ToolsService.fail('用户 id 不存在');                                 找不到用户抛出异常

//getConnection 的方式:await getConnection().transaction(manager=> {});
//getManager 的方式:
    const result = await getManager().transaction(async (manager) => {
      const avatarEntity = manager.create(AvatarEntity, { url: urlObj.url });   创建头像地址的实体
      const avatarUrl = await manager.save(AvatarEntity, avatarEntity);         使用事务保存副表
      user.avatar = avatarUrl;                                                  创建关联
      return await manager.save(UsersEntity, user);                             使用事务保存主表,并返回结果
    });
    return result;
  }
}

{
    "status": 200,
    "message": "请求成功",
    "data": {
        "id": 1,
        "createdAt": "2021-04-26T09:58:54.469Z",
        "updatedAt": "2021-04-28T14:47:36.000Z",
        "deletedAt": null,
        "username": "admin",
        "gender": "male",
        "age": 18,
        "status": 1,
        "avatar": {
            "url": "http://www.dmyxs.com/images/1.png",
            "id": 52
        }
    }
}

方式三:使用 connection 或 getConnection

service

import { Injectable } from '@nestjs/common';
import { Connection, Repository, getManager } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { UsersEntity } from './entities/user.entity';
import { AvatarEntity } from './entities/avatar.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UsersEntity)
    private readonly usersRepository: Repository<UsersEntity>,
    private readonly connection: Connection,
  ) { }

  async test(id: string) {
    const urlObj = {
      url: `http://www.test.com/images/${id}.png`,
    };
    const user = await this.usersRepository.findOne(id);         先查找用户
    if (!user) ToolsService.fail('用户 id 不存在');                 找不到用户抛出异常

    const queryRunner = this.connection.createQueryRunner();     获取连接并创建新的 queryRunner
    await queryRunner.connect();                                 使用我们的新 queryRunner 建立真正的数据库连
    await queryRunner.startTransaction();                        开始事务

    const avatarEntity = new AvatarEntity();                     创建实体:要保存的数据
    avatarEntity.url = urlObj.url;

    try {
      const result = await queryRunner.manager                  使用事务保存到副表
        .getRepository(AvatarEntity)
        .save(avatarEntity);

      user.avatar = result;                                     主表和副表建立连接
 
      const userResult = await queryRunner.manager              使用事务保存到副表
        .getRepository(UsersEntity)
        .save(user);

      await queryRunner.commitTransaction();                   提交事务
      return userResult;                                       返回结果
    } catch (error) {
      console.log('创建失败,取消事务');
      await queryRunner.rollbackTransaction();                 出错回滚
    } finally {
      await queryRunner.release();                             释放
    }
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文