Node.js/Sequelize

[ORM] ๐Ÿ“š Sequelize - Transaction ๋ฌธ๋ฒ•

์ธํŒŒ_ 2022. 1. 28. 21:38

transaction

 

์„ ํ–‰ํ•™์Šต

 

[MYSQL] ๐Ÿ“š ํŠธ๋žœ์žญ์…˜(Transaction) ์ด๋ž€? ๐Ÿ’ฏ ์ •๋ฆฌ

ํŠธ๋žœ์žญ์…˜(Transaction) ์ด๋ž€? ํŠธ๋žœ์žญ์…˜(Transaction)์˜ ์‚ฌ์ „์  ์˜๋ฏธ๋Š” ๊ฑฐ๋ž˜์ด๊ณ , ์ปดํ“จํ„ฐ ๊ณผํ•™ ๋ถ„์•ผ์—์„œ์˜ ํŠธ๋žœ์žญ์…˜(Transaction)์€ "๋”์ด์ƒ ๋ถ„ํ• ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์—…๋ฌด์ฒ˜๋ฆฌ์˜ ๋‹จ์œ„"๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ด๊ฒƒ์€ ํ•˜๋‚˜์˜

inpa.tistory.com


Sequelize Transaction

Sequelize๋Š” transaction์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ง€์›ํ•œ๋‹ค.

  1. Unmanaged Transactions : Unmanaged transactions๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ปค๋ฐ‹๊ณผ ๋กค๋ฐฑ์„ ์ง์ ‘ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.
  2. Managed Transactions : Managed transactions๋Š” Sequelize๊ฐ€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ž๋™์œผ๋กœ ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑํ•ด์ฃผ๋ฉฐ, ๋ฐ˜๋Œ€์˜ ๊ฒฝ์šฐ์—๋Š” ์ž๋™์œผ๋กœ ์ปค๋ฐ‹์„ ํ•ด์ค€๋‹ค.

 

๋‹ค์Œ ORM ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

3๊ฐœ์˜ ์ฟผ๋ฆฌ๋Š” ๋ฐ˜๋“œ์‹œ ๋ชจ๋‘ ์„ฑ๊ณตํ•˜๊ฑฐ๋‚˜ ์‹คํŒจํ•ด์•ผ ํ•œ๋‹ค. ์ค‘๊ฐ„์— ์–ด๋–ค๊ฑด ์„ฑ๊ณตํ•˜๊ณ  ์–ด๋–ค๊ฑด ์‹คํŒจ๋œ์ฑ„๋กœ ์กฐ์ž‘๋˜๋ฉด ํฌ๋‚˜ํฐ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค๊ณ  ํ•˜์ž.

const success = await Auction.findOne({
   where: { GoodId: good.id },
   order: [['bid', 'DESC']],
});

await Good.update(
   { SoldId: success.UserId },
   { where: { id: good.id } },
);

await User.update(
   { money: sequelize.literal(`money - ${success.bid}`) },
   { where: { id: success.UserId } },
);

Unmanaged Transactions

//* ํŠธ๋žœ์žญ์…˜ ์„ค์ •
const t = await sequelize.transaction();

// try catch๋กœ ๋ฌถ์Œ !!
try {
   const success = await Auction.findOne({
      where: { GoodId: good.id },
      order: [['bid', 'DESC']],
      transaction: t, // ์ด ์ฟผ๋ฆฌ๋ฅผ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
   });
   
   await Good.update(
      { SoldId: success.UserId },
      {
         where: { id: good.id },
         transaction: t, // ์ด ์ฟผ๋ฆฌ๋ฅผ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
      },
   );
   
   await User.update(
      { money: sequelize.literal(`money - ${success.bid}`) },
      {
         where: { id: success.UserId },
         transaction: t, // ์ด ์ฟผ๋ฆฌ๋ฅผ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
      },
   );
   
   await t.commit(); // ํŠธ๋žœ์žญ์…˜ ๋ฌธ์ œ์—†์œผ๋ฉด ์ปค๋ฐ‹
   
} catch (err) {
   await t.rollback(); // ์ค‘๊ฐ„์— failed ๋‚˜๋ฉด ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ
}

unmanaged transaction์€ ์œ„์— ๋ณด์ด๋Š” ์ฝ”๋“œ์™€ ๊ฐ™์ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ผ์ผํžˆ commit ๊ณผ rollback์˜ ์œ„์น˜๋ฅผ ์ง€์ •ํ•ด๋†“๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์ฝ”๋“œ๊ฐ€ ๋ฌธ์ œ ์—†์ด ์‹คํ–‰์ด ๋˜์—ˆ๋‹ค๋ฉด try์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์—์„œ transaction์„ ์ปค๋ฐ‹ํ•œ๋‹ค.

๋งŒ์•ฝ ์ฝ”๋“œ ์ค‘๊ฐ„์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋ฉด catch ๋ถ€๋ถ„์—์„œ transaction์„ ๋กค๋ฐฑํ•œ ํ›„ ์—๋Ÿฌ ๋กœ๊ทธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

 

 

Managed Transactions 

// try catch๋กœ ๋ฌถ์Œ !!
try {
   //* ํŠธ๋žœ์žญ์…˜ ์„ค์ •
   await sequelize.transaction(async (t) => {

      const success = await Auction.findOne({
         where: { GoodId: good.id },
         order: [['bid', 'DESC']],
         transaction: t, // ์ด ์ฟผ๋ฆฌ๋ฅผ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
      });

      await Good.update(
         { SoldId: success.UserId },
         {
            where: { id: good.id },
            transaction: t, // ์ด ์ฟผ๋ฆฌ๋ฅผ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
         },
      );

      await User.update(
         { money: sequelize.literal(`money - ${success.bid}`) },
         {
            where: { id: success.UserId },
            transaction: t, // ์ด ์ฟผ๋ฆฌ๋ฅผ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
         },
      );
   });

   // ํŠธ๋žœ์žญ์…˜ ๋ฌธ์ œ์—†์œผ๋ฉด ์•Œ์•„์„œ ์ž๋™์œผ๋กœ ์ปค๋ฐ‹
} catch (err) {
    // ์ค‘๊ฐ„์— failed ๋‚˜๋ฉด ์•Œ์•„์„œ ์ž๋™์œผ๋กœ ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ
}

Managed trasaction์€ Unamanaged Transaction๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ,

๊ฐœ๋ฐœ์ž๊ฐ€ commit๊ณผ rollback์„ ๋”ฐ๋กœ ๋ช…์‹œํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š” ์ฐจ์ด์ ์ด ์žˆ๋‹ค.

๊ธฐ๋Šฅ์ด ๋ฌธ์ œ ์—†์ด ์ง„ํ–‰์ด ๋œ๋‹ค๋ฉด ์ฝœ๋ฐฑํ•จ์ˆ˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์—์„œ commit์„ ์ž๋™์œผ๋กœ ์‹คํ–‰ํ•˜๋ฉฐ, error๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ž๋™์œผ๋กœ rollback์„ ํ•ด์ค€๋‹ค.


transaction์„ ์‚ฌ์šฉํ•  ๋•Œ ์œ ์˜ํ•ด์•ผ ํ•  ์ ์€ try catch์˜ ๋ฒ”์œ„๋ฅผ ์ž˜ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ์ด๋‹ค.

๋งŒ์•ฝ managed transaction์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ try ๋ฒ”์œ„ ๋ฐ–์—์„œ throw Error๋ฅผ ๋˜์ง„๋‹ค๋ฉด, catch์—์„œ ์—๋Ÿฌ๋ฅผ ์žก์ง€ ๋ชปํ•ด ๋กค๋ฐฑ์ด ์‹คํ–‰๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ ํ•ญ์ƒ ์ƒํ™ฉ์— ๋งž์ถฐ์„œ try catch์˜ ๋ฒ”์œ„๋ฅผ ์ž˜ ์„ ํƒํ•ด์•ผ ํ•˜๊ณ , ๊ฑฐ๊ธฐ์— ๋งž๋Š” transaction ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์ฝ”๋“œ ๋กœ์ง์ด ๋ณต์žกํ•œ ๊ฒฝ์šฐ์—๋Š”,
์–ด๋””์„œ ์ปค๋ฐ‹๊ณผ ๋กค๋ฐฑ์ด ์ผ์–ด๋‚˜๋Š” ์ง€ ์‰ฝ๊ฒŒ ์•Œ๊ธฐ ์œ„ํ•ด unmanaged transaction์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š”๊ฑธ ์ถ”์ฒœํ•˜๋Š” ๋ฐ”์ด๋‹ค

Reference

https://gareen.tistory.com/79

https://jeonghwan-kim.github.io/2016/07/13/sequelize-transaction.html

https://avengersrhydon1121.tistory.com/224

https://uju-tech.tistory.com/96

https://velog.io/@leesilverash/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98-%EC%82%AC%EC%9A%A9%EB%B2%95-sequelize