오늘은 nestjs에서 typeorm transaction을 어떻게 활용하는지에 대해서 보려고 합니다 🤔
typeorm에서는 transaction을 관리하는 내장 함수를 제공합니다.
일단 참고한 transaction docs를 공유합니다.
DOCS : https://orkhan.gitbook.io/typeorm/docs/transactions
typeorm을 통해서 transaction을 할 수 있는 방법은 여러개가 있는것으로 보여졌습니다.
그중에서도 가장 직관적이고 개발자가 수동적으로 작동시킬 수 있는 코드를 이용해서 코드화 작업을 해보았습니다.
import {getConnection} from "typeorm";
// get a connection and create a new query runner
const connection = getConnection();
const queryRunner = connection.createQueryRunner();
// establish real database connection using our new query runner
await queryRunner.connect();
// now we can execute any queries on a query runner, for example:
await queryRunner.query("SELECT * FROM users");
// we can also access entity manager that works with connection created by a query runner:
const users = await queryRunner.manager.find(User);
// lets now open a new transaction:
await queryRunner.startTransaction();
try {
// execute some operations on this transaction:
await queryRunner.manager.save(user1);
await queryRunner.manager.save(user2);
await queryRunner.manager.save(photos);
// commit transaction now:
await queryRunner.commitTransaction();
} catch (err) {
// since we have errors let's rollback changes we made
await queryRunner.rollbackTransaction();
} finally {
// you need to release query runner which is manually created:
await queryRunner.release();
}
위의 코드는 docs에 나와있는 그대로의 코드입니다.
우선 각각의 연결이 어떻게 되는지를 우선적으로 보겠습니다.
const connection = getConnection();// typeorm을 통해서 db를 연결하는 코드입니다.
const queryRunner = connection.createQueryRunner(); // 새로운 쿼리 러너를 사용하겠다는 의미입니다.
await queryRunner.connect();
await queryRunner.startTransaction();
//쿼리 러너를 연결해서 transaction을 시작할 준비를 마쳤습니다.
@Injectable()
export class UsersService {
private logger = new Logger('UsersService');
constructor(
@InjectRepository(Users)
private readonly usersRepository: Repository<Users>,
@InjectRepository(WorkspaceMembers)
private readonly workspaceMembersRepository: Repository<WorkspaceMembers>,
@InjectRepository(ChannelMembers)
private readonly channelMembersRepository: Repository<ChannelMembers>,
private readonly connection: Connection,
) {}
async authorUser() {
try {
} catch (e) {
console.log('authorUser Error: ', e);
}
}
async join(joinData: JoinRequestDto): Promise<any> {
const { email, nickname, password } = joinData;
const user = await this.usersRepository.findOne({ where: { email } });
console.log('user: ', user);
if (user) {
return new UnauthorizedException('이미 존재하는 사용자 입니다.');
}
const queryRunner = this.connection.createQueryRunner();
try {
//transation을 쓰지 않았다면 이러한 코드를 입력하면 됩니다.
//그러나 transation을 하려면 아래와 같은 코드로 입력해선 안됩니다.
//아래와 같이 입력하면 안되는 이유? 🤔
//아래와 같은 연결은 typrorm.config에 연결되어있는 코드와 연결되는 코드입니다. 따라서 아래와 같은 코드를 입력하면 위에 transaction에서 연결한 코드로 연결되지 않아 transation에 원활하게 동작하지 않게됩니다. 따라서 아래와 같은 코드 대신해야합니다 (✅ 이모지에 따른 코드!)
await this.workspaceMembersRepository.save({
UserId: returned.id,
ChannelId: 1,
})
//✅ 여기와 같은 코드로 입력해야 transation의 진행이됩니다!
await queryRunner.manager.getRepository(ChannelMembers).save({
UserId: returned.id,
ChannelId: 1,
});
await queryRunner.commitTransaction();
return true;
} catch (e) {
this.logger.log('postUsers Error: ', e);
await queryRunner.rollbackTransaction();
} finally {
//디비에는 최대 연결 계수가 있기떄문에 연결을 끊어주어야한다.
await queryRunner.release();
}
}
}