# SQLite에서의 트랜잭션과 가상 테이블

> Clean Markdown view of GeekNews topic #20441. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=20441](https://news.hada.io/topic?id=20441)
- GeekNews Markdown: [https://news.hada.io/topic/20441.md](https://news.hada.io/topic/20441.md)
- Type: GN+
- Author: [xguru](https://news.hada.io/@xguru)
- Published: 2025-04-21T09:14:03+09:00
- Updated: 2025-04-21T09:14:03+09:00
- Original source: [misfra.me](https://misfra.me/2025/sqlite-transactions-and-virtual-tables/)
- Points: 9
- Comments: 1

## Summary

SQLite의 **가상 테이블**은 쓰기 및 트랜잭션을 지원하며, `xUpdate`, `xSync`, `xCommit`, `xRollback` 등의 훅을 구현하여 사용합니다. 기본적으로 **롤백 저널**을 통해 원자성을 보장하며, 여러 데이터베이스 파일을 다룰 때는 **슈퍼 저널**을 사용하여 전체 커밋을 조정합니다. **2단계 커밋** 과정에서 `xSync`는 내구성을 보장하고, `xCommit`과 `xRollback`은 실패 없이 실행 가능한 정리 작업을 수행해야 합니다. 가상 테이블 작성자는 **`xSync`에 지속성 있는 작업을 포함**시켜야 하며, `xCommit`과 `xRollback`은 **항등성**을 유지해야 합니다.

## Topic Body

- **SQLite 가상 테이블도 쓰기 및 트랜잭션 지원이 가능**하며, `xUpdate`, `xSync`, `xCommit`, `xRollback` 등의 훅을 구현해 사용함  
- SQLite는 기본적으로 **롤백 저널 방식으로 원자성**을 보장하며, 여러 DB 파일을 다룰 때는 **슈퍼 저널**로 전체 커밋을 조정함  
- **가상 테이블도 SQLite의 트랜잭션 프로토콜에 포함**되어, `xSync` 실패 시 전체 트랜잭션을 롤백함  
- 커밋은 **2단계로 나뉘며, `xSync`는 실패 가능성 있는 작업**, `xCommit`은 단순 정리 작업만 수행해야 함  
- **`xCommit`과 `xRollback`은 항상 호출될 수 있으므로 실패 없이 실행 가능한 정리용 함수로 작성**해야 함  
  
---  
  
### SQLite의 가상 테이블과 트랜잭션 처리  
  
[이전 글](https://misfra.me/2025/virtual-tables-in-sqlite-with-go/)에서는 Go 언어를 통해 SQLite의 가상 테이블을 등록하고 쿼리하는 기본 방법을 소개했음. 이번 글에서는 **쓰기 가능하고 트랜잭션을 지원하는 가상 테이블 구현법**을 다룸.  
  
### 가상 테이블의 쓰기 및 트랜잭션 지원  
  
- SQLite의 가상 테이블 인터페이스는 **읽기 전용이 아님**  
- `xUpdate` 훅을 구현하면 **외부 데이터 소스에도 쓰기 가능**  
- 진정한 트랜잭션 일관성을 위해서는 다음과 같은 트랜잭션 훅 필요:  
  
  - **`xBegin`**: 트랜잭션 시작 알림  
  - **`xSync`**: 디스크에 안전하게 커밋하기 위한 준비 (여기서 실패하면 전체 롤백)  
  - **`xCommit`**: 최종 커밋 및 정리  
  - **`xRollback`**: 트랜잭션이 중단됐을 경우 롤백 수행  
  
- 일반 테이블 또는 다른 가상 테이블과 함께 수정될 때도 SQLite는 **모든 훅을 연동해 원자성을 보장**함  
  
### SQLite 트랜잭션의 내부 동작 방식  
  
#### 롤백 저널 (Rollback Journals)  
  
- SQLite는 기본적으로 **페이지를 덮어쓰기 전에 백업 파일(저널)에 저장**  
- 문제가 생기면 저널에서 복구하여 **원자성 보장**  
  
> 참고: SQLite는 WAL 모드도 지원하지만 이 글의 범위에서는 제외됨  
  
#### 슈퍼 저널 (Super-Journals)  
  
- 여러 데이터베이스가 연결된 경우, **각 DB에 개별 저널만으로는 동기화 어려움**  
- **슈퍼 저널**이라는 상위 레벨 파일을 통해 여러 파일 간 커밋을 조정  
- 한 DB 파일 내 여러 가상 테이블만 다루는 경우는 **슈퍼 저널 없이도 동기화 가능**  
  
- 어떤 경우든 SQLite는 **트랜잭션 흐름 안에서 `xSync`, `xCommit`, `xRollback` 훅을 자동으로 호출**  
  
### 가상 테이블과 함께하는 2단계 커밋  
  
SQLite의 커밋 과정은 2단계로 이루어짐:  
  
#### 1단계: `xSync` (Durability 보장)  
  
- 모든 B-Tree 및 DB 파일의 페이지 또는 저널을 **디스크에 안전하게 동기화**  
- 가상 테이블도 각각 `xSync` 훅이 호출됨  
- **어느 한 `xSync`에서 실패하면 전체 트랜잭션이 롤백됨** → 원자성 유지  
  
#### 2단계: 정리 (`xCommit`)  
  
- 디스크에 저장이 완료되면 **저널 파일을 삭제하고 가상 테이블 정리 수행**  
- 아래는 [`vdbeaux.c`](https://github.com/sqlite/sqlite/blob/dc2d79f80fab9bda99ad95f4c7de752feefa927a/src/vdbeaux.c#L3141-L3159) 코드 일부임  
  ```cpp   
  disable_simulated_io_errors();  
  sqlite3BeginBenignMalloc();  
  for(i=0; i&lt;db-&gt;nDb; i++){  
    Btree *pBt = db->aDb[i].pBt;  
    if( pBt ){  
      sqlite3BtreeCommitPhaseTwo(pBt, 1);  
    }  
  }  
  sqlite3EndBenignMalloc();  
  enable_simulated_io_errors();  
  sqlite3VtabCommit(db);  
  ```  
  
- `sqlite3VtabCommit()` 안에서 실제로는 **모든 `xCommit` 호출이 실패해도 무시됨** → 순수한 정리 단계  
  ```cpp   
  int sqlite3VtabCommit(sqlite3 *db){  
    callFinaliser(db, offsetof(sqlite3_module,xCommit));  
    return SQLITE_OK;  
  }  
  ```  
  
- `xSync`로 내구성이 확보됐기 때문에, **`xCommit`, `xRollback`은 실패해도 무시됨**  
  
### 가상 테이블 작성자를 위한 주의사항  
  
- **지속성 있는 작업은 반드시 `xSync`에 넣어야 함**  
  - 네트워크 I/O, 파일 쓰기 등 실패할 수 있는 작업은 여기서 처리해야 트랜잭션이 안전하게 중단됨  
- **`xSync` 후에도 `xRollback`이 호출될 수 있음**  
  - 다른 테이블의 `xSync`가 실패하면 전체 롤백됨  
- **`xCommit`과 `xRollback`은 실패하지 않는 정리용 함수로 작성**  
  - **idempotent(항등성)**하게, 여러 번 호출돼도 상태 변화가 없어야 함  
  
### 결론  
  
- SQLite의 저널링 메커니즘은 **기본 테이블과 가상 테이블을 포함한 모든 요소의 원자성 커밋을 보장**  
- 가상 테이블의 트랜잭션 훅은 SQLite 트랜잭션 흐름에 **자연스럽게 통합**됨  
- 가상 테이블을 구현하는 개발자는 **`xSync`에 집중하여 데이터 무결성을 확보**하고, 정리 작업은 `xCommit`, `xRollback`으로 나눠야 함

## Comments



### Comment 37397

- Author: neo
- Created: 2025-04-21T09:14:03+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=43719830) 
- vtabs에 대한 글을 보니 좋음. 나는 Rust로 SQLite를 재구현하면서 vtab 지원을 구현했음. 그래서 최근에 vtab에 대해 많은 것을 배웠음. vtab은 매우 강력하고 아마도 충분히 활용되지 않음
- 흥미로움. 하지만 이것은 mattn의 go-sqlite3 패키지를 사용함. 이는 CGO임
  - 현대 GO에서 이것이 일반적이거나 예상되는 요구사항인지 궁금함
