Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Transakce umožňují seskupit více příkazů SQL do jedné jednotky operace, která je potvrzena do databáze jako jedna atomická jednotka. Pokud některý příkaz v transakci selže, změny provedené předchozími příkazy lze vrátit zpět. Počáteční stav databáze při spuštění transakce je zachován. Použití transakce může také zvýšit výkon SQLite při provádění mnoha změn v databázi najednou.
Konkurentnost
V nástroji SQLite může mít v databázi najednou čekající změny pouze jedna transakce. Z tohoto důvodu může na BeginTransaction dojít k tomu, že volání metod Execute a SqliteCommand vyprší časový limit, pokud dokončení jiné transakce trvá příliš dlouho.
Další informace o uzamykání, opakování a vypršení časových limitů najdete v tématu Chyby databáze.
Úrovně izolace
Transakce jsou serializovatelné ve výchozím nastavení v SQLite. Tato úroveň izolace zaručuje, že všechny změny provedené v rámci transakce jsou zcela izolované. Jiné příkazy provedené mimo transakci nejsou ovlivněny změnami transakce.
SQLite také podporuje nepotvrzené čtení při použití sdílené mezipaměti. Tato úroveň umožňuje špinavé čtení, neopakovatelné čtení a fantomy:
Špinavé čtení nastane, když změny čekající v jedné transakci jsou vráceny dotazem mimo transakci, ale změny v transakci jsou vráceny zpět. Výsledky obsahují data, která nebyla nikdy ve skutečnosti potvrzena do databáze.
Neopakovatelné čtení nastane, když transakce dotazuje stejný řádek dvakrát, ale výsledky jsou odlišné, protože byly změněny mezi těmito dvěma dotazy jinou transakcí.
Přízraky jsou řádky, které se během transakce změní nebo přidají, aby splňovaly klauzuli WHERE v dotazu. Pokud je dotaz povolen, může stejný dotaz vrátit různé řádky, když je proveden dvakrát ve stejné transakci.
Microsoft.Data.Sqlite považuje úroveň IsolationLevel předanou do BeginTransaction za minimální úroveň. Skutečná úroveň izolace se zvýší na čtení, které není povoleno, nebo serializovatelné.
Následující kód simuluje špinavé čtení. Poznámka: Připojovací řetězec musí obsahovat Cache=Shared.
using (var firstTransaction = firstConnection.BeginTransaction())
{
var updateCommand = firstConnection.CreateCommand();
updateCommand.CommandText =
@"
UPDATE data
SET value = 'dirty'
";
updateCommand.ExecuteNonQuery();
// Without ReadUncommitted, the command will time out since the table is locked
// while the transaction on the first connection is active
using (secondConnection.BeginTransaction(IsolationLevel.ReadUncommitted))
{
var queryCommand = secondConnection.CreateCommand();
queryCommand.CommandText =
@"
SELECT *
FROM data
";
var value = (string)queryCommand.ExecuteScalar();
Console.WriteLine($"Value: {value}");
}
firstTransaction.Rollback();
}
Odložené transakce
Od Microsoft.Data.Sqlite verze 5.0 je možné transakce odložit. Tím se odkládá vytvoření skutečné transakce v databázi, dokud není vykonán první příkaz. Také způsobí, že se transakce postupně upgraduje z transakce čtení na transakci zápisu dle požadavků jeho příkazů. To může být užitečné pro povolení souběžného přístupu k databázi během transakce.
using (var transaction = connection.BeginTransaction(deferred: true))
{
// Before the first statement of the transaction is executed, both concurrent
// reads and writes are allowed
var readCommand = connection.CreateCommand();
readCommand.CommandText =
@"
SELECT *
FROM data
";
var value = (long)readCommand.ExecuteScalar();
// After a the first read statement, concurrent writes are blocked until the
// transaction completes. Concurrent reads are still allowed
var writeCommand = connection.CreateCommand();
writeCommand.CommandText =
@"
UPDATE data
SET value = $newValue
";
writeCommand.Parameters.AddWithValue("$newValue", value + 1L);
writeCommand.ExecuteNonQuery();
// After the first write statement, both concurrent reads and writes are blocked
// until the transaction completes
transaction.Commit();
}
Výstraha
Příkazy uvnitř odložené transakce mohou selhat, pokud způsobí, že transakce se upgraduje z transakce čtení na transakci zápisu, zatímco je databáze uzamčena. V takovém případě bude aplikace muset opakovat celou transakci.
Savepoints
Verze 6.0 Microsoft.Data.Sqlite podporuje savepointy. K vytváření vnořených transakcí lze použít uzlové body. Savepointy se dají vrátit zpět, aniž by to mělo vliv na jiné části transakce, a přestože může být savepoint potvrzen, jeho změny mohou být později vráceny zpět jako součást nadřazené transakce.
Následující kód znázorňuje použití modelu Optimistic Offline Lock k detekci souběžných aktualizací a řešení konfliktů v rámci bodu uložení v rámci větší transakce.
using (var transaction = connection.BeginTransaction())
{
// Transaction may include additional statements before the savepoint
var updated = false;
do
{
// Begin savepoint
transaction.Save("optimistic-update");
var insertCommand = connection.CreateCommand();
insertCommand.CommandText =
@"
INSERT INTO audit
VALUES (datetime('now'), 'User updates data with id 1')
";
insertCommand.ExecuteScalar();
var updateCommand = connection.CreateCommand();
updateCommand.CommandText =
@"
UPDATE data
SET value = 2,
version = $expectedVersion + 1
WHERE id = 1
AND version = $expectedVersion
";
updateCommand.Parameters.AddWithValue("$expectedVersion", expectedVersion);
var recordsAffected = updateCommand.ExecuteNonQuery();
if (recordsAffected == 0)
{
// Concurrent update detected! Rollback savepoint and retry
transaction.Rollback("optimistic-update");
// TODO: Resolve update conflicts
}
else
{
// Update succeeded. Commit savepoint and continue with the transaction
transaction.Release("optimistic-update");
updated = true;
}
}
while (!updated);
// Additional statements may be included after the savepoint
transaction.Commit();
}