AD JB Toolbox 01

MariaDB 강좌 / UPDATE·DELETE를 실행하기 전 대상 행 확인하기

UPDATE는 기존 행의 값을 바꾸고 DELETE는 조건에 맞는 행을 삭제합니다. 실행 전 같은 WHERE 조건으로 대상과 현재 값을 확인하고, InnoDB 트랜잭션 안에서 변경 결과를 검증한 뒤 COMMIT 또는 ROLLBACK을 선택해야 실수의 범위를 줄일 수 있습니다.

변경 전에 대상·복구 범위·확정 시점 정하기

이 실습은 수정과 삭제를 각각 시험한 뒤 모두 ROLLBACK으로 취소합니다. 운영 데이터 복구를 보장하는 절차가 아니라, 독립된 연습 테이블에서 대상 확인과 확정 전 검증을 배우는 예제입니다. 중요한 실제 변경에는 별도의 백업·복구 검증과 권한·동시 작업 정책이 필요합니다. 확정·취소의 범위는 트랜잭션 시작하기: InnoDB·COMMIT·ROLLBACK, 동시 연결에서 대기·충돌을 관찰하는 방법은 두 연결로 격리 수준·잠금·교착 상태 확인하기에서 별도 실습합니다.

확인 항목 확인 방법 이유
대상 서버·DB 접속 정보, SELECT DATABASE() 잘못된 서버 변경 방지
저장 엔진 SHOW CREATE TABLE 이 예제는 InnoDB 사용
대상 행 같은 WHERE의 SELECT 이름이 아니라 고유 번호와 현재값 확인
변경 결과 즉시 ROW_COUNT(), 재조회 건수·수정값 확인
확정 여부 COMMIT 또는 ROLLBACK 이 연결의 트랜잭션 종료

WHERE가 없는 UPDATE·DELETE는 모든 행을 대상으로 합니다. 실습을 위해 운영 테이블에서 무조건 실행하거나, LIMIT만 붙였으니 안전하다고 생각하지 않습니다. 프로그램의 확인 화면을 거쳐도 실제 변경 직전 조건을 다시 평가해야 합니다.

InnoDB 연습 테이블과 연결 상태 확인하기

명령줄 클라이언트에서 course_user로 학습용 서버에 접속하고 shopcourse 데이터베이스를 준비합니다. 접속과 UTF-8 SQL 파일 실행 방법은 명령줄 클라이언트와 SQL 파일 실행 안내를 참고하세요. 아래 코드는 운영 서버가 아닌 연습 환경에서 실행합니다.

이 글은 products_18_lab이라는 독립된 실습 테이블을 사용합니다. 이전 강좌의 products 등 기존 테이블에는 손대지 않습니다. SELECT VERSION(), DATABASE();와 SHOW TABLES LIKE 'products_18_lab';로 서버·선택한 데이터베이스·이름 중복을 먼저 확인합니다. 같은 이름이 이미 있으면 정의와 데이터를 확인하고, 이 글에서 만든 연습 데이터인지 판단한 뒤 마지막 절의 반복 방법을 따르세요.

USE shopcourse;
CREATE TABLE products_18_lab (
  product_id INT NOT NULL AUTO_INCREMENT,
  product_name VARCHAR(100) NOT NULL,
  category VARCHAR(30) NOT NULL,
  price DECIMAL(10,2) NOT NULL,
  stock INT NOT NULL DEFAULT 0,
  note VARCHAR(100) NULL DEFAULT NULL,
  PRIMARY KEY (product_id),
  CONSTRAINT ck_p18_price CHECK (price >= 0),
  CONSTRAINT ck_p18_stock CHECK (stock >= 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO products_18_lab
  (product_id, product_name, category, price, stock, note)
VALUES (1, '노트', '문구', 3500.00, 20, NULL),
  (2, '볼펜', '문구', 1500.00, 0, ''),
  (3, '머그컵', '생활', 8000.00, 12, '선물 포장'),
  (4, '스탠드', '생활', 25000.00, 5, NULL),
  (5, '파일', '문구', 1500.00, 50, ''),
  (6, '케이블', '전자', 8000.00, 0, '호환 확인');
SELECT DATABASE() AS selected_database, @@autocommit AS autocommit_mode;
SHOW CREATE TABLE products_18_lab;

SHOW CREATE TABLE 결과에서 ENGINE=InnoDB를 확인합니다. autocommit=1이어도 명시적인 START TRANSACTION 이후의 해당 트랜잭션은 COMMIT·ROLLBACK으로 끝낼 수 있습니다. 모든 문장은 같은 연결에서 실행해야 하며, 도구가 문장마다 새 연결을 열거나 자동 확정하는 설정이면 이 절차를 그대로 사용할 수 없습니다. 테이블 생성은 트랜잭션 실습을 시작하기 전에 끝냅니다.

재고 수정 전에 행을 잠그고 바뀐 값 확인하기

노트의 재고가 20일 때 3개 줄이는 상황입니다. 먼저 번호와 예상 재고로 조회하고, 트랜잭션을 시작한 뒤 같은 조건을 FOR UPDATE로 다시 읽습니다. 실행 사이 다른 연결이 재고를 바꿨다면 기대한 행이 없을 수 있으므로, 자동으로 조건을 완화하지 말고 멈춰 원인을 확인합니다.

SELECT product_id, product_name, stock FROM products_18_lab
WHERE product_id = 1 AND stock = 20;
START TRANSACTION;
SELECT product_id, product_name, stock FROM products_18_lab
WHERE product_id = 1 AND stock = 20 FOR UPDATE;
UPDATE products_18_lab SET stock = stock - 3
WHERE product_id = 1 AND stock = 20;
SELECT ROW_COUNT() AS changed_rows;
SELECT product_id, stock FROM products_18_lab WHERE product_id = 1;
ROLLBACK;
SELECT product_id, stock FROM products_18_lab WHERE product_id = 1;

초기 데이터에서는 changed_rows=1이고, 트랜잭션 안의 재고는 17입니다. ROLLBACK 뒤에는 다시 20이 됩니다. SET stock = stock - 3은 현재 값을 기준으로 계산하고 WHERE product_id = 1 AND stock = 20은 조회 때 기대한 값이 유지되는지 다시 제한합니다. 잠금은 트랜잭션을 끝낼 때까지 유지되므로 작업 중 사용자 입력을 오래 기다리게 만들지 않습니다.

FOR UPDATE의 잠금 범위는 인덱스·격리 수준·조건 등에 영향을 받습니다. 이 예제는 기본키 한 행을 다루며, 모든 변경 충돌이나 교착 상태가 사라진다는 뜻은 아닙니다. 오류나 시간 초과가 나면 결과를 재확인하고 해당 트랜잭션을 명시적으로 끝냅니다. FOR UPDATE의 트랜잭션 적용 조건도 함께 확인하세요. UPDATE 공식 문서에서 SET과 WHERE의 역할을 확인하세요.

삭제 대상과 삭제 후 행 수를 확인하고 되돌리기

재고가 없는 모든 상품을 지우는 대신 번호 2인 볼펜 한 행만 대상으로 정합니다. 6번 케이블도 재고가 0이지만 이 예제의 삭제 대상은 아닙니다. 이름이나 수량만으로 대상을 넓히는 실수를 피하기 위해 고유 번호와 확인한 값을 함께 사용합니다.

SELECT product_id, product_name, stock FROM products_18_lab
WHERE product_id = 2 AND stock = 0;
START TRANSACTION;
SELECT product_id, product_name, stock FROM products_18_lab
WHERE product_id = 2 AND stock = 0 FOR UPDATE;
DELETE FROM products_18_lab WHERE product_id = 2 AND stock = 0;
SELECT ROW_COUNT() AS deleted_rows;
SELECT COUNT(*) AS rows_inside_transaction FROM products_18_lab;
ROLLBACK;
SELECT COUNT(*) AS rows_after_rollback FROM products_18_lab;

deleted_rows=1, 삭제 직후 전체 행 수는 5, ROLLBACK 뒤 행 수는 6입니다. 마지막에는 SELECT * FROM products_18_lab WHERE product_id = 2;로 볼펜이 복구되었는지도 확인합니다. DELETE는 선택한 행을 지우는 작업이며 테이블의 열 구조를 없애지 않습니다. DELETE 공식 문서에서 WHERE가 없을 때의 범위를 확인할 수 있습니다.

영향받은 행 수가 0일 때 판단하기

START TRANSACTION;
UPDATE products_18_lab SET stock = stock
WHERE product_id = 1;
SELECT ROW_COUNT() AS changed_rows;
ROLLBACK;

기본 명령줄 연결에서 재고를 같은 값으로 대입하면 실제 바뀐 행이 없어 changed_rows는 0입니다. 따라서 0이 항상 상품이 없다는 뜻은 아닙니다. 대상 부재·현재값 조건 불일치·같은 값 대입을 재조회로 구분합니다. 클라이언트가 CLIENT_FOUND_ROWS 옵션을 사용하면 일치한 행 수를 보고할 수 있으므로 드라이버 설정도 확인해야 합니다. ROW_COUNT 공식 문서에서 두 계산 방식의 차이를 확인할 수 있습니다.

ROW_COUNT()는 변경 직후 다른 문장보다 먼저 읽습니다. 예상보다 많거나 적으면 COMMIT하지 말고 ROLLBACK한 뒤 같은 조건의 SELECT부터 다시 점검합니다. 실제로 확정하는 별도 작업에서는 취소 대신 COMMIT을 선택하고 확정 후 다시 조회해야 합니다. 이 글의 정상 파일은 연습 결과를 남기지 않기 위해 COMMIT을 포함하지 않습니다.

ROLLBACK으로 되돌릴 수 없는 경계 확인하기

ROLLBACK은 아직 확정하지 않은 해당 연결의 트랜잭션 작업을 되돌립니다. 이미 COMMIT한 변경, autocommit으로 끝난 변경, 비트랜잭션 엔진의 변경까지 이전 상태로 돌려 주지는 않습니다. CREATE·DROP·TRUNCATE 같은 구조 변경은 암묵적 확정과 별도 동작이 있으므로 취소 실습 사이에 섞지 않습니다.

safe-updates 설정에 의해 실행이 막히면 안전 장치를 무조건 끄지 말고 기본키 조건과 쿼리 범위를 먼저 확인합니다. 운영에서 실수로 확정한 삭제를 발견했다면 추가 쓰기를 멈추고 백업·로그를 이용한 복구 가능성을 담당자와 판단해야 합니다. 반대 값을 한 번 UPDATE하면 언제나 정확히 복원된다고 가정하지 않습니다.

다시 실습하려면 SELECT DATABASE();, SHOW CREATE TABLE products_18_lab;와 저장된 행을 확인합니다. 보관할 데이터가 없는 이 글의 연습 테이블이 확실할 때만 아래 문장으로 지운 뒤 준비 코드를 다시 실행합니다. DROP TABLE은 구조와 데이터를 함께 없애며 일반적인 ROLLBACK으로 취소되지 않습니다.

DROP TABLE shopcourse.products_18_lab;
같은 카테고리의 다른 글
MariaDB 강좌 / 숫자 계산과 타입 변환: ROUND·CAST

MariaDB 강좌 / 숫자 계산과 타입 변환: ROUND·CAST

ROUND와 CAST를 할인 금액·정확한 소수·숫자 문자열로 실습합니다. 반올림 시점, 앞자리 0 손실, 잘림 경고와 SQL 모드에 따른 저장 동작의 차이를 설명합니다.

MariaDB 강좌 / ALTER TABLE로 구조 변경하기: 열·제약 조건·변경 전 점검

MariaDB 강좌 / ALTER TABLE로 구조 변경하기: 열·제약 조건·변경 전 점검

ALTER TABLE을 새 코드 열 추가·기존 행 채우기·제약 적용으로 나누어 실습합니다. NULL·중복 사전 검사, MODIFY 속성 보존, 실제 실패 입력과 잠금·복구 계획을 설명합니다.

MariaDB 강좌 / NULL을 올바르게 비교하기: IS NULL·COALESCE

MariaDB 강좌 / NULL을 올바르게 비교하기: IS NULL·COALESCE

NULL·빈 문자열·0을 구분하고 IS NULL·IS NOT NULL과 COALESCE의 역할을 실습합니다. 일반 비교에서 빠지는 NULL 행, NULL-safe 비교와 NOT IN 목록의 함정을 설명합니다.

MariaDB / 연산자 / 논리 연산자

MariaDB / 연산자 / 논리 연산자

MariaDB의 논리 연산자에 대하여 알아보겠습니다. 예제로 사용하는 테이블은 아래의 데이터를 가진 T_2이라는 테이블입니다. 각 열의 데이터 형식은 다음과 같습니다. C_1 : 정수 C_2 : 문자 +----+------+------+ | ID | C_1 | C_2 | +----+------+------+ | 1 | 1 | A | | 2 | ...

MariaDB 강좌 / UPDATE·DELETE를 실행하기 전 대상 행 확인하기

MariaDB 강좌 / UPDATE·DELETE를 실행하기 전 대상 행 확인하기

UPDATE·DELETE 전에 기본키와 현재값으로 대상 행을 확인하고, InnoDB 트랜잭션에서 수정·삭제 결과를 검증한 뒤 취소합니다. 영향받은 행 수와 ROLLBACK의 적용 한계도 설명합니다.

MariaDB 강좌 / 명령줄 클라이언트로 접속하고 SQL 파일 실행하기

MariaDB 강좌 / 명령줄 클라이언트로 접속하고 SQL 파일 실행하기

터미널 명령과 SQL 입력 위치를 구분하고 학습 계정으로 접속합니다. UTF-8 SQL 파일의 SOURCE 실행, 예상 결과, 오류 중단·한글 표시·경로 문제를 함께 확인합니다.

MariaDB 강좌 / 날짜 계산하기: 기간·날짜 차이·표시 형식

MariaDB 강좌 / 날짜 계산하기: 기간·날짜 차이·표시 형식

기간 더하기, 날짜 차이와 시간 차이, 표시 형식을 고정 날짜로 비교합니다. 월말 조정과 함수별 인수 순서, 하루·한 달을 빠짐없이 조회하는 경계 조건을 설명합니다.

MariaDB 강좌 / 서버 설정·SQL 모드·시간대·로그 확인하기

MariaDB 강좌 / 서버 설정·SQL 모드·시간대·로그 확인하기

설정 파일·GLOBAL·SESSION의 차이를 기준으로 MariaDB 동작을 확인합니다. SQL 모드 오류와 TIMESTAMP·DATETIME 시간대 실습, 로그 조건 점검 및 변경 복구 절차를 제공합니다.

MariaDB 강좌 / EXPLAIN으로 실행 계획 읽고 인덱스 전후 비교하기

MariaDB 강좌 / EXPLAIN으로 실행 계획 읽고 인덱스 전후 비교하기

1000행 실습으로 인덱스 전후 EXPLAIN과 실제 반환 행을 비교합니다. ANALYZE FORMAT=JSON의 실행 정보와 통계 갱신을 구분하고 결과·환경을 기록합니다.

MariaDB / 사용자 관리하는 방법

MariaDB / 사용자 관리하는 방법

MariaDB에서 사용자를 만드는 방법, 수정하는 방법, 삭제하는 방법, 권한을 부여하고 제거하는 방법을 알아봅니다.