DatabaseSnapshot
A database connection that serializes accesses to an unchanging database content, as it existed at the moment the snapshot was created.
final class DatabaseSnapshot
Overview
A DatabaseSnapshot
never sees any database modification during all its lifetime. All database accesses performed from a snapshot always see the same identical database content.
A snapshot creates one single SQLite connection. All database accesses are executed in a serial reader dispatch queue. The SQLite connection is closed when the DatabaseSnapshot
is deallocated.
A snapshot created on a WAL database doesn’t prevent database modifications performed by other connections (but it won’t see them). Refer to Isolation In SQLite for more information.
On non-WAL databases, a snapshot prevents all database modifications as long as it exists, because of the SHARED lock it holds.
Usage
You create instances of DatabaseSnapshot
from a DatabasePool
, with makeSnapshot
:
let dbPool = try DatabasePool(path: "/path/to/database.sqlite")
let snapshot = try dbPool.makeSnapshot()
let playerCount = try snapshot.read { db in
try Player.fetchCount(db)
}
When you want to control the database state seen by a snapshot, create the snapshot from within a write access, outside of any transaction.
For example, compare the two snapshots below. The first one is guaranteed to see an empty table of players, because is is created after all players have been deleted, and from the serialized writer dispatch queue which prevents any concurrent write. The second is created without this concurrency protection, which means that some other threads may already have created some players:
let snapshot1 = try dbPool.writeWithoutTransaction { db -> DatabaseSnapshot in
try db.inTransaction {
try Player.deleteAll()
return .commit
}
return try dbPool.makeSnapshot()
}
// <- Other threads may have created some players here
let snapshot2 = try dbPool.makeSnapshot()
// Guaranteed to be zero
let count1 = try snapshot1.read { db in
try Player.fetchCount(db)
}
// Could be anything
let count2 = try snapshot2.read { db in
try Player.fetchCount(db)
}
DatabaseSnapshot
inherits its database access methods from the DatabaseReader
protocols.
DatabaseSnapshot
serializes database accesses and can’t perform concurrent reads. For concurrent reads, see DatabaseSnapshotPool
.