You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/docs/durable-objects/api/sqlite-storage-api.mdx
+5-7Lines changed: 5 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -154,9 +154,9 @@ class MyDurableObject(DurableObject):
154
154
A cursor (`SqlStorageCursor`) to iterate over query row results as objects. `SqlStorageCursor` is a JavaScript [Iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol), which supports iteration using `for (let row of cursor)`. `SqlStorageCursor` is also a JavaScript [Iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol), which supports iteration using `cursor.next()`.
155
155
156
156
:::caution[Consume cursors synchronously]
157
-
It is not safe to hold a reference to a `SqlStorageCursor` and continue reading from it after an `await`. When you `await`an asynchronous operation, other requests can interleave and modify the underlying database, which can silently invalidate the cursor. This does not produce an error — the cursor may appear to work but return unpredictable results.
157
+
Although a cursor object can technically be held across an `await`, it does not provide a stable snapshot of the query results. A cursor resumed after an `await`may observe rows inserted, updated, or deleted after the cursor was created, including writes from a later implicit transaction that has not yet committed. If that later transaction rolls back, the cursor may have already returned data from a state that never became durable.
158
158
159
-
Always consume the cursor fully before yielding the event loop. Call `.toArray()`, `.one()`, or iterate with `for...of` synchronously after calling `sql.exec()`:
159
+
For predictable behavior, fully consume cursors synchronously before the next `await`, for example with `.toArray()` or `Array.from(cursor)`. Treat cursors that cross `await` boundaries as having no snapshot isolation guarantees.
160
160
161
161
```ts
162
162
// ✅ Safe: cursor is fully consumed before any await
//⚠️ No snapshot isolation: cursor may reflect changes made after it was created
169
169
const cursor =this.ctx.storage.sql.exec("SELECT * FROM users");
170
170
awaitfetch("https://example.com/notify");
171
-
//Another request may have modified the database during the await above.
172
-
//The cursor is now potentially invalid — it may appear to work but return wrong data.
171
+
//Rows returned here may include writes that occurred during the await,
172
+
//including uncommitted data from a later implicit transaction.
173
173
const rows =cursor.toArray();
174
174
```
175
-
176
-
If you need to prevent other requests from interleaving while you hold a cursor, use [`blockConcurrencyWhile()`](/durable-objects/api/state/#blockconcurrencywhile).
177
175
:::
178
176
179
177
`SqlStorageCursor` supports the following methods:
0 commit comments