백엔드/Node

데이터베이스에서 동시 수정을 방지하기

홍수성찬 2023. 5. 21. 14:55

데이터베이스에서 동시 수정을 방지하기 위해서 사용하는 데이터베이스 구문이 있다.

 

바로 'SELECT ... FOR UPDATE' 구문이다.

 

이 구문은 특정 행을 선택하고 해당 행에 대한 잠금을 설정하여 다른 트랜잭션에서 해당 행을 수정할 수 없도록 만들어준다. 이 구문을 활용하면 데이터의 일관성과 동시성을 유지할 수 있다.

 

다음은 'SELECT ... FOR UPDATE' 구문을 사용한 기본적인 예시이다. 이는 MySQL를 예로 들어 사용한 문법이다.

 

-- 트랜잭션 시작
START TRANSACTION;

-- 특정 행을 선택하고 잠금을 설정
SELECT * FROM your_table WHERE id = 'your_id' FOR UPDATE;

-- 선택한 행을 수정
UPDATE your_table SET column1 = 'new_value' WHERE id = 'your_id';

-- 트랜잭션 종료
COMMIT;

 

MySQL 연결을 하고, 트랜잭션을 시작한다. 그리고 수정하려는 테이블의 특정 행을 선택하고 잠금을 설정한다. 그리고 선택한 행을 수정하고 트랜잭션을 종료하는 것이 기본적인 단계이다.

 

위의 예시는 'your_table'은 대상 테이블이며, 'id'는 선택한 행의 고유 식별자이다. 'FOR UPDATE'를 사용하여 해당 행에 잠금을 설정하고 나서 'UPDATE' 문을 사용해 선택한 행을 수정하게 된다. 마지막으로 트랜잭션을 커밋해 변경 사항을 영구적으로 반영한다.

 

여기서 참고로, 'SELECT ... FOR UPDATE' 문은 데이터베이스마다 구현 방식과 지연 여부가 다르다. 사용하고자 하는 데이터베이스의 공식 문서를 참조하여 사용 방법과 지원 여부를 확인하고 사용해야 한다.

 

그렇다면, 실제로 NodeJS에서는 어떻게 활용할 수 있을까?

다음은 NodeJS에서 활용한 기본적인 예시이다.

 

const mysql = require('mysql');

// MySQL 연결 설정
const connection = mysql.createConnection({
  host: 'your_host',
  user: 'your_user',
  password: 'your_password',
  database: 'your_database',
});

// 트랜잭션 시작
connection.beginTransaction((err) => {
  if (err) {
    throw err;
  }

  const id = 'your_id';

  // 특정 행을 선택하고 잠금을 설정
  const selectQuery = `SELECT * FROM your_table WHERE id = ? FOR UPDATE`;
  connection.query(selectQuery, [id], (selectErr, results) => {
    if (selectErr) {
      connection.rollback(() => {
        throw selectErr;
      });
    }

    // 선택한 행을 수정
    const updateQuery = `UPDATE your_table SET column1 = ? WHERE id = ?`;
    const newValue = 'new_value';
    connection.query(updateQuery, [newValue, id], (updateErr, updateResult) => {
      if (updateErr) {
        connection.rollback(() => {
          throw updateErr;
        });
      }

      // 트랜잭션 커밋
      connection.commit((commitErr) => {
        if (commitErr) {
          connection.rollback(() => {
            throw commitErr;
          });
        }

        console.log('트랜잭션 커밋 성공');
        connection.end();
      });
    });
  });
});

 

위 예시에서 'your_table'은 대상 테이블이며, 'id'는 선택할 행의 고유 식별자이다. 즉, 해당 'id'를 가진 데이터를 수정하기 위함이다. 'SELECT ... FOR UPDATE'를 사용해 해당 행에 잠금을 설정하고, 'UPDATE' 문을 사용해 선택한 행을 수정한다. 트랜잭션은 'beginTransaction'으로 시작하고, 작업이 성공적으로 이루어졌다면 'commit'으로 커밋한다. 만약에 에러가 발생한다면, 'rollback'으로 롤백해 트랜잭션의 변경 사항을 취소한다.