Откат транзакции в Nest
Представим, что второй шаг записи падает с ошибкой, а первый уже отправлен в базу через менеджер вне общего блока. В таблице остаётся одна лишняя строка, хотя операция для клиента считается неудачной.
Если ошибка возникает внутри
callback блока transaction,
TypeORM не фиксирует изменения
и выполняет откат. Строки,
которые успели пройти через
менеджер до исключения, исчезают
из таблицы так же, как если бы
их не сохраняли.
Покажем на примере постов. Сущность та же, что в прошлом уроке:
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
}
Контроллер сохранит первую строку, затем выбросит исключение до второго сохранения:
import { Controller, Post } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { Post as PostEntity } from '../post.entity.js';
@Controller('posts')
export class PostController {
dataSource: DataSource;
constructor(dataSource: DataSource) {
this.dataSource = dataSource;
}
@Post('fail-pair')
failPair() {
return this.dataSource.transaction(async (manager) => {
await manager.save(PostEntity, {
title: 'Draft note',
});
throw new Error('Second step failed');
await manager.save(PostEntity, {
title: 'Final note',
});
});
}
}
Модуль темы и корень настраивают базу так же, как при парной записи без ошибки:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Post } from '../post.entity.js';
import { PostController } from './post.controller.js';
@Module({
imports: [TypeOrmModule.forFeature([Post])],
controllers: [PostController],
})
export class PostsModule {}
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PostsModule } from './posts/posts.module.js';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'postgres',
database: 'site',
autoLoadEntities: true,
synchronize: true,
}),
PostsModule,
],
})
export class AppModule {}
Сделайте в WorkerController
действие, где намеренная ошибка
внутри блока не оставляет
ни одной строки работника
в таблице, и подключите
WorkersModule к базе
в корне.