Post

[Sequelize] Unmanaged/Managed Transaction과 주의사항

인턴으로 참여하는 프로젝트에서 SvelteKit / Svelte로 웹 애플리케이션 개발을 하고 있다. 데이터베이스는 MariaDB, 스토리지는 Supabase storage, ORM은 Sequelize를 사용해서 풀스택 개발을 한다. 하나의 화면에도 여러 레포지토리에 데이터를 저장하는데, 이 작업들이 시작부터 끝까지 완결성 있게 이루어지지 않으면 큰일이 난다.

✅ 이를 위해 A부터 Z까지 원하는 작업이 전부 수행된다면 commit, 중간에 B 작업에서 문제가 생긴다면 A 작업까지 없던 것으로 만드는 트랜잭션을 도입하였다. Sequelize로 어떻게 트랜잭션을 이용할 수 있는지 정리하자!

Sequelize는 지원하는 프레임워크가 많아서 그런지 특정 프레임워크에 대한 설명은 명확하게 자세히 나와있지 않다고 생각했는데, 베이직한 내용에 대해서는 예시 코드와 설명이 잘 되어있다. 블로그를 많이 찾아봐도 공식 문서만한 글을 발견하지 못했으므로 한 번 확인하길 추천한다.


Unmanaged Transaction

  • 사용자가 직접 한 번에 이루어져야 하는 작업 단위들에 transaction을 설정하고, commit과 rollback 위치를 지정한다.
  • 트랜잭션으로 처리할 작업의 단위를 try-catch로 묶고, 단위에 transaction을 설정한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const t = await sequelize.transaction();

try {
  const user = await User.create(
    {
      firstName: "Bart",
      lastName: "Simpson"
    },
    { transaction: t }
  );

  await user.addSibling(
    {
      firstName: "Lisa",
      lastName: "Simpson"
    },
    { transaction: t }
  );

  await t.commit();
} catch (error) {
  await t.rollback();
}


Managed Transaction

  • 사용자가 한 번에 이루어져야 하는 작업 단위들에 transaction을 설정하는 것은 맞지만, commit과 rollback 위치를 지정하지 않아도 sequelize에 의해 자동으로 처리된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
try {
  const result = await sequelize.transaction(async (t) => {
    const user = await User.create(
      {
        firstName: "Abraham",
        lastName: "Lincoln"
      },
      { transaction: t }
    );

    await user.setShooter(
      {
        firstName: "John",
        lastName: "Boothe"
      },
      { transaction: t }
    );

    return user;
  });
} catch (error) {
  // If the execution reaches this line, an error occurred.
  // The transaction has already been rolled back automatically by Sequelize!
}


주의 사항

📌 Sequelize의 create 문에서 error가 throw 되어야 try-catch에서 catch로 가기 때문에 정상적으로 동작할 수 있다. Sequelize의 메서드(create, find …)를 사용하는데 repository에서 throw new Error()를 하지 않으면 catch에 걸리지 않는다.

📌 ✅ Repository에서 반드시 throw error가 필요하다. BaseRepository를 지정해서 다른 Repository들이 BaseRepository를 extends 한다면 BaseRepository에 custom throw error를 만들어 명시적으로 공통된 에러를 반환하는 것도 좋은 방법이다!

📌 Sequelize의 메서드를 사용하지 않는 경우 정상적으로 롤백되지 않는다. 예를 들어 Sequelize의 find, create를 사용한다면 정상적으로 동작하지만, 직접 구현한 메서드를 사용하는 경우 롤백되지 않을 수 있다.


✅ 인턴십을 하며 Sequelize + MariaDB에서 사용하는 트랜잭션 방법에 대해 알아보라고 하셔서 공식 문서에 나오는 내용을 어떻게 코드에 적용할 수 있을지만 알아봤었다. 트랜잭션이 프로젝트에 필요한 이유, Why에 대해서는 어렴풋이 알게 되었으니, How를 공부해야할 것 같다. 관련해서 MySQL의 트랜잭션에 대해 알아보고 다음 글을 작성하도록 하겠다!



This post is licensed under CC BY 4.0 by the author.