이 글을 읽기 전에 트랜잭션에 관해 작성한 글을 읽는 것을 추천한다.
오늘 회사에서 운영 업무를 하며, 게시글 하나를 지워 달라는 요청이 들어왔다.
해당 게시글이 DB에서 갖고 있는 Column 중 하나를 UPDATE만 해주면 되는 간단한 요청이었다.
그런데 두 시간 걸렸다.
데이터 수정 작업이다 보니 BEGIN TRAN을 사용하여 데이터를 바꾸고 애플리케이션 작동이 잘 되는지 확인하려고 했다.
그런데 해당 데이터를 사용하는 화면의 게시글들을 불러오는 쿼리에서 계속 멈춰있었다.
해당 쿼리를 SSMS나 DBeaver같은 DB 클라이언트 툴에서 실행해보면 잘 돌아가는데 말이다.
BEGIN TRAN ?
Begin Transaction이라는 뜻으로, MSSQL에서 제공하는 보호 기능이다.
무엇을 보호하냐?
데이터를 Insert, Update, Delete를 할 때 해당 쿼리를 날린 사용자와 데이터를 보호한다.
예를 들어, Person이라는 테이블의 PK인 NUM 컬럼의 값이 1인 레코드의 NAME을 수정해달라는 요청이 들어왔다고 하자.
BEGIN TRAN을 사용하지 않으면 아래처럼 작성하면 된다.
UPDATE PERSON
SET NAME='헬창'
WHERE NUM=1
그런데 만약 쿼리를 잘못 작성해서 수정되면 안되는 데이터들까지 바뀐다면?
Update가 아니라 Delete였다면?
데이터를 미리 백업 받아놨으면 몰라도, 그렇지 않으면 식은땀 줄줄 흐르는 상황이다.
이럴 때, 사용하는 것이 BEGIN TRAN이다.
사용 방식은 아래 코드처럼 굉장히 간단한데, 실행 시킬 쿼리 가장 앞에 BEGIN TRAN을 써주고 실행시킨다.
그렇게 되면 DB의 데이터가 원하는 대로 바뀌지만,
ROLLBACK 명령어를 실행시켜 원래 상태로 돌아가거나,
COMMIT 명령어를 실행시켜 현재 상태를 저장하고 끝낼 수 있는 상태가 된다.
이를 MS 공식 문서에서는 로컬 트랜잭션이라고 표현하고 있다.
BEGIN TRAN
UPDATE PERSON
SET NAME='헬창'
WHERE NUM=1
/* 정상적으로 시스템이 동작하면 */
COMMIT
/* 비정상적으로 시스템이 동작하면 */
ROLLBACK
주석의 내용처럼 UPDATE를 하고 난 후에,
다른 데이터들에 문제가 없다면 COMMIT을 실행시켜 저장하면 되고, 문제가 있다면 ROLLBACK을 실행시켜 원래대로 돌아가면 된다.
내가 한 삽질
위에 링크 걸어놓은 MS 공식 문서를 보면 일반적인 주의 사항이라는 부분에 이런 말이 나온다.
"BEGIN TRANSACTION은 해당 문을 실행한 연결에 대해 로컬 트랜잭션을 시작합니다.
현재 트랜잭션 격리 수준 설정에 따라,
해당 연결에서 실행한 Transact-SQL 문을 지원하기 위해 획득한 리소스는
트랜잭션이 COMMIT TRANSACTION 또는 ROLLBACK TRANSACTION 문으로 완료될 때까지 잠금 상태가 됩니다.
트랜잭션이 장기간 처리 중이면 다른 사용자가 이러한 잠긴 리소스에 액세스 할 수 없고 로그가 잘리지 않을 수도 있습니다."
!!
내가 이해한 바로는,
BEGIN TRAN으로 쿼리를 실행하면 로컬 트랜잭션이라는 공간이 생기며, 그 공간은 액세스할 수 없다는 것이다.
내가 한 실수가 여기에 있었다.
COMMIT을 쳐서 실제 DB에 반영을 확실히 하던가,
데이터를 미리 백업해 두고 BEGIN TRAN을 빼고 UPDATE를 실행했어야 했다.
끝!