데이터데이터베이스
트랜잭션
세션 하나 안에서는 평범한 PostgreSQL 트랜잭션입니다. 세션 밖에는 트랜잭션이 없습니다.
되는 것
const s = await env.db.session();
try {
await s.exec("begin");
await s.exec("update accounts set balance = balance - $1 where id = $2", [100, 1]);
await s.exec("update accounts set balance = balance + $1 where id = $2", [100, 2]);
await s.exec("commit");
} catch (e) {
await s.exec("rollback");
throw e;
} finally {
await s.close();
}BEGIN·COMMIT·ROLLBACKSAVEPOINT와 그 되돌리기SET TRANSACTION ISOLATION LEVEL- 여섯 ORM 의 트랜잭션 API 전부
- 세션 안의
SET, temp table,PREPARE
안 되는 것
env.db.exec 을 두 번 부르는 것 사이에는 트랜잭션이 없습니다. 호출마다 새 세션이라 BEGIN 이 다음 호출로 이어지지 않습니다. @runlot/pg 의 pool.query() 도 같습니다 — 트랜잭션에는 pool.connect() 를 쓰세요.시간
now() 는 트랜잭션이 시작된 시각입니다. 트랜잭션 안에서 여러 번 불러도 같은 값입니다. 벽시계가 필요하면 clock_timestamp() 를 쓰세요.
길게 잡지 마세요
한 프로젝트의 데이터베이스는 차선이 하나입니다. 긴 트랜잭션은 그 프로젝트의 다른 요청을 대기열에 세웁니다. 트랜잭션 안에서 외부 API 를 부르는 것 같은 일은 피하세요.
세션은 문장 없이 30 초가 지나면 회수되고, 열려 있던 블록은 롤백됩니다. 요청 하나의 수명 안에서 열고 닫으시면 됩니다.
실패를 코드로 읽기
const r = await s.tryExec("insert into users (email) values ($1)", [email]);
if (!r.ok && r.error.code === "23505") {
await s.exec("rollback");
return new Response("이미 있는 이메일입니다", { status: 409 });
}Prisma 만 unique 위반을 P2002 로 바꿔 줍니다. 나머지는 SQLSTATE 23505 그대로입니다.