[Node.js][TIL] Prisma Transaction

Trippy·2023년 11월 30일
2

Node.js

목록 보기
18/28
post-thumbnail

트랜잭션(transaction)

트랜잭션이란 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 논리적 단위이다. 데이터 베이스의 상태를 변화시킨다는 말은 SELECT, INSERT, UPDATE, DELETE 등과 같은 조작어를 사용하는 행동을 의미한다.
이런 트랜잭션은 상황에 따라 여러 개가 만들어 질 수 있고, 그 각각의 트랜잭션들은 상황에 따라 Commit되거나 Rollback될 수 있다.


트랜잭션의 사용 이유

예를 들어 자금 이체 기능을 구현할 때 트랜잭션을 사용할 수 있다.
이체는 보내는 계좌에서 금액을 감소시키고, 받는 계좌에서 금액을 증가시키는 두 단계의 쿼리로 구성된다. 만약 어느 하나라도 실패하면 변경 사항을 롤백하고, 둘 다 성공하면 변경을 커밋하여 데이터베이스에 반영한다.

이러한 거래의 안정성을 확보하는 방법이 트랜잭션이다.


트랜잭션의 특징

원자성

  • 트랜잭션에서 실행되는 쿼리마다 하나의 작업 단위로 보지 않고, 여러개의 작업들을 묶어 하나의 작업단위로 보게 된다.

일관성

  • 작업이 성공하면 commit되고 실패하면 rollback되어 트랜잭션 내의 데이터의 상태가 일관성을 유지한다.

격리성

  • 트랜잭션이 실행 중인 경우 다른 트랜잭션에 의해 데이터가 변경되는 것을 방지하는 것이 특징이다.
  • 트랜잭션의 중간 과정이나 중간 결과를 볼 수 없도록 하는 특징

지속성

  • 지속성은 트랜잭션이 성공적으로 커밋된 후, 해당 트랜잭션에 의해 생성 또는 수정된 데이터가 어떠한 상황에서도 보존되는 특징이다.
  • 트랜잭션이 완료되면 결과는 데이터베이스에 영구적으로 저장된다.

락(Lock)

락은 동시성을 제어하기 위해 사용되는 기능이다. 해당하는 데이터를 점유하여 다른 트랜잭션의 접근을 막아 동시성과 일관성의 균형을 맞추기 위해 사용한다.

락의 종류

공유 락(Shared Locks) | 읽기 락(READ Locks)

  • 다른 트랜잭션이 데이터를 읽기 허용 수정 금지

배타 락(Exclusive Locks) | 쓰기 락(WRITE Locks)

  • 다른 트랜잭션이 데이터를 읽기 금지 수정 금지

락킹 수준 (Level)

글로벌 락(Global Locks) | 데이터베이스 락(Database Locks)

  • 데이터베이스의 모든 테이블에 락을 걸어, 현재 트랜잭션을 제외한 나머지 트랜잭션들이 모든 테이블을 사용할 수 없도록 만든다.
  • 가장 높은 수준의 락을 가지고 있으며, 가장 큰 범위를 가지고 있다.

테이블 락(Table Locks)

  • 다른 사용자가 작업중인 테이블을 동시에 수정하지 못하도록 한다.

네임드 락(Named Locks)

  • 테이블이나 테이블의 행과같은 DB 오브젝트가 아닌, 특정한 문자열을 점유한다.

메타데이터 락(Metadata Locks)

  • 다른 사용자가 작업중인 테이블의 동일한 행 및 동일한 데이터베이스의 객체를 동시에 수정하지 못하도록 한다

트랜잭션의 격리 수준

READ UNCOMMITTED

  • 커밋 되지 않은 읽기(Uncommitted Read)를 허용하는 격리 수준이다.
  • 가장 낮은 수준의 격리수준이며, 락을 걸지 않아 동시성이 높지만 일관성이 쉽게 깨질 수 있다.

READ COMMITTED

  • 커밋 된 읽기(Committed Read)만을 허용하고, SELECT 문을 실행할 때 공유락을 겁니다.
  • 다른 트랜잭션이 데이터를 수정하고 있는 중에는 데이터를 읽을 수 없어 커밋되지 않은 읽기현상이 발생하지 않습니다.

REPEATABLE READ

  • 읽기를 마치더라도 공유락풀지 않으며, 트랜잭션이 완전히 종료될 때 까지 락을 유지합니다.
  • 공유락이 걸린 상태에서 데이터를 수정하는 것은 불가능하지만, 데이터를 삽입하는 것이 가능해집니다. 그로인해 팬텀 읽기가 발생할 수 있는 문제점이 있습니다.

SERIALIZABLE

  • 데이터를 읽는 동안 다른 트랜잭션이 해당 데이터를 읽거나 삽입할 수 없고, 새로운 데이터를 추가하는 것 또한 불가능합니다.
  • 가장 높은 수준의 격리 수준이므로, 동시성이 떨어지는 문제점이 존재합니다.

트랜잭션에 대한 나의 고찰

유튜브에서 한참 재밌게 보고 있는 주제가 해킹이다.
최근에는 SQL인젝션에 대해서 알게 되었는데, 트랜잭션을 이용한다면 낮은 수준의 SQL인젝션을 방어 하는데 도움이 되지 않을까? 라는 생각을 가지게 되었고 잘 짜여진 트랜잭션이라면 해커들에게로 부터 안전한 DB구조를 만들 수 있지 않을까 라는 생각을 갖게 되었다.

그렇게 그 두 가지 사이에서의 연관성이 궁금해졌고 공부를 해본 결과는 다음과 같았다.

원자성을 이용 한다면?
트랜잭션은 여러 쿼리를 묶어서 원자성을 보장하므로 이를 이용해 SQL인젝션으로 인한 데이터 손상을 최소화 할 수 있지 않을까 라는 생각을 갖게 되었다.
또한 트랜잭션 내에서 실행되는 쿼리들은 원자적으로 실행되므로, 모든 쿼리가 성공해야만 데이터베이스에 영향을 미치게 되는 특성 때문에 SQL인젝션으로 인한 데이터베이스의 비정상적인 상태를 방지하는데 도움이 될 것 같다.

격리성은?
트랜잭션은 여러 트랜잭션이 동시에 실행될 떄 각각을 격리시킨다. 이는 SQL인젝션으로 인한 하나의 트랜잭션이 다른 트랜잭션에 영향을 미치지 못하도록 한다면 적어도 두 가지 트랜잭션 영역에서 운용되는 로직에서 만큼은 SQL인젝션으로 부터 안전하지 않을까?

하지만 SQL인젝션에 대한 직접적인 방어 메커니즘은 트랜잭션을 사용하는 것만으로는 충분하지 않다는 것을 알게 되었다 방어를 위한 추가적인 보안수준이 필요하다고 나와있었으며, 프리페어드 스타일의 쿼리를 사용하는 방식으로 쿼리 실행 자체의 보안을 강화하는 방법이 있다고 알게 되었다.

profile
감금 당하고 개발만 하고 싶어요

0개의 댓글