[PostgreSQL] Transaction + Pool 사용시 주의

2022. 4. 4. 12:06·DataBase/PostgreSQL

 

 

pool 객체를 트랜잭션과 함께 쓰지마라.
Do not use pool.query if you need transactional integrity: the pool will dispatch every query passed to pool.query on the first available idle client. Transactions within PostgreSQL are scoped to a single client and so dispatching individual queries within a single transaction across multiple, random clients will cause big problems in your app and not work. For more info please read transactions.
                                                                                                                                                  - node-postgre docs

 

PostgreSQL 에서 모든 트랜잭션은 단일 클라이언트 범위 내에서 이뤄진다.

connection pool 은 모든 pool.query 를 1번째로 놀고있는 클라이언트에 dispatch 하게 되어있다.

따라서 단일 트랜잭션 내에서 여러, 랜덤한 클라이언트로 쿼리 내용을 displatch 하는 것은 매우 큰 문제를 야기한다.

 

Dispatch?

메모리기반의 데이터를 다루는 Object가 버퍼링과 노출 (최종 execute)하여 메모리 다음 블록에 적용하는 것.

=> 트랜잭션은 최종 COMMIT이나 ROLLBACK 하기 전에 모든 쿼리를 미리 연속된 블록에 써둔다.

이 쓰는 동작을 'dispatch' 라고 한다.

 

 

pool vs poolCLient

pool (⚠️) 위험한 코드 사례

커넥션 풀 객체

pool.query() 는 트랜잭션 내에 써선 안된다.
const { Pool } = require('pg')
const pool = new Pool();

await pool.query('BEGIN');

// 아래 2개의 query는 
// 놀고 있는 1번째 클라이언트에 dispatch 한다. (블록에 query 기록)

await pool.query(renameUserQuery, [
    id, 'new_name'
]);
await pool.query(renewModifiedDatetime, [
	new Date()
]);

// 앞서 dispatch 한 모든 쿼리를 COMMIT 
await pool.query('COMMIT')

pool.query 의 장점은 내부적으로 acquire / release 를 한번에 해준다는 것이다.

 

그러나 다음과 같은 케이스에서 매우 위험하다.

`renameUserQuery` 를 할 때의 디스패치 할 클라이언트와 `renewModifiedDatetime` 할 때 디스패치 할 클라이언트가 다를 수 있다.

 

따라서 트랜잭션 사용시 pool 대신 일반 poolClient 를 쓰는 것이 안전하다.

 

 

poolClient ✅

커넥션 풀로부터 받아온 커넥션 객체로,
트랜잭션과 사용하기 적절하다.

단, try ~ catch ~ finally 를 통해 에러 핸들링을 하고, `release()`를 반드시 해줘야한다.

(내부적으로 client 를 acquire ~ release 를 자동으로 해주지 않음)

const { Pool } = require('pg')
const pool = new Pool();


(async ()=>{
	// 커넥션 풀로부터 단일 클라이언트를 빌려온다.
    // => 앱에서 여러 쿼리를 실행해도 독립된 클라이언트 내에서 dispatch 가 일어난다.
    const poolClient = pool.connect();
    try {
    	await poolClient.query('BEGIN');

        await poolClient.query(renameUserQuery, [
            id, 'new_name'
        ]);
        await poolClient.query(renewModifiedDatetime, [
            new Date()
        ]);

        // 앞서 dispatch 한 모든 쿼리를 COMMIT 
        await poolClient.query('COMMIT');
    } catch(e) {
    	await poolClient.query('ROLLBACK');
    } finally {
        // 명시적 해제
        poolClient.release();
    }
    
})();

 

 

📝 결론

poolClient 를 pool 로부터 받아와서 사용하라. (pool 객체를 그대로 사용하길 지양할 것)

 

 

 


🔗 Reference

 

Apple Developer Documentation

 

developer.apple.com

 

Transactions

To execute a transaction with node-postgres you simply execute BEGIN / COMMIT / ROLLBACK queries yourself through a client. Because node-postgres strives to be low level and un-opinionated, it doesn't provide any higher level abstractions specifically arou

node-postgres.com

 

저작자표시 (새창열림)

'DataBase > PostgreSQL' 카테고리의 다른 글

[PostgreSQL] CHECK Constraint  (0) 2022.05.04
[PostgreSQL] Trigger + Transaction  (0) 2022.04.18
[PostgreSQL] Function (feat. trigger)  (0) 2022.03.29
[PostgreSQL] Notify  (0) 2022.03.25
[PostgreSQL] Transaction 왜, 언제, 어떻게 동작하나?  (0) 2022.03.25
'DataBase/PostgreSQL' 카테고리의 다른 글
  • [PostgreSQL] CHECK Constraint
  • [PostgreSQL] Trigger + Transaction
  • [PostgreSQL] Function (feat. trigger)
  • [PostgreSQL] Notify
M_Falcon
M_Falcon
  • M_Falcon
    Falcon
    M_Falcon
  • 전체
    오늘
    어제
    • 분류 전체보기 (432) N
      • Web (16)
        • Nodejs (14)
        • Javascript (23)
        • FrontEnd (4)
      • DataBase (39)
        • Fundamental (1)
        • Redis (4)
        • PostgreSQL (10)
        • NoSQL (4)
        • MySQL (9)
        • MSSQL (3)
        • Error (4)
      • Algorithm (79)
        • Algorithm (문제풀이) (56)
        • Algorithm (이론) (23)
      • JVM (65)
        • Spring (13)
        • JPA (5)
        • Kotlin (13)
        • Java (24)
        • Error (7)
      • 기타 (70) N
        • Kafka (3)
        • Kubernetes (3)
        • Docker (13) N
        • git (19)
        • 잡동사니 (27)
      • 재테크 (11)
        • 세무 (4)
        • 투자 (3)
        • 보험 (0)
      • BlockChain (2)
        • BitCoin (0)
      • C (32)
        • C (10)
        • C++ (17)
        • Error (3)
      • Low Level (8)
        • OS (3)
        • 시스템 보안 (5)
      • 네트워크 (3)
      • LINUX (30)
        • Linux (26)
        • Error (4)
      • 저작권과 스마트폰의 이해 (0)
      • 생각 뭉치 (6)
      • 궁금증 (2)
      • Private (4)
        • 이직 경험 (0)
        • 꿈을 찾아서 (1)
      • Android (21)
        • OS (4)
  • 블로그 메뉴

    • 홈
    • WEB
    • 알고리즘
    • DataBase
    • Linux
    • Mobile
    • C
    • 방명록
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    Spring
    kafka
    PostgreSQL
    docker
    linux
    알고리즘
    ubuntu
    백준
    Programmers
    java
    database
    C++
    android
    Kotlin
    프로그래머스
    algorithm
    javascript
    Bitcoin
    JPA
    Git
  • hELLO· Designed By정상우.v4.10.3
M_Falcon
[PostgreSQL] Transaction + Pool 사용시 주의
상단으로

티스토리툴바