기술 · 실용 가이드
Python sqlite3의 “cannot start a transaction within a transaction”은 소유자부터 찾으세요
잠금 대기 시간 초과가 아니라 같은 연결에 이미 활성 트랜잭션이 있다는 뜻입니다. Python 모드를 기록하고 하나의 외부 트랜잭션이나 SAVEPOINT를 사용하세요.

SQLite는 활성 트랜잭션 안의 BEGIN을 거부합니다. 첫 트랜잭션은 autocommit=False, 레거시 isolation_level, 바깥 helper 또는 스크립트가 열었을 수 있습니다.
commit을 여기저기 추가하기 전에 autocommit, isolation_level, in_transaction을 기록하고 작업 단위 소유자를 정하세요.
실패한 BEGIN 지점의 증거를 고정하세요
실패한 SQL, autocommit, isolation_level, in_transaction과 같은 연결에서 직전에 실행한 DML, BEGIN, SAVEPOINT, executescript, commit, rollback을 기록하세요.
호출 스택에서 가깝다는 이유로 소유자를 추정하지 마세요. 바깥 컨텍스트 관리자나 연결 정책이 이미 트랜잭션을 열었을 수 있습니다.
외부 트랜잭션 소유자는 하나만 선택하세요
애플리케이션 소유 모델에서는 호출자가 작업 단위를 열고 닫으며 하위 helper는 BEGIN이나 COMMIT을 실행하지 않습니다. 드라이버 소유 모델에서는 연결 정책과 commit/rollback을 사용합니다.
스크립트에 BEGIN/COMMIT이 들어 있다면 다시 바깥에서 감싸지 마세요. 의도적으로 중간에 실패시켜 롤백 경계를 검증하세요.
의도한 중첩에는 SAVEPOINT를 사용하세요
내부 범위만 되돌려야 한다면 고유한 이름의 SAVEPOINT를 만들고 성공 시 RELEASE, 실패 시 ROLLBACK TO 다음 RELEASE를 실행하세요.
재사용 가능한 라이브러리는 자신이 소유하지 않은 외부 트랜잭션을 보통 commit하면 안 됩니다.
BEGIN IMMEDIATE는 잠금 시점 선택입니다
BEGIN IMMEDIATE는 쓰기 잠금을 더 일찍 획득할 뿐이며 같은 연결의 활성 트랜잭션 안에서는 여전히 실행할 수 없습니다.
레거시 모드의 DML이 이미 DEFERRED를 열었다면 앞선 작업이 같은 단위인지 판단한 뒤 유지, commit 또는 경계 재설계를 선택하세요.
commit과 rollback 경계를 증명하세요
첫 쓰기 다음에 의도적으로 실패하는 테스트를 만들어 예상한 작업 단위 전체가 롤백되는지 확인하고, 성공 경로와 중첩 helper도 시험하세요.
API 경계에서 in_transaction을 확인해 모드나 기본값 변경을 조기에 드러내세요.
