diff --git a/docs/standard/data/sqlite/database-errors.md b/docs/standard/data/sqlite/database-errors.md index 6dd0d3ca9226d..e3b0561a259f2 100644 --- a/docs/standard/data/sqlite/database-errors.md +++ b/docs/standard/data/sqlite/database-errors.md @@ -18,6 +18,10 @@ Consider carefully how your app will handle these errors. ## Locking, retries, and timeouts +> [!WARNING] +> Although SQLite supports concurrent access to the same database from multiple threads, the .NET APIs objects are not thread-safe. This means that `SqliteConnection`, `SqliteCommand` and `SqliteDataReader` cannot be shared and used concurrently from multiple threads. +> When using Microsoft.Data.Sqlite from a concurrent application, simply create and open a new instance of `SqliteConnection` whenever you need to access the database (pooling ensures that this is a fast operation). + SQLite is aggressive when it comes to locking tables and database files. If your app enables any concurrent database access, you'll likely encounter busy and locked errors. You can mitigate many errors by using [write-ahead logging](async.md). Whenever Microsoft.Data.Sqlite encounters a busy or locked error, it will automatically retry until it succeeds or the command timeout is reached. diff --git a/samples/snippets/standard/data/sqlite/HelloWorldSample/Program.cs b/samples/snippets/standard/data/sqlite/HelloWorldSample/Program.cs index 97f2157894552..ce8ec7ecd5448 100644 --- a/samples/snippets/standard/data/sqlite/HelloWorldSample/Program.cs +++ b/samples/snippets/standard/data/sqlite/HelloWorldSample/Program.cs @@ -8,79 +8,82 @@ class Program { static void Main() { - using (var connection = new SqliteConnection("Data Source=hello.db")) + CreateAndSeed(); + Query(); + + // Clean up + SqliteConnection.ClearAllPools(); + File.Delete("hello.db"); + } + + static void CreateAndSeed() + { + using var connection = new SqliteConnection("Data Source=hello.db"); + + connection.Open(); + + var command = connection.CreateCommand(); + command.CommandText = """ + CREATE TABLE user ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL + ); + + INSERT INTO user + VALUES (1, 'Brice'), + (2, 'Alexander'), + (3, 'Nate'); + """; + command.ExecuteNonQuery(); + + Console.Write("Name: "); + var name = Console.ReadLine(); + + #region snippet_Parameter + command.CommandText = "INSERT INTO user (name) VALUES ($name)"; + command.Parameters.AddWithValue("$name", name); + #endregion + command.ExecuteNonQuery(); + + command.CommandText = "SELECT last_insert_rowid()"; + var newId = (long)command.ExecuteScalar()!; + + Console.WriteLine($"Your new user ID is {newId}."); + } + + static void Query() + { + Console.Write("User ID: "); + var line = Console.ReadLine(); + if (line is null) { - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - @" - CREATE TABLE user ( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL - ); - - INSERT INTO user - VALUES (1, 'Brice'), - (2, 'Alexander'), - (3, 'Nate'); - "; - command.ExecuteNonQuery(); - - Console.Write("Name: "); - var name = Console.ReadLine(); - - #region snippet_Parameter - command.CommandText = - @" - INSERT INTO user (name) - VALUES ($name) - "; - command.Parameters.AddWithValue("$name", name); - #endregion - command.ExecuteNonQuery(); - - command.CommandText = - @" - SELECT last_insert_rowid() - "; - var newId = (long)command.ExecuteScalar(); - - Console.WriteLine($"Your new user ID is {newId}."); + return; } - Console.Write("User ID: "); - var id = int.Parse(Console.ReadLine()); + var id = int.Parse(line); #region snippet_HelloWorld - using (var connection = new SqliteConnection("Data Source=hello.db")) + using var connection = new SqliteConnection("Data Source=hello.db"); + + connection.Open(); + + using var command = connection.CreateCommand(); + command.CommandText = """ + SELECT name + FROM user + WHERE id = $id + """; + command.Parameters.AddWithValue("$id", id); + + using var reader = command.ExecuteReader(); + + while (reader.Read()) { - connection.Open(); - - var command = connection.CreateCommand(); - command.CommandText = - @" - SELECT name - FROM user - WHERE id = $id - "; - command.Parameters.AddWithValue("$id", id); - - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - var name = reader.GetString(0); - - Console.WriteLine($"Hello, {name}!"); - } - } + var name = reader.GetString(0); + + Console.WriteLine($"Hello, {name}!"); } #endregion - - // Clean up - SqliteConnection.ClearAllPools(); - File.Delete("hello.db"); } } }