๐Ÿ’พ ํŠธ๋žœ์žญ์…˜(Transaction) ๊ฐœ๋… ์ •๋ฆฌ - DB ๋ฌด๊ฒฐ์„ฑ์˜ ํ•ต์‹ฌ

JOPOยท2025๋…„ 4์›” 4์ผ
0

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

๋ชฉ๋ก ๋ณด๊ธฐ
5/7
post-thumbnail

์‹ค์ œ๋กœ SQL ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ๋ฌถ์–ด์„œ ์‹คํ–‰ํ•ด๋ณด๊ณ , ์ค‘๊ฐ„์— ์˜ค๋ฅ˜๊ฐ€ ๋‚˜๋ฉด ์ „๋ถ€ ๋˜๋Œ๋ฆฌ๋Š” ๊ฑธ ๊ฒฝํ—˜ํ•ด๋ณด๋‹ˆ๊นŒ ์™œ ๊ทธ๋Ÿฐ ๋ง์ด ๋‚˜์˜ค๋Š”์ง€ ์ดํ•ด๊ฐ€ ๋์–ด์š”. ์‹ค์Šต์„ ๋”ฐ๋ผ๊ฐ€๋ฉด์„œ rollback๊ณผ commit์ด ์–ด๋–ค ์ƒํ™ฉ์—์„œ ํ•„์š”ํ•œ์ง€๋„ ํ™•์‹คํžˆ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ ์š”. '์•„~ ์ด๋ž˜์„œ ์‹ค๋ฌด์—์„œ๋„ ๊ผญ ์“ฐ๋Š”๊ตฌ๋‚˜!' ์‹ถ์€ ์ˆœ๊ฐ„์ด ์žˆ์—ˆ์–ด์š”.


๐Ÿ“š ๋ชฉ์ฐจ


๐Ÿ’ก ํŠธ๋žœ์žญ์…˜์ด๋ž€?

ํŠธ๋žœ์žญ์…˜(Transaction)์€ ํ•˜๋‚˜์˜ ๋…ผ๋ฆฌ์ ์ธ ์ž‘์—… ๋‹จ์œ„๋กœ, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์ด ๋ชจ๋‘ ์„ฑ๊ณตํ•˜๊ฑฐ๋‚˜ ๋ชจ๋‘ ์‹คํŒจํ•ด์•ผ๋งŒ ํ•˜๋Š” ๊ทธ๋ฃน์„ ๋งํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๊ณ„์ขŒ ์ด์ฒด๋ฅผ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค. A ๊ณ„์ขŒ์—์„œ 1๋งŒ ์›์„ ๋นผ๊ณ  B ๊ณ„์ขŒ์— 1๋งŒ ์›์„ ๋„ฃ๋Š” ๋‘ ์ž‘์—…์ด ํ•จ๊ป˜ ์‹คํ–‰๋ผ์•ผ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ์ชฝ๋งŒ ์ฒ˜๋ฆฌ๋˜๋ฉด ๋ฐ์ดํ„ฐ๋Š” ํ‹€์–ด์ง€๊ฒŒ ๋˜์ฃ . ์ด์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ํ•˜๋‚˜๋กœ ๋ฌถ๊ณ  ์›์ž์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋‹จ์œ„๊ฐ€ ๋ฐ”๋กœ ํŠธ๋žœ์žญ์…˜์ž…๋‹ˆ๋‹ค.

๐Ÿ›’ ๋น„์œ ํ•˜์ž๋ฉด, ํŠธ๋žœ์žญ์…˜์€ '๊ฒฐ์ œํ•˜๊ธฐ ์ „ ์žฅ๋ฐ”๊ตฌ๋‹ˆ'์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ฒฐ์ œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ธฐ ์ „๊นŒ์ง„ ์–ด๋–ค ์ƒํ’ˆ๋„ ์‹ค์ œ ๊ตฌ๋งค๋˜์ง€ ์•Š์•„์š”. ํ•˜์ง€๋งŒ ๊ฒฐ์ œ๋ฅผ ๋ˆ„๋ฅด๋Š” ์ˆœ๊ฐ„, ๋ชจ๋“  ์ƒํ’ˆ์ด ํ•œ๊บผ๋ฒˆ์— ๊ฒฐ์ œ๋˜์ฃ . ํ•˜๋‚˜๋ผ๋„ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ์ „์ฒด ๊ฒฐ์ œ๋Š” ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค.


๐Ÿ“„ ACID ํŠน์„ฑ

ํŠธ๋žœ์žญ์…˜์ด ๊ฐ–์ถ”์–ด์•ผ ํ•  ๋„ค ๊ฐ€์ง€ ์„ฑ์งˆ์„ ACID๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

์•ฝ์–ด์ด๋ฆ„์„ค๋ช…
AAtomicity (์›์ž์„ฑ)๋ชจ๋‘ ์‹คํ–‰๋˜๊ฑฐ๋‚˜, ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด ์ „์ฒด ์ทจ์†Œ๋จ
CConsistency (์ผ๊ด€์„ฑ)ํŠธ๋žœ์žญ์…˜ ์ „ํ›„์˜ ๋ฐ์ดํ„ฐ๋Š” ํ•ญ์ƒ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•จ
IIsolation (๊ฒฉ๋ฆฌ์„ฑ)๋™์‹œ์— ์‹คํ–‰๋˜๋Š” ํŠธ๋žœ์žญ์…˜ ๊ฐ„ ๊ฐ„์„ญ์ด ์—†์–ด์•ผ ํ•จ
DDurability (์ง€์†์„ฑ)ํŠธ๋žœ์žญ์…˜ ์™„๋ฃŒ ํ›„ ๋ฐ์ดํ„ฐ๋Š” ์˜๊ตฌ์ ์œผ๋กœ ๋ฐ˜์˜๋จ

๐Ÿ” Atomicity โ†’ ํ•œ ๋ชธ์ฒ˜๋Ÿผ ์›€์ง์ด๋Š” ์ž‘์—…!
๐Ÿ” Consistency โ†’ ๊ทœ์น™์ด ๊นจ์ง€์ง€ ์•Š๋„๋ก ๋ณด์žฅ!
๐Ÿ” Isolation โ†’ ๋‚ด ์ž‘์—…์€ ๋ฐฉํ•ด๋ฐ›์ง€ ์•Š๋„๋ก!
๐Ÿ” Durability โ†’ ์ „์›์ด ๋‚˜๊ฐ€๋„ ๊ฒฐ๊ณผ๋Š” ๋‚จ์•„์žˆ์–ด์•ผํ•ด!


๐Ÿ’ป SQL ์˜ˆ์‹œ

BEGIN; -- ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘

-- A ๊ณ„์ขŒ์—์„œ 1๋งŒ ์› ์ฐจ๊ฐ
UPDATE Account SET balance = balance - 10000 WHERE id = 1;

-- B ๊ณ„์ขŒ์— 1๋งŒ ์› ์ถ”๊ฐ€
UPDATE Account SET balance = balance + 10000 WHERE id = 2;

COMMIT; -- ํŠธ๋žœ์žญ์…˜ ์„ฑ๊ณต ์‹œ ํ™•์ • ์ €์žฅ

์œ„ ์˜ˆ์‹œ๋Š” A โ†’ B๋กœ 1๋งŒ ์›์„ ์ด์ฒดํ•˜๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. ์ด ๋‘ ์ฟผ๋ฆฌ๋Š” ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฌถ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด ์ „์ฒด๋ฅผ ROLLBACK ํ•ด์•ผ ๋ฐ์ดํ„ฐ ๋ถˆ์ผ์น˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿงพ ๊ณ„์•ฝ์„œ์— ์–‘์ชฝ ๋„์žฅ์ด ๋ชจ๋‘ ์ฐํ˜€์•ผ ๊ณ„์•ฝ์ด ์„ฑ๋ฆฝ๋˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.


โ˜• Java์—์„œ์˜ ํŠธ๋žœ์žญ์…˜

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class TransactionExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "root";
        String pw = "password";

        Connection conn = null;

        try {
            // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ
            conn = DriverManager.getConnection(url, user, pw);

            // ์ž๋™ ์ปค๋ฐ‹์„ ๊บผ์„œ ์ˆ˜๋™ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
            conn.setAutoCommit(false);

            // A ๊ณ„์ขŒ์—์„œ 10000์› ์ฐจ๊ฐ
            String sql1 = "UPDATE Account SET balance = balance - 10000 WHERE id = 1";
            PreparedStatement pstmt1 = conn.prepareStatement(sql1);
            pstmt1.executeUpdate();

            // B ๊ณ„์ขŒ์— 10000์› ์ถ”๊ฐ€
            String sql2 = "UPDATE Account SET balance = balance + 10000 WHERE id = 2";
            PreparedStatement pstmt2 = conn.prepareStatement(sql2);
            pstmt2.executeUpdate();

            // ๋ชจ๋“  ์ž‘์—…์ด ๋ฌธ์ œ์—†์ด ๋๋‚˜๋ฉด ์ปค๋ฐ‹
            conn.commit();
            System.out.println("ํŠธ๋žœ์žญ์…˜ ์„ฑ๊ณต: ์ปค๋ฐ‹ ์™„๋ฃŒ");

        } catch (Exception e) {
            try {
                // ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋กค๋ฐฑ
                if (conn != null) {
                    conn.rollback();
                    System.out.println("์˜ค๋ฅ˜ ๋ฐœ์ƒ: ๋กค๋ฐฑ ์ฒ˜๋ฆฌ๋จ");
                }
            } catch (Exception rollbackEx) {
                rollbackEx.printStackTrace();
            }
        } finally {
            try {
                if (conn != null) conn.close(); // ์—ฐ๊ฒฐ ์ข…๋ฃŒ
            } catch (Exception closeEx) {
                closeEx.printStackTrace();
            }
        }
    }
}

JDBC์—์„œ๋Š” setAutoCommit(false)๋ฅผ ํ˜ธ์ถœํ•ด ์ˆ˜๋™ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
๋ชจ๋“  ์ž‘์—…์ด ์„ฑ๊ณตํ•˜๋ฉด commit(), ์‹คํŒจํ•˜๋ฉด rollback()์„ ํ˜ธ์ถœํ•ด ๋ณต๊ตฌํ•ฉ๋‹ˆ๋‹ค.

โœ๏ธ ์ง์ ‘ ์ €์žฅ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์•ผ ์ €์žฅ๋˜๋Š” ์—๋””ํ„ฐ์ฒ˜๋Ÿผ, ํŠธ๋žœ์žญ์…˜๋„ ์ˆ˜๋™์œผ๋กœ ์™„๋ฃŒ์‹œ์ผœ์•ผ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.

๐Ÿงฉ Spring์—์„œ๋Š” @Transactional์„ ์‚ฌ์šฉํ•˜๋ฉด ๋”์šฑ ๊น”๋”ํ•˜๊ฒŒ ํŠธ๋žœ์žญ์…˜์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿšจ ํŠธ๋žœ์žญ์…˜ ์˜ˆ์™ธ์™€ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€

ํŠธ๋žœ์žญ์…˜ ๊ฐ„ ์ถฉ๋Œ๋กœ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ํ˜„์ƒ๋“ค

  • Dirty Read: ์•„์ง ์ปค๋ฐ‹๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๊ฒฝ์šฐ
  • Non-repeatable Read: ๊ฐ™์€ ์ฟผ๋ฆฌ๋ฅผ ๋‘ ๋ฒˆ ํ–ˆ์„ ๋•Œ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง€๋Š” ๊ฒฝ์šฐ
  • Phantom Read: ์กฐ๊ฑด์— ๋งž๋Š” ํ–‰์ด ํŠธ๋žœ์žญ์…˜ ๋„์ค‘ ์ƒˆ๋กœ ์ƒ๊ธฐ๋Š” ๊ฒฝ์šฐ
  • Deadlock: ์„œ๋กœ์˜ ์ž์›์„ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ ๋ฌดํ•œ ๋Œ€๊ธฐ ์ƒํƒœ์— ๋น ์ง€๋Š” ์ƒํ™ฉ

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋Š” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€(Isolation Level) ์„ค์ •์„ ํ†ตํ•ด ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ˆ˜์ค€์„ค๋ช…๋ง‰์„ ์ˆ˜ ์žˆ๋Š” ํ˜„์ƒ
READ UNCOMMITTED๊ฐ€์žฅ ๋‚ฎ์€ ์ˆ˜์ค€. Dirty Read ํ—ˆ์šฉ์—†์Œ
READ COMMITTED์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ๋งŒ ์ฝ์ŒDirty Read โŒ
REPEATABLE READ๊ฐ™์€ ํ–‰์— ๋Œ€ํ•œ ์กฐํšŒ ์ผ๊ด€์„ฑ ๋ณด์žฅNon-repeatable Read โŒ
SERIALIZABLE๊ฐ€์žฅ ๋†’์€ ๊ฒฉ๋ฆฌ, ์„ฑ๋Šฅ ์ €ํ•˜Phantom Read โŒ

โš ๏ธ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด ๋†’์„์ˆ˜๋ก ์•ˆ์ „ํ•˜์ง€๋งŒ ์„ฑ๋Šฅ์€ ๋‚ฎ์•„์ง‘๋‹ˆ๋‹ค. ์ƒํ™ฉ์— ๋งž๋Š” ์„ค์ •์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!


๐Ÿ“ ์š”์•ฝ

  • ํŠธ๋žœ์žญ์…˜์€ ๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ์„ ์œ„ํ•œ ํ•ต์‹ฌ ๋„๊ตฌ
  • ACID๋Š” ํŠธ๋žœ์žญ์…˜์˜ 4๋Œ€ ํŠน์„ฑ์œผ๋กœ ๋ฐ˜๋“œ์‹œ ์ดํ•ดํ•ด์•ผ ํ•จ
  • JDBC์—์„œ๋Š” ์ˆ˜๋™ ์ œ์–ด, Spring์—์„œ๋Š” @Transactional๋กœ ์„ ์–ธ์  ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • ํŠธ๋žœ์žญ์…˜ ๊ฐ„ ๊ฐ„์„ญ ๋ฌธ์ œ๋Š” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์œผ๋กœ ๋Œ€์‘

๐Ÿ“– ๋А๋‚€์ 

์ฒ˜์Œ์—” commit, rollback ๊ฐ™์€ ๊ฒƒ๋„ ๋‚ฏ์„ค๊ณ  ์–ด๋ ต๊ฒŒ ๋А๊ปด์กŒ์ง€๋งŒ, ์—๋Ÿฌ๋ฅผ ์ผ๋ถ€๋Ÿฌ ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ
'์™œ ํ•„์š”ํ•œ์ง€'๋ฅผ ๋ชธ์œผ๋กœ ๋А๋‚„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.
์ค‘๊ฐ„์— ์ฟผ๋ฆฌ ํ•˜๋‚˜๊ฐ€ ์‹คํŒจํ•˜๋ฉด ๋‚˜๋จธ์ง€๋„ ํ•จ๊ป˜ ๋˜๋Œ๋ ค์•ผ ํ•œ๋‹ค๋Š” ๊ฒŒ ์‹ค์ œ๋กœ ์ž‘๋™ํ•˜๋‹ˆ๊นŒ ์‹ ๊ธฐํ–ˆ๋‹ค.
์•„์ง ๊ฒฉ๋ฆฌ ์ˆ˜์ค€ ๊ฐ™์€ ๊ฑด ์กฐ๊ธˆ ํ—ท๊ฐˆ๋ฆฌ์ง€๋งŒ, ํ•˜๋‚˜์”ฉ ํ…Œ์ŠคํŠธํ•ด๋ณด๋‹ˆ๊นŒ '๊ทธ๋ž˜์„œ ์ด๋Ÿฐ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๊ตฌ๋‚˜' ์‹ถ์–ด์„œ ์žฌ๋ฏธ์žˆ์—ˆ๋‹ค. (๋ฌผ๋ก  ์ง€๊ธˆ๋„ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๊ฑด ๋งŽ์•„์š”!)

0๊ฐœ์˜ ๋Œ“๊ธ€