メインコンテンツまでスキップ

書き込みの原子性と同時実行

Nested writecreate の中の posts: { create: [...] } など)や、onDelete / onUpdateCascade は、1 回の操作で複数のシートに書き込みます。このページでは、こうした操作で何が保証され、何が保証されないかを説明します。

エラー時には何も書かれない

複数シートに書く操作は、内部で書き込みをバッファし、操作全体が成功したときにまとめてシートに書き込みます。途中でエラーになった場合、シートには 1 行も書かれません

// 子の作成でエラーになる場合
gassma.Users.create({
data: {
id: 4,
name: "Dave",
posts: {
create: [{ id: 4, titel: "..." }], // 列名の誤りでエラー
},
},
});
// → エラー。Users にも Posts にも何も書かれない

これは、Prisma が nested write を暗黙のトランザクションで包むのと同じ保証です。

この保証が及ばないケース

書き込み中にスプレッドシートの API が失敗した場合

バッファをシートに書き出している最中に Google スプレッドシートの API が失敗すると、そこまでの書き込みはシートに残ります

$transactionrollback: true(既定)で使うと、書き込み前のバックアップから自動復元されます(詳細は rollback を参照)。

操作中に他のプロセスや人がシートを書き換えた場合

GASsma は、更新・削除する行を位置(行番号)で特定します。対象の行を読んでから書き込むまでの間に、他の誰かが行を挿入・削除すると、意図した行とは別の行に書き込む可能性があります。

GASsma が読んだ時点:  1行目 Alice / 2行目 Bob / 3行目 Carol
→ 「3行目の Carol を更新しよう」

他の誰かが 1行目を削除: 1行目 Bob / 2行目 Carol

GASsma が書き込む: 3行目に書く → そこには誰もいない、あるいは別の行

複数シートに書く操作は、バッファするぶん読んでから書くまでの間隔が長くなります。同時に書き込みが起こる環境では、この点を意識してください。

同時に書き込みが起こりうるなら $transaction で包む

同時に書き込みが起こりうるシステムでは、書き込みを $transaction で包んでください。

gassma.$transaction((tx) => {
tx.Users.create({
data: {
id: 4,
name: "Dave",
posts: {
create: [{ id: 4, title: "Dave の記事", published: true }],
},
},
});
});

$transaction はロックを取得するため、GASsma を経由する書き込みどうしは直列化されます。上の「読んでから書くまで」の割り込みが GASsma の書き込みによって起こることはなくなります。

注意

このロックが直列化するのは GASsma を使う処理どうしだけです。以下には効きません。

  • 人がスプレッドシートを手で編集した場合
  • GASsma を使っていない別のスクリプトが書き込んだ場合

これらに対しては GASsma からは何もできません。操作中にシートが手編集される可能性がある場合は、そもそも同時に触らない運用にする編集を受け付けない時間帯に処理するといった、設計側の対処が必要です。