티스토리 뷰

txProcess 분석

백엔드 보일러 플레이트를 만들고 있는데, 옆에 계신 개발자 분이 자신이 짠 코드를 보여주셨다
처음엔 보고 이해가 안되었는데 보다보니, 놀랍다. 내가 갈 길이 멀다

즉 함수 명 그대로 트랜잭션 프로세스만 담당하는 함수이다
이 함수가 존재함으로써 안전하게 트랜잭션 처리가 되고 있음이 자명해졌다
또한 트랜잭션 처리를 하나로 묶음으로써 코드도 간결해졌다

Contents

export const txProcess = async (callback: (manager: EntityManager) => Promise<any>) => {
  const queryRunner = _datasource.createQueryRunner();
  await queryRunner.connect();
  await queryRunner.startTransaction();
  try {
    const manager: EntityManager = queryRunner.manager;
    const result: any = await callback(manager);
    await queryRunner.commitTransaction();
    return result;
  } catch (err: any) {
    await queryRunner.rollbackTransaction();
    throw Error(err);
  } finally {
    await queryRunner.release();
  }
};
export function getManager(): EntityManager {
  return _datasource.createQueryRunner().manager;
}

txProcess 함수는 데이터베이스 트랜잭션 처리를 위한 고차원 함수입니다.
고차원 함수란, 다른 함수를 인자로 받아 실행하는 함수입니다.

트랜잭션은 데이터베이스에서 일련의 연산을 묶어 원자성(atomicity), 일관성(consistency), 격리성(isolation), 지속성(durability) - ACID 속성을 보장하는 데 사용됩니다. 이러한 속성을 유지하면 데이터베이스의 정확성과 신뢰성이 향상됩니다.

txProcess의 주요 장점은 다음과 같습니다:

  1. 추상화: 트랜잭션의 시작, 커밋, 롤백 및 종료를 처리하는 로직을 추상화하여 사용자가 직접 작성할 필요가 없습니다.
    • 사용자는 콜백 함수를 전달하기만 하면 되며, 해당 콜백 함수 내에서 데이터베이스 작업을 수행하면 됩니다.
  2. 에러 처리
    • txProcess 함수는 콜백 함수 내에서 발생한 에러를 자동으로 처리합니다.
    • 에러가 발생하면 트랜잭션을 롤백하여 데이터베이스 상태를 이전 상태로 복원하고, 에러 메시지를 던져 사용자가 적절한 조치를 취할 수 있도록 합니다.
  3. 코드 재사용성
    • txProcess 함수를 사용하면 트랜잭션 관리와 관련된 코드를 재사용할 수 있습니다.
    • 이를 통해 코드 중복을 줄이고 유지 보수를 용이하게 할 수 있습니다.
  4. 일관된 패턴
    • txProcess 함수를 사용하면 모든 데이터베이스 작업에서 일관된 패턴을 따를 수 있습니다.
    • 이는 코드의 가독성을 높이고 새로운 개발자들이 프로젝트에 더 쉽게 적응할 수 있도록 도와줍니다.

txProcess를 사용하면 여러 작업을 한 트랜잭션으로 묶어 처리할 수 있으며, 이를 통해 데이터 일관성을 유지하고 에러 처리를 간소화할 수 있습니다. 이러한 이유로 많은 개발자들이 이러한 유틸리티 함수를 사용하여 데이터베이스 트랜잭션을 처리합니다.

예시

export async function editUser(
  userid: number,
  {
    nickname,
    gender,
    cccyn,
    campusid,
    major,
    sid,
    ssoid,
    email,
    type,
  }: {
    nickname: string;
    gender: Gender;
    cccyn: CommonYN;
    campusid: string;
    major: string;
    sid: number;
    ssoid?: string;
    email?: string;
    type?: string;
  },
) {
  return await txProcess(async manager => {
    const repository = manager.getRepository(User);
    const loginRepository = manager.getRepository(UserLogin);
    const confRepository = manager.getRepository(UserConfig);
    const campusRepository = manager.getRepository(UserCampus);
    if (ssoid || email || type) {
      await loginRepository.update({userid}, {ssoid, email, type});
    }
    await confRepository.update({userid}, {cccyn});
    await campusRepository.update({userid, campusid}, {major, sid});
    const result = await repository.update({userid}, {nickname, gender});
    return result;
  });
}

이 예제에서 editUser 함수는 사용자 정보를 수정하는 작업을 수행합니다.
이 작업에서는 여러 테이블(User, UserLogin, UserConfig, UserCampus)에 대한 데이터 변경이 필요하므로, 데이터 일관성을 유지하기 위해 txProcess 함수를 사용하여 모든 변경 작업을 하나의 트랜잭션으로 처리합니다.

editUser 함수는 다음과 같이 작동합니다:

  1. txProcess 함수를 호출하고, 콜백 함수를 전달합니다. 이 콜백 함수 내에서 실제 데이터베이스 작업이 수행됩니다.
  2. 콜백 함수는 매개변수로 manager 객체를 받습니다. 이 객체는 EntityManager 타입으로, 데이터베이스 엔티티를 관리하는 데 사용됩니다.
  3. manager 객체를 사용하여 각 테이블의 레포지토리(repository) 인스턴스를 얻습니다.
  4. 전달된 인자에 따라 각 레포지토리의 update 메서드를 호출하여 데이터를 수정합니다.
  5. 모든 변경 작업이 정상적으로 완료되면, txProcess 함수는 트랜잭션을 커밋하고, 수정된 결과를 반환합니다.
728x90