Durable Object Storage API を使うと、Durable Objects はトランザクション対応で強い一貫性を持つストレージにアクセスできます。Durable Object に付属するストレージは、その一意なインスタンス専用であり、ほかのオブジェクトからはアクセスできません。
Durable Object Storage API には、SQL、ポイントインタイムリカバリ(PITR)、キーバリュー(KV)、アラーム API など、いくつかのメソッドがあります。利用できる API メソッドは、Durable Objects クラスのストレージバックエンドが SQLite か KV かによって異なります。
| メソッド 1 | SQLite バックエンドの Durable Object クラス | KV バックエンドの Durable Object クラス |
|---|---|---|
| SQL API | ✅ | ❌ |
| PITR API | ✅ | ❌ |
| Synchronous KV API | ✅ 2, 3 | ❌ |
| Asynchronous KV API | ✅ 3 | ✅ |
| Alarms API | ✅ | ✅ |
脚注
1 各メソッドは暗黙的にトランザクションでラップされます。複数のキーバリューペアにアクセスする場合でも、結果はアトミックであり、ほかのストレージ操作から分離されます。
2 get()、put()、delete()、list() などの KV API メソッドは、隠し SQLite テーブル __cf_kv にデータを保存します。テーブル一覧ではこのテーブルを確認できますが、SQL API から中身へアクセスすることはできません。
3 SQLite バックエンドの Durable Objects は ctx.storage.kv を使う 同期 KV API メソッド も利用します。一方、KV バックエンドの Durable Objects が提供するのは 非同期 KV API メソッド だけです。
Durable Objects は DurableObjectStorage インターフェイス経由で Storage API にアクセスし、DurableObjectState::storage プロパティで使います。Durable Object のコンストラクターに渡される ctx パラメーターを使い、this.ctx.storage で参照することが多いです。
次のコードスニペットは、Durable Object Storage API でデータを保存・取得する方法を示します。
export class Counter extends DurableObject {
constructor(ctx, env) {
super(ctx, env);
}
async increment() {
let value = (await this.ctx.storage.get("value")) || 0;
value += 1;
await this.ctx.storage.put("value", value);
return value;
}
}export class Counter extends DurableObject {
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
}
async increment(): Promise<number> {
let value: number = (await this.ctx.storage.get('value')) || 0;
value += 1;
await this.ctx.storage.put('value', value);
return value;
}
}from workers import DurableObject
class Counter(DurableObject):
def __init__(self, ctx, env):
super().__init__(ctx, env)
async def increment(self):
value = (await self.ctx.storage.get('value')) or 0
value += 1
await self.ctx.storage.put('value', value)
return valueJavaScript はシングルスレッドのイベント駆動言語です。そのため JavaScript ランタイムは、デフォルトではリクエスト同士の実行が入り交じることがあり、並行性の不具合につながることがあります。Durable Objects ランタイムは、input gates と output gates を組み合わせて、ストレージ操作時にこの種の並行性の不具合を防ぎます。詳細は ブログ記事 ↗ を参照してください。
SqlStorage インターフェイスは、Durable Object に埋め込まれた SQLite データベースを変更するメソッドをまとめたものです。SqlStorage インターフェイスは、DurableObjectStorage クラスの sql プロパティ から使えます。
たとえば、sql.exec() でテーブルを作成し、行を挿入できます。
import { DurableObject } from "cloudflare:workers";
export class MyDurableObject extends DurableObject {
sql: SqlStorage;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.sql = ctx.storage.sql;
this.sql.exec(`
CREATE TABLE IF NOT EXISTS artist(
artistid INTEGER PRIMARY KEY,
artistname TEXT
);
INSERT INTO artist (artistid, artistname) VALUES
(123, 'Alice'),
(456, 'Bob'),
(789, 'Charlie');
`);
}
}from workers import DurableObject
class MyDurableObject(DurableObject):
def __init__(self, ctx, env):
super().__init__(ctx, env)
self.sql = ctx.storage.sql
self.sql.exec("""
CREATE TABLE IF NOT EXISTS artist(
artistid INTEGER PRIMARY KEY,
artistname TEXT
);
INSERT INTO artist (artistid, artistname) VALUES
(123, 'Alice'),
(456, 'Bob'),
(789, 'Charlie');
""")ctx.storage.sqlで使う SQL API メソッドは、SQLite ストレージバックエンドの Durable Object クラス でのみ使えます。KV ストレージバックエンドの Durable Object クラスで呼ぶとエラーが返ります。- データを書き込むとき、インデックスの行更新は追加の行としてカウントされます。ただし、読み取りが多い用途ではインデックスが有効な場合があります。Index for SQLite Durable Objects を参照してください。
- SQLite 仮想テーブル ↗ への書き込みも、書き込んだ行数にカウントされます。
Durable Objects support 追加機能として、次を含む SQLite 拡張の一部を利用できます。
- 全文検索向けの FTS5 モジュール ↗(
fts5vocabを含む)。 - JSON 関数と演算子向けの JSON 拡張 ↗。
- 数学関数 ↗。
対応している関数の一覧は、ソースコード ↗ を参照してください。
exec(query: : string, ...bindings: any[])SqlStorageCursor
query:string- 実行する SQL クエリ文字列です。
queryにはパラメーターバインディング用の?プレースホルダーを含められます。セミコロンで区切った複数の SQL 文をqueryで実行できます。複数の SQL 文がある場合、パラメーターバインディングはquery内の最後の SQL 文に適用され、返されるカーソルも最後の SQL 文だけが対象です。
- 実行する SQL クエリ文字列です。
...bindings:any[]Optionalquery内の?プレースホルダーに対応する、任意個の引数です。
クエリ結果の行をオブジェクトとして反復するためのカーソル(SqlStorageCursor)です。SqlStorageCursor は JavaScript の Iterable ↗ であり、for (let row of cursor) で反復できます。SqlStorageCursor は JavaScript の Iterator ↗ でもあり、cursor.next() でも反復できます。
SqlStorageCursor は次のメソッドをサポートします。
next()- カーソルの次の値を表すオブジェクトを返します。返されるオブジェクトには、JavaScript の Iterator ↗ に従う
doneとvalueプロパティがあります。次の値があるときはdoneはfalseで、valueはクエリ結果の次の行オブジェクトです。カーソルをすべて使い切るとdoneはtrueになり、valueは設定されません。
- カーソルの次の値を表すオブジェクトを返します。返されるオブジェクトには、JavaScript の Iterator ↗ に従う
toArray()- 残りのカーソル値を反復し、返された行オブジェクトの配列を返します。
one()- クエリ結果がちょうど 1 行のとき、その行オブジェクトを返します。0 行または 2 行以上の場合、
one()は例外を投げます。
- クエリ結果がちょうど 1 行のとき、その行オブジェクトを返します。0 行または 2 行以上の場合、
raw():Iterator- 同じクエリ結果に対する Iterator を返します。各行はオブジェクトではなく、列名なしの列値の配列です。
- 返される Iterator は、上記の
next()とtoArray()メソッドをサポートします。 - 返されるカーソルと
raw()イテレーターは同じクエリ結果を反復し、組み合わせて使えます。例:
let cursor = this.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;");
let rawResult = cursor.raw().next();
if (!rawResult.done) {
console.log(rawResult.value); // prints [ 123, 'Alice' ]
} else {
// query returned zero results
}
console.log(cursor.toArray()); // prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }]cursor = self.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;")
raw_result = cursor.raw().next()
if not raw_result.done:
print(raw_result.value) # prints [ 123, 'Alice' ]
else:
# query returned zero results
pass
print(cursor.toArray()) # prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }]SqlStorageCursor には次のプロパティがあります。
columnNames:string[]rawイテレーターが返す各行配列に現れる順の、クエリの列名です。
rowsRead:number- この SQL
queryでこれまでに読み取った行数です。カーソルを反復すると増えることがあります。最終値は SQL 課金 に使われます。
- この SQL
rowsWritten:number- この SQL
queryでこれまでに書き込んだ行数です。カーソルを反復すると増えることがあります。最終値は SQL 課金 に使われます。
- この SQL
- 列の数値は、JavaScript の数値の 52 ビット精度の影響を受けます。非常に大きな数(
int64)を保存して同じ値を取り出すと、元の数より精度が落ちることがあります。
以降の SQL API の例では、次の SQL スキーマを使います。
import { DurableObject } from "cloudflare:workers";
export class MyDurableObject extends DurableObject {
sql: SqlStorage
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.sql = ctx.storage.sql;
this.sql.exec(`CREATE TABLE IF NOT EXISTS artist(
artistid INTEGER PRIMARY KEY,
artistname TEXT
);INSERT INTO artist (artistid, artistname) VALUES
(123, 'Alice'),
(456, 'Bob'),
(789, 'Charlie');`
);
}
}クエリ結果を行オブジェクトとして反復します。
let cursor = this.sql.exec("SELECT * FROM artist;");
for (let row of cursor) {
// Iterate over row object and do something
}クエリ結果を行オブジェクトの配列に変換します。
// Return array of row objects: [{"artistid":123,"artistname":"Alice"},{"artistid":456,"artistname":"Bob"},{"artistid":789,"artistname":"Charlie"}]
let resultsArray1 = this.sql.exec("SELECT * FROM artist;").toArray();
// OR
let resultsArray2 = Array.from(this.sql.exec("SELECT * FROM artist;"));
// OR
let resultsArray3 = [...this.sql.exec("SELECT * FROM artist;")]; // JavaScript spread syntaxクエリ結果を、行の値配列の配列に変換します。
// Returns [[123,"Alice"],[456,"Bob"],[789,"Charlie"]]
let cursor = this.sql.exec("SELECT * FROM artist;");
let resultsArray = cursor.raw().toArray();
// Returns ["artistid","artistname"]
let columnNameArray = this.sql.exec("SELECT * FROM artist;").columnNames.toArray();クエリ結果の最初の行オブジェクトを取得します。
// Returns {"artistid":123,"artistname":"Alice"}
let firstRow = this.sql.exec("SELECT * FROM artist ORDER BY artistname DESC;").toArray()[0];クエリ結果がちょうど 1 行かどうかを確認します。
// returns error
this.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;").one();
// returns { artistid: 123, artistname: 'Alice' }
let oneRow = this.sql.exec("SELECT * FROM artist WHERE artistname = ?;", "Alice").one()返されるカーソルの動作:
let cursor = this.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;");
let result = cursor.next();
if (!result.done) {
console.log(result.value); // prints { artistid: 123, artistname: 'Alice' }
} else {
// query returned zero results
}
let remainingRows = cursor.toArray();
console.log(remainingRows); // prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }]返されるカーソルと raw() イテレーターは、同じクエリ結果を反復します。
let cursor = this.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;");
let result = cursor.raw().next();
if (!result.done) {
console.log(result.value); // prints [ 123, 'Alice' ]
} else {
// query returned zero results
}
console.log(cursor.toArray()); // prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }]sql.exec().rowsRead():
let cursor = this.sql.exec("SELECT * FROM artist;");
cursor.next()
console.log(cursor.rowsRead); // prints 1
cursor.toArray(); // consumes remaining cursor
console.log(cursor.rowsRead); // prints 3databaseSize: number
現在の SQLite データベースサイズ(バイト)です。
let size = ctx.storage.sql.databaseSize;size = ctx.storage.sql.databaseSizeSQLite バックエンドの Durable Objects では、埋め込み SQLite データベースを過去 30 日以内の任意の時点に復元する、ポイントインタイムリカバリー(PITR)API メソッドが使えます。これらのメソッドは SQLite データベース全体に適用され、オブジェクトの保存済み SQL データと、キーバリュー put() API で保存したキーバリューデータの両方を含みます。PITR API はローカル開発では使えません。データの変更の永続ログがローカルに保存されないためです。
PITR API は時点を「ブックマーク」で表します。ブックマークは、ほぼ英数字の文字列です。例は 0000007b-0000b26e-00001538-0c3e87bb37b3db5cc52eedb93cd3b96b です。ブックマークは辞書順で比較できるように設計されています。より早い時点のブックマークは、通常の文字列比較で、より遅い時点のブックマークより小さくなります。
ctx.storage.getCurrentBookmark(): Promise<string>
- オブジェクトの履歴における現在の時点を表すブックマークを返します。
ctx.storage.getBookmarkForTime(timestamp: : number | Date)Promise<string>
- 指定した時点におおよそ対応するブックマークを返します。時点は過去 30 日以内である必要があります。タイムスタンプが数値の場合、
new Date(timestamp)を使ったときと同じ方法で日付に変換されます。
ctx.storage.onNextSessionRestoreBookmark(bookmark: : string)Promise<string>
- 次に再起動したとき、ストレージが指定したブックマーク時点の内容と完全に一致するよう Durable Object を設定します。このあと、アプリケーションは通常
ctx.abort()を呼んで Durable Object を再起動し、ポイントインタイムリカバリーを完了します。
このメソッドは、リカバリーが行われる直前の時点を表す特別なブックマークを返します(その時点はまだ技術的には未来です)。そのため、リカバリー完了後に、このブックマークへ再度リカバリーすれば元に戻せます。
const DAY_MS = 24*60*60*1000;
// restore to 2 days ago
let bookmark = ctx.storage.getBookmarkForTime(Date.now() - 2 * DAYS_MS);
ctx.storage.onNextSessionRestoreBookmark(bookmark);from datetime import datetime, timedelta
now = datetime.now()
# restore to 2 days ago
bookmark = ctx.storage.getBookmarkForTime(now - timedelta(days=2))
ctx.storage.onNextSessionRestoreBookmark(bookmark)ctx.storage.kv.get(key:string)Any, undefined- 指定したキーに対応する値を取得します。戻り値の型は、そのキーに以前書き込まれた値と同じです。キーが存在しない場合は undefined です。
ctx.storage.kv.put(key:string, valueany)void-
値を保存し、指定したキーに関連付けます。値は structured clone algorithm ↗ がサポートする任意の型を使えます。ほとんどの型が対象です。
キーと値のサイズについては、SQLite バックエンドの Durable Object の上限 を参照してください。
-
ctx.storage.kv.delete(key:string)boolean- キーと対応する値を削除します。キーが存在した場合は
true、存在しなかった場合はfalseを返します。
- キーと対応する値を削除します。キーが存在した場合は
ctx.storage.kv.list(options:Object任意)Iterable<string, any>-
現在の Durable Object に関連付けられたすべてのキーと値を、キーの UTF-8 エンコーディングに基づく昇順で返します。
-
Iterable↗ 内の各戻り値の型は、対応するキーに以前書き込まれた値と同じです。 -
オプションなしでこの
listを呼ぶ前に、Durable Object にどれだけデータが保存されているかに注意してください。すべてのデータが Durable Object のメモリに読み込まれ、上限 に達する可能性があります。それが心配な場合は、以下で説明するオプションをlistに渡してください。
-
-
startstring- リスト結果の開始キーです。このキーを含みます。
-
startAfterstring- リスト結果の開始位置となるキーの直後です。このキーは含みません。
startと同時には使えません。
- リスト結果の開始位置となるキーの直後です。このキーは含みません。
-
endstring- リスト結果の終了キーです。このキーは含みません。
-
prefixstring- キーがこのプレフィックスで始まるキーと値のペアだけに結果を限定します。
-
reverseboolean- true の場合、デフォルトの昇順ではなく降順で結果を返します。
reverseを有効にしても、start、startKey、endKeyの意味は変わりません。startは辞書順で返せる最小のキー(含む)を定義し、降順リストでは実質的な終点になります。endは辞書順でリストが対象とする最大のキー(含まない)を定義し、降順リストでは実質的な始点になります。
-
limitnumber- 返すキーと値のペアの最大数です。
-
ctx.storage.get(key:string, optionsObject任意)Promise<any>- 指定したキーに対応する値を取得します。戻り値の型は、そのキーに以前書き込まれた値と同じです。キーが存在しない場合は undefined です。
-
ctx.storage.get(keys:Array<string>, optionsObject任意)Promise<Map<string, any>>- 指定した各キーに対応する値を取得します。
Map↗ 内の各戻り値の型は、対応するキーに以前書き込まれた値と同じです。Mapの結果は UTF-8 エンコーディングの昇順で並び、存在しないキーは省略されます。一度に最大 128 個のキーを指定できます。
- 指定した各キーに対応する値を取得します。
-
allowConcurrency:boolean- デフォルトでは、予期しない競合状態を避けるため、ストレージ操作の実行中は Object への I/O イベントの配信を一時停止します。この動作を無効にして同時イベントの配信を許可するには、
allowConcurrency: trueを渡します。
- デフォルトでは、予期しない競合状態を避けるため、ストレージ操作の実行中は Object への I/O イベントの配信を一時停止します。この動作を無効にして同時イベントの配信を許可するには、
-
noCache:boolean- true の場合、キーと値はメモリ内キャッシュに挿入されません。キーがすでにキャッシュにある場合はキャッシュされた値を返しますが、最終使用時刻は更新しません。近い将来このキーを使わない見込みのときに使います。このフラグはヒントです。コードの意味は変わりませんが、パフォーマンスに影響する場合があります。
-
put(key:string, valueany, optionsObject任意)Promise-
値を保存し、指定したキーに関連付けます。値は structured clone algorithm ↗ がサポートする任意の型を使えます。ほとんどの型が対象です。
キーと値のサイズ上限は、利用している Durable Object のストレージバックエンドによって異なります。次のいずれかを参照してください。
KV バックエンドの Durable Object では、シリアライズ後の値が 128 KiB(131072 バイト)の値サイズ上限を超えると、書き込みが適用される前に
put()がRangeErrorを投げます(例:Values cannot be larger than 131072 bytes.)。
-
-
put(entries:Object, optionsObject任意)Promise- オブジェクトを受け取り、各キーと値をストレージに保存します。
- 各値は structured clone algorithm ↗ がサポートする任意の型を使えます。ほとんどの型が対象です。
- 一度に最大 128 個のキーと値のペアを指定できます。キーと値のサイズ上限は、利用している Durable Object の種類によって異なります。次のいずれかを参照してください。
-
delete(key:string, optionsObject任意)Promise<boolean>- キーと対応する値を削除します。キーが存在した場合は
true、存在しなかった場合はfalseを返します。
- キーと対応する値を削除します。キーが存在した場合は
-
delete(keys:Array<string>, optionsObject任意)Promise<number>- 指定したキーと対応する値を削除します。一度に最大 128 個のキーを指定できます。削除したキーと値のペアの数を返します。
-
put()、delete()、deleteAll()は次のオプションをサポートします。 -
allowUnconfirmedboolean-
デフォルトでは、以前の書き込みがディスクへフラッシュされたことを確認するまで、Durable Object からの送信ネットワークメッセージを一時停止します。書き込みが失敗した場合、システムは Object をリセットし、送信中のメッセージをすべて破棄して、クライアントにはエラーを返します。
-
こうすることで、書き込みが実際に成功しない限り外部から Object の動作は観測できないため、Durable Objects は書き込みが完了する前に確定してしまう心配なく、書き込みと並行して実行を続けられます。
-
書き込みのあと、後続のネットワークメッセージがわずかに遅れることがあります。未確認の書き込みを前提に通信しても問題ないアプリケーションもあります。ネットワークトラフィックをすぐに許可したいプログラムもあります。その場合は
allowUnconfirmedをtrueに設定し、デフォルトの動作を無効にします。 -
一部の送信ネットワークメッセージだけをすぐに進めたい場合は、
allowUnconfirmedオプションで進めたいメッセージのブロックを避け、別途sync()を呼びます。sync()は、以前の書き込みがすべてディスクへ正常に永続化されたときにだけ解決する Promise を返します。
-
-
noCacheboolean-
true の場合、ディスクへの書き込みが完了した時点で、キーと値はメモリから破棄されます。
-
近い将来キーを使わない場合は
noCacheを使います。noCacheはコードの意味を変えませんが、パフォーマンスに影響する場合があります。 -
書き込み完了前に
get()でキーを取得した場合は、書き込みバッファーのコピーが返されます。これにより、最新のput()呼び出しとの一貫性が保たれます。
-
list(options:Object任意)Promise<Map<string, any>>
-
startstring- リスト結果の開始キーです。このキーを含みます。
-
startAfterstring- リスト結果の開始位置となるキーの直後です。このキーは含みません。
startと同時には使えません。
- リスト結果の開始位置となるキーの直後です。このキーは含みません。
-
endstring- リスト結果の終了キーです。このキーは含みません。
-
prefixstring- キーがこのプレフィックスで始まるキーと値のペアだけに結果を限定します。
-
reverseboolean- true の場合、デフォルトの昇順ではなく降順で結果を返します。
reverseを有効にしても、start、startKey、endKeyの意味は変わりません。startは辞書順で返せる最小のキー(含む)を定義し、降順リストでは実質的な終点になります。endは辞書順でリストが対象とする最大のキー(含まない)を定義し、降順リストでは実質的な始点になります。
-
limitnumber- 返すキーと値のペアの最大数です。
-
allowConcurrencyboolean- 上記の
get()のオプションと同じです。
- 上記の
-
noCacheboolean- 上記の
get()のオプションと同じです。
- 上記の
getAlarm(options:Object任意)Promise<Number | null>- 現在のアラーム時刻(設定されている場合)を、エポックからの整数ミリ秒として取得します。アラームは、まだ開始していない場合、または失敗して再試行が始まっていない場合に、設定済みとみなされます。アラームが設定されていない場合、
getAlarm()はnullを返します。
- 現在のアラーム時刻(設定されている場合)を、エポックからの整数ミリ秒として取得します。アラームは、まだ開始していない場合、または失敗して再試行が始まっていない場合に、設定済みとみなされます。アラームが設定されていない場合、
get()と同じオプションです。ただしnoCacheはありません。
-
setAlarm(scheduledTime:Date | number, optionsObject任意)Promise- 現在のアラーム時刻を設定します。JavaScript の
Date、またはエポックからの整数ミリ秒を受け付けます。
setAlarm()にDate.now()以前の時刻を渡した場合、アラームはすぐあとで非同期実行されるようスケジュールされます。このときアラームハンドラーが実行中でも、キャンセルはされません。アラームはミリ秒単位で設定でき、通常は設定時刻の数ミリ秒後に実行されます。ただしメンテナンスやフェイルオーバー中の障害により、最大 1 分遅れることがあります。 - 現在のアラーム時刻を設定します。JavaScript の
deleteAlarm(options:Object任意)Promise- アラームが存在する場合は削除します。アラームハンドラーが実行中の場合はキャンセルしません。
setAlarm()とdeleteAlarm()はput()と同じオプションをサポートします。ただしnoCacheはありません。
deleteAll(options:Object任意)Promise- 保存されているデータをすべて削除し、Durable Object が使っているストレージを実質的に解放します。キーバリューストレージバックエンドの Durable Object では、
deleteAll()はその Durable Object のすべてのキーと対応する値を削除します。SQLite ストレージバックエンド の Durable Object では、deleteAll()はその Durable Object のプライベート SQLite データベースの内容をすべて削除します。SQL データとキーバリューデータの両方が対象です。 - キーバリューストレージバックエンドの Durable Object では、進行中の
deleteAll()が失敗し、一部のデータだけが残ることがあります。SQLite ストレージバックエンドの Durable Object では、deleteAll()はアトミック(すべて成功するか、まったく実行されないか)なので、部分削除の問題はありません。 - 互換日付が
2026-02-24以降の Workers では、deleteAll()は有効な アラーム も削除します。それより前の互換日付では、deleteAll()はアラームを削除しません。別途deleteAlarm()を使うか、delete_all_deletes_alarm互換フラグ を有効にしてください。
- 保存されているデータをすべて削除し、Durable Object が使っているストレージを実質的に解放します。キーバリューストレージバックエンドの Durable Object では、
transactionSync(callback):any-
SQLite バックエンドの Durable Object でのみ利用できます。
-
callback()をトランザクションで包んで実行し、その結果を返します。 -
callback()が例外を投げた場合、トランザクションはロールバックされます。 -
コールバックは同期的に完了する必要があります。つまり、
asyncとして宣言したり、Promise を返したりしてはいけません。トランザクションに含められるのは同期的なストレージ操作だけです。これは、同期的に完了するctx.storage.sql.exec()を使った SQL クエリ向けです。
-
-
transaction(closureFunction(txn)):Promise-
txnに対して呼ばれた一連のストレージ操作を、1 つのトランザクションとして実行します。コミットに成功するか、中止されます。 -
明示的なトランザクションは、もはや必要ありません。間に
awaitを挟まない一連の書き込み操作は、自動的にアトミックに送信されます。また、読み取り操作をawaitしている間は、システムが同時イベントの実行を防ぎます(allowConcurrency: trueを使っている場合を除く)。そのため、一連の読み取りのあとに一連の書き込み(間にほかの I/O がない場合)は自動的にアトミックになり、トランザクションのように振る舞います。
-
-
txn-
上記で説明した
put()、get()、delete()、list()メソッドに、現在のトランザクションコンテキストでアクセスできます。トランザクションクロージャ内でトランザクションの振る舞いを得るには、トップレベルのctx.storageオブジェクトではなく、txnオブジェクトのメソッドを呼ぶ必要があります。
また、トランザクション中の変更をコミットせずにロールバックするrollback()関数も使えます。rollback()を呼んだあと、txnオブジェクトへの以降の操作は例外で失敗します。rollback()はパラメーターを取らず、呼び出し元に何も返しません。 -
SQLite バックエンドのストレージエンジン を使う場合、
txnオブジェクトは不要です。ctx.storageオブジェクトに対して直接行うストレージ操作(ctx.storage.sql.exec()を使った SQL クエリを含む)は、トランザクションの一部と見なされます。
-
sync():Promise-
保留中の書き込みをディスクへ同期します。
-
自動的な書き込み合体(write coalescing)の通常の振る舞いと似ています。書き込みバッファーに保留中の書き込みがある場合(
allowUnconfirmedオプション で送信したものも含む)、返される Promise はそれらが完了したときに解決します。保留中の書き込みがない場合、返される Promise はすでに解決済みです。
-
sql は DurableObjectStorage 型の読み取り専用プロパティで、SQL API をまとめたものです。