개발노트

SQLite 파일을 복사했는데 기록이 없습니다: WAL 백업과 복구 실습

파일 복사가 성공해도 기록이 빠질 수 있습니다. 원본은 그대로 두고 잘못된 복사본과 정상 백업을 나란히 열어 차이를 확인합니다.

백업 파일이 있고 오류 없이 열리기까지 하는데, 정작 기록이 비어 있다면 어떨까요? 이번에는 이 상황을 임시 SQLite DB에서 직접 만들었습니다. 2026년 10월 23일 실행한 결과, 본체 파일만 복사한 DB에는 0건, 백업 API로 만든 복구본에는 3건이 있었습니다.

기록이 사라진 복사본부터 열어봤습니다

실습은 빈 테이블을 DB 본체에 반영한 다음, WAL 모드에서 가짜 기록 세 건을 저장합니다. 원본 연결은 열어둔 채 본체 파일만 복사합니다. 복사 과정에는 오류가 없지만 새 복사본에서 조회한 기록 수는 0입니다. 이번 조건에서는 테이블 구조는 본체에, 새 기록은 WAL에 있었기 때문입니다.

대상조회 결과
열려 있는 원본3건
본체만 복사한 naive-copy.db0건
백업 API를 거쳐 만든 restored.db3건

이것은 파일 복사가 언제나 실패한다는 뜻은 아닙니다. 재현 조건을 만들기 위해 자동 체크포인트를 끄고, 테이블 생성 뒤에 체크포인트를 실행했습니다. 이 설정은 임시 DB에만 적용했습니다. 운영 설정을 바꾸지 않고도 차이를 확인할 수 있습니다.

SQLite WAL 문서에서 WAL이 DB 상태의 일부라는 설명을 확인할 수 있습니다. 실행 중인 본체와 WAL을 각각 복사하면 복사 시점이 달라질 수 있으므로, 두 파일을 찾았다는 것만으로 백업이 완성되지는 않습니다.

같은 원본을 backup()으로 복사합니다

이번에는 SQLite가 제공하는 백업 기능을 사용했습니다. Python에서는 원본 연결에서 reader.backup(destination)을 호출합니다. 괄호 안의 destination이 덮어쓸 대상이므로 방향을 먼저 확인합니다.

with closing(sqlite3.connect(source.as_uri() + "?mode=ro", uri=True)) as reader:
    with closing(sqlite3.connect(backup)) as destination:
        reader.backup(destination)

이 부분만 떼어 실행하기보다 전체 실습 코드를 사용하세요. 코드는 Python 표준 라이브러리만 쓰며 실행할 때 새 임시 폴더를 만듭니다. 기존 DB 경로를 받지 않고, 실습이 끝나면 임시 파일을 정리합니다.

python3 sqlite-backup-demo.py

복구본이 백업 시점의 값인지 확인했습니다

백업을 만든 다음 원본의 첫 값을 draft에서 changed로 바꿨습니다. 그 후 백업에서 별도 restored.db를 만들었습니다. 원본을 덮어쓰는 대신 새 DB에서 세 건의 ID와 상태를 모두 비교했습니다.

main_file_only_copy_rows: 0
restored_rows: 3
source_status_after_change: changed
restored_status: draft
integrity_check: ok
matches_backup_time_data: true

위 값은 SQLite 3.45.1 환경에서 실제로 나온 결과입니다. 원본은 changed로 바뀌었지만 복구본은 draft를 유지했습니다. 단순히 건수가 같은지만 본 것이 아니라 백업 당시의 세 건과 전체 값을 비교했습니다. 이 시험에는 실제 게시글이나 문의 데이터가 들어가지 않았습니다.

ok가 나와도 확인해야 할 것이 남습니다

PRAGMA integrity_check는 구조 검사입니다. 이번에 내용이 비어 있던 복사본처럼 정상적인 빈 DB도 구조 검사를 통과할 수 있습니다. 원하는 데이터가 있는지는 실제 조회로 확인해야 합니다. 외래 키 위반은 별도 foreign_key_check 대상입니다.

DB가 사진 경로만 보관한다면 사진 파일은 이 백업에 포함되지 않습니다. 운영 복구를 준비할 때는 업로드 파일, 앱 버전과 설정도 함께 목록으로 남겨야 합니다. 여기서 검증한 것은 작은 DB의 복사·복구 경로이며 대용량 동시 쓰기나 실제 서비스 전환은 시험하지 않았습니다.

실습의 성공 기준은 간단합니다. 본체만 복사한 결과가 0건이고, 정상 백업에서 복구한 값은 원본 변경 전 세 건과 같아야 합니다. 자신의 운영 DB를 건드리기 전에 이 결과부터 확인해보세요.

구현 근거: Python Connection.backup(), SQLite 무결성 검사.

실전노트 목록 문의하기

댓글

0개

아직 표시된 댓글이 없습니다.

Google 계정으로 댓글 작성

이메일은 일부를 가린 아이디로 표시됩니다.