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 강좌 / GROUP BY·HAVING으로 묶고 집계 결과 걸러내기

MariaDB 강좌 / GROUP BY·HAVING으로 묶고 집계 결과 걸러내기

GROUP BY로 분류별 상품 수·재고·금액을 계산하고 HAVING으로 그룹을 제한합니다. WHERE 적용 시점과 비집계 열·SQL 모드·NULL 그룹의 주의점을 비교 실습으로 설명합니다.

MariaDB 강좌 / 조회 종합 실습: 월별 매출·고객별 구매·미판매 상품

MariaDB 강좌 / 조회 종합 실습: 월별 매출·고객별 구매·미판매 상품

월별 paid 매출, 미구매 포함 고객별 구매 금액, 미판매 상품 조회를 종합 실습합니다. 주문·상세 단위와 취소 정책을 정하고 세 결과의 전체 금액을 교차 검증합니다.

MariaDB 강좌 / 백업을 별도 데이터베이스에 복원하고 검증하기

MariaDB 강좌 / 백업을 별도 데이터베이스에 복원하고 검증하기

새 원본과 별도 빈 DB를 준비해 덤프를 복원하고 객체·행 수·키·업무 합계를 비교합니다. 파일 안의 DB 전환·삭제 문장, 클라이언트 호환성과 부분 복원 실패의 대응을 설명합니다.

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

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

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

MariaDB 강좌 / 날짜와 시간 저장하기: DATE·DATETIME·TIMESTAMP

MariaDB 강좌 / 날짜와 시간 저장하기: DATE·DATETIME·TIMESTAMP

DATE·DATETIME·TIMESTAMP의 저장 의미와 시간대 처리를 비교합니다. 동일 입력의 한국 시간·UTC 조회 결과, 버전별 TIMESTAMP 범위, 날짜 오류와 설정 복원을 실습합니다.

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

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

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

MariaDB 강좌 / WHERE로 조건 지정하기: 비교·AND·OR·IN·BETWEEN·LIKE

MariaDB 강좌 / WHERE로 조건 지정하기: 비교·AND·OR·IN·BETWEEN·LIKE

상품 가격·분류·재고·이름으로 WHERE 조건을 실습합니다. AND·OR 괄호 차이, IN 목록, BETWEEN 경계, LIKE 와일드카드와 실제 퍼센트 검색을 예상 행 번호로 확인합니다.

MariaDB 강좌 / 로컬·원격 접속과 연결 오류 해결하기

MariaDB 강좌 / 로컬·원격 접속과 연결 오류 해결하기

로컬 TCP 연결을 명시하고 서버 정보·현재 계정·실제 테이블 권한을 확인합니다. 연결 거절·인증·DB 오류를 나누어 진단하고 원격 수신 주소·계정·TLS의 적용 조건을 설명합니다.

MariaDB 강좌 / ORDER BY·LIMIT로 정렬하고 조회 범위 제한하기

MariaDB 강좌 / ORDER BY·LIMIT로 정렬하고 조회 범위 제한하기

ORDER BY의 여러 열·방향과 LIMIT·OFFSET을 같은 가격의 상품으로 실습합니다. 동점 해소, 페이지 경계 변화, 마지막 정렬값을 이용한 조회와 NULL 배치를 설명합니다.

MariaDB 강좌 / SELECT로 열 선택하기: 별칭·계산식·DISTINCT

MariaDB 강좌 / SELECT로 열 선택하기: 별칭·계산식·DISTINCT

SELECT의 열 선택과 AS 별칭, 행별 계산식, DISTINCT의 열 조합 기준을 실습합니다. 원본 데이터와 출력 결과를 구분하고 WHERE에서 별칭을 사용할 때의 주의점을 설명합니다.