#node.js #nestjs #typeorm
#node.js #nestjs #typeorm
Вопрос:
Моя проблема в том, что я выполняю транзакцию, которая включает несколько запросов, и если один из этих запросов завершается неудачно, те, которые указаны выше, не откатываются, но должны. Транзакция имеет следующую структуру (рекомендуется в официальной документации nestjs):
public async create(createUserDto: RegisterUserDto): Promise<UserEntity> {
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const firstReqResult = await this.firstMethod(queryRunner, createUserDto);
const secondReqResult = await this.secondMethod(firstReqResult, queryRunner);
await queryRunner.commitTransaction();
return secondReqResu<
} catch (err) {
await queryRunner.rollbackTransaction();
throw new HttpException(err.message, HttpStatus.BAD_REQUEST);
} finally {
await queryRunner.release();
}
}
Итак, если первый метод записывает некоторые данные в некоторые таблицы данных и secondMethod
по какой-то причине выдает ошибку, то эти данные не удаляются при откате и, следовательно, в БД появляются потерянные записи.
Одна важная вещь: эти два метода firstMethod
и secondMethod
сами не являются транзакциями, это просто обычные методы, которые используют queryRunner
переданный им параметр.
Как правильно выполнить typeorm
откат такой транзакции?
Редактировать:
Похоже, что моя попытка не сработала. Поэтому я опубликую более подробную информацию:
Вот основной метод:
public async create(createUserDto: RegisterUserDto): Promise<UserEntity> {
const queryRunner = this.connection.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
// some code
const profilePrivacyPermissions = await this.profilePrivacyPermissionsService.generateInitSettings(queryRunner);
const registeredUser = await this.registerUser(user);
await queryRunner.commitTransaction();
return registeredUser;
} catch (err) {
await queryRunner.rollbackTransaction();
throw new HttpException(err.message, HttpStatus.BAD_REQUEST);
} finally {
await queryRunner.release();
}
}
registerUser
Метод выдает исключение.
Метод generateInitSettings выглядит следующим образом:
public async generateInitSettings(qr: QueryRunner): Promise<ProfilePrivacyEntity[]> {
const generatedSettings = [];
const screenTypeIds = Object.values(EScreenType).filter(value => typeof value === 'number') as number[];
for (const stId of screenTypeIds) {
const setting = this.createAndSaveInitSetting(stId, qr);
generatedSettings.push(setting);
}
return await Promise.all(generatedSettings);
}
и createAndSaveInitSetting
:
private async createAndSaveInitSetting(screenType: number, qr: QueryRunner): Promise<ProfilePrivacyEntity> {
const permission = new ProfilePrivacyEntity();
permission.setScreenType(screenType)
.setIsEverybody(true)
.setIsContacts(false)
.setIsNobody(false);
const createdPermission = qr.manager.getRepository(ProfilePrivacyEntity).create(permission);
return await createdPermission.save();
}
Поэтому, когда registerUser
метод выдает исключение, изменения, внесенные DB generateInitSettings
, не откатываются.
Комментарии:
1. Какую базу данных вы используете? Можете ли вы предоставить реализацию (точнее, вызовы
queryRunner
) вthis.firstMethod
andthis.secondMethod
?2. Я использую PostreSQL, что касается реализации, я постараюсь что-нибудь придумать, и когда я это сделаю, я опубликую это здесь, потому что оригинальные методы довольно сложны. У меня была такая же проблема с другими, более простыми методами.
3. Добавьте некоторый код, который воспроизводит проблему.
4. @jeeves хм, кажется, мне удалось исправить эту проблему, проблема заключалась в том, что один из методов не получил контекст транзакции queryRunner. Похоже, сейчас это работает, но в любом случае я не буду удалять этот вопрос, пока не буду уверен, что исправил ошибку, если нет, я попытаюсь опубликовать минимум кода, достаточного для воспроизведения проблемы.
5. Мне придется попытаться повторить это.