좌충우돌 개발공부

TIL(20240531) [데이터베이스:트랜잭션과 ACID]


들어가기전에 데이터베이스의 개념을 한번 더 생각하고 정리하면서 데이터베이스의 트랜잭션을 알아보자!

📌 데이터베이스(DB)

: 데이터를 쉽게 공유하기 위해 체계적으로 관리되는 데이터의 집합

📌 DBMS : 이런 데이터베이스를 관리하는 시스템

  • 데이터의 특성에 따라 효율적으로 관리할 수 있다.
  • 관계형 데이터베이스(SQL) vs 비관계형 데이터베이스(NoSQL)

💥 스키마? 구조와 제약 조건에 관한 명세

💡 SQL

  • 스키마를 가지고 있다.
  • MySQL, PostgreSQL, SQLite, ORACLE
  • 엑셀과 유사한 형태로 행과 열이 존재. 엑셀에 시트가 있다면 SQL에는 테이블이 있다!
  • 데이터의 구조가 엄격함

💡 NoSQL

  • 스키마가 정해져 있지 않은 형태
  • 장점 : 속도가 빠름, 확장성, 유연성 1) Document_DB
  • MongoDB(데이터를 json document형태로 저장함) : 어떤 형태로든 저장이 가능하다.
  • firebase 2) Key-value DB
  • CassandraDB : column wide database 유형으로 읽고, 쓰기가 빠름 대기업 중 애플, 넷플릭스, 인스타그램, 우버 같은 회사들이 사용하고 있음. 검색엔진처럼 많은 양의 데이터를 빠르게 읽어야 한다면 카산드라가 유용함
  • DynamoDB : serverless, 분산된 key-value형태로 아마존이 만들었음. 영어학습과 같은 형태의 프로그램을 제작할 때 읽기가 빠르기 때문에 유용함 3) Graph DB : 각 노드 사이관계를 알아야 할때 필요함 ex)소셜네트워크(페이스북-> Tao라는 DB를 만듬)
  • neo4j

🚩 데이터베이스 트랜잭션

  • 트랜잭션(transaction)이란? 단일한 논리적인 작업단위, 논리적인 이유로 여러 SQL문들을 단일 작업으로 묶어서 나눠질 수 없게 만든 것이 transaction이다. 이해가 쉽게 설명하자면, 한 단위안에 A와 B가 있는데 A와 B가 모두 성공해야만 그 결과를 DB에 저장할 수 있다는 의미이다. 그래서 transaction의 SQL문들 중에 일부만 성공해서는 DB에 반영되는 일은 없다.

그렇다면 어떤 경우에 transactio이 필요한지 알아보자.

  • ⭐예시: 하니은행의 고객인 A,B가 있는데 A는 요니의 엄마 B는 요니다. 요니는 엄마에게 문제집을 사기위해 10,000원을 입금해달라고 요청을 한다. 그래서 A의 통장잔고에 500,000원이 있고 B에게는 5,000원이 있다. A는 B에게 10,000원을 입금해준다면 A의 통잔잔고: 490,000원이고 B의 통장잔고: 15,000원이 된다. 여기서 A가 B에게 입금하면서 (-)된 금액과 B에게 (+)된 금액이 된 과정을 트랜잭션이라고 생각하면 A 통장잔고에서 출금(1) , B 통잔잔고에 입금(2) 2개의 단위로 나눌 수 있다. 여기서 하나의 과정이라도 잘못 된다면 어떻게 될까? A 통장잔고에서 출금은 되었지만 B에게 입금되지 않았으면 10,000원은 날라가는 셈, A통장잔고에서 출금은 안되었지만 B에게 10,000원이 입금되면 하니은행은 망한다……. 이러한 경우에 transaction이 필요하다고 볼 수 있다.

SQL문에서 어떻게 이 과정들이 이루어지는지 한번 알아보자

CREATE Table account;

START TRANSACTION; 

insert into account value('YoniMom', 500000);
insert into account value('Yoni', 5000);

UPDATE account SET balance = balance - 10000 WHERE id ='YoniMom';
UPDATE account SET balance = balance + 10000 WHERE id ='Yoni';

COMMIT;

💡 COMMIT ? 지금까지 작업한 내용을 DB에 영구적으로 저장한다, 그리고 Transaction을 종료하겠다.

결과는?

  • 요니엄마의 통장잔고: 490,000원이 되고 요니의 통장잔고: 15,000원이 된다. 여기서 요니가 문구용품을 조금 더 사겠다고 해서 20,000원을 더 보내달라고 한다면?
START TRANSACTION;

UPDATE account SET balance = balance - 20000 WHERE id ='YoniMom';

SELECT * FROM account;

ROLLBACK;

💡 ROLLBACK ? 지금까지의 작업들을 모두 취소하고 transaction 이전상태로 되돌린다. 그리고 Transaction을 종료하겠다.

여기까지 봤을 때 요니엄마의 통장잔고: 470,000원이 된다. 그런데 ROLLBACK 이라면? 결과는?

  • 요니엄마의 통장잔고: 490,000원(transaction이전상태로 돌린다.) 요니 통장잔고 : 15,000원

여기까지 살펴본 결과 transaction이 위와 같은 상황에서 꼭 필요하다라는 것을 알게된다. 그렇다면 매번 transaction을 START TRANSACTION 해줘야 하는 걸까?


SELECT @@AUTOCOMMIT;

insert into account values('Yonifather',100000);

SELECT * FROM account;

💡 AUTOCOMMIT 이란? 각가의 SQL문을 자동으로 transaction처리해주는 개념이고 SQL문이 성공적으로 실행되면 자동으로 COMMIT한다. 또한 실행중에 문제가 있었다면 알아서 ROLLBACK한다. 위의 쿼리문은 오토커밋의 여부를 묻는 것이고 활성화 되었다면 1 비활성화상태라면 0이 된다.

위의 쿼리문은 오토커밋이 활성화되어있는지 확인 후 (1이라고 가정했을 때) 요니아빠에게 100000원이 생성되었고 자동 커밋(영구저장)이 되었기 때문에 DB에서 확인했을 때 요니엄마:490,000원 요니:15,000원 요니아빠:100000원 으로 확인할 수 있다.

오토커밋을 하지 않고 실행하면?


SET autocommit = 0;

DELETE FROM account WHERE balance <= 100000;

SELECT * FROM account;

ROLLBACK;

오토커밋을 비활성화시키고 100,000원이하인 계좌는 삭제하도록 만들었다. 그러면 account테이블은 어떻게 될까? 요니엄마의 계좌만 남게된다. 그런데 현재 오토커밋을 하지 않은 상태이기 때문에 ROLLBACK을 해서 다시 이전상태로 되돌릴 수 있다. 여기서 헷갈리지 말아야 할 것은 START TRANSACTION을 실행하면 동시에 오토커밋은 비활성화가 되기에 영구저장을 하기 위해선 COMMIT을 꼭 해주어야 한다.

그런데 개발자는 프로그래밍 언어로 위와 같은 쿼리문을 작성하게 되는데, spring이나 SpringBoot를 사용하게 되면 부가적으로 작성해야 하는 이러한 트랜잭션 구문들을 생략하고 애너테이션(@Transactional) 하나만 메소드에 달아주게되면 자동으로 트랜잭션 걸어서 실행된다!

마지막으로 Transaction의 중요한 속성인 ACID에 대해서 살펴보자. ACID는 트랜잭션이 어떠한 속성을 가져야 하는지 나타내는 개념이다.

🚩 트랜잭션에 필요한 속성 : ACID

  • A(Atomicity) : 트랜잭션은 논리적으로 쪼개질 수 없는 작업단위이기에 내부의 SQL문들이 모두 성공해야한다. 만약 중간에 실패하게 된다면 작업을 모두 취소하여 아무일도 없었던 것처럼 ROLLBACK한다. 즉, 일부만 성공해서는 안된다. 모두 성공하거나/모두 실패하거나 COMMIT과 ROLLBACK은 DBMS가 담당하지만 개발자는 언제 COMMIT을 할지 ROLLBACK을 할지 알아야 한다
  • C(Consistency): 데이터베이스에 일관성을 유지시켜주는 것, 예를 들어서 DB에 정의된 rules을 transaction이 위반했다면 DBMS가 commit전에 확인하고 알려주고 개발자가 EXCEPTION처리를 했다면 rollback을 하게된다.
  • I(Isolation) : 여러 트랜잭션이 동시에 실행될 때도 혼자 실행되는 것처럼 동작하게 만든다. DBMS에는 여러종류의 isolation level을 제공하는데, 개발자는 isolation level중에 어떤 레벨로 트랜잭션을 동작시킬지 설정할 수 있다.
  • D(Durability): COMMIT된 트랜잭션은 DB에 영구적으로 저장한다. 즉, DB 시스템에 문제가 생겨도 COMMIT된 트랜잭션은 DB에 남아 있게된다. 이러한 기능을 DBMS가 보장하게 된다.

그러므로

1. 트랜잭션을 어떻게 정의해서 쓸지는 개발자가 정하는 것이고 구현하려는 기능과 ACID속성을 이해해야 트랜잭션을 잘 정의할 수 있다.

2. 트랜잭션의 ACID와 관련해서 개발자가 챙겨야 할 부분들이 있다. ex) exception처리 등

트랜잭션


📌 코딩테스트1️⃣ : 약수의 개수와 덧셈

🔒 문제 : 두 정수 left와 right가 매개변수로 주어집니다. left부터 right까지의 모든 수들 중에서, 약수의 개수가 짝수인 수는 더하고, 약수의 개수가 홀수인 수는 뺀 수를 return 하도록 solution 함수를 완성해주세요.

🚫 조건 :

  • 1 ≤ left ≤ right ≤ 1,000

🔓 문제풀이

class Solution {
    public int solution(int left, int right) {
        int answer = 0;
                
        for (int i=left; i<=right; i++){ // left에서 right까지 반복문 돌리기
            int count =0; 
            
            for(int j=1; j<= i; j++){ // 약수 개수 구하기
                if(i%j == 0){ // 나누어 떨어지는 수는 약수 
                    count++; // count에 약수의 개수 넣기
                }
            }
            if (count % 2 == 0) { // 개수가 짝수인지 홀수인지 
                answer += i; // 짝수라면 answer에 더하고
            } else {
                answer -= i; // 홀수라면 answer에서 빼기
            }
        }
        return answer;
    }
}