--- title: "Concurrency & Threading" description: "Configure concurrency modes for safe multi-threaded database access." canonical: "https://roomsharp.dev/docs/v0.5.4/concurrency" source: "src/content/v0.5.4/concurrency.mdx" --- # Concurrency & Threading RoomSharp supports two concurrency modes, configured per `RoomDatabase` instance. ## Serialized (Default, Production-Safe) - All DAO calls on a database instance are **serialized** through an internal gate. - Safe for multi-threaded apps even when you call DAOs concurrently (e.g. `Task.WhenAll(...)`). - Keeps current performance optimizations (single connection + reusable command templates). - Recommended for **SQLite** in most apps (single-writer file database). ```csharp var db = RoomDatabase.Builder() .UseSqlite("app.db") .Build(); ``` ## Parallel (Opt-in, True Parallel DB I/O) - Each DAO operation uses a **separate `DbSession` / `DbConnection`** (from provider pooling). - Enables true parallelism for independent DAO calls (e.g. `Task.WhenAll(...)`). - Requires configuring a connection factory (or a custom `IRoomDatabaseFactory`). - Transactions are **single-connection**: use `BeginUnitOfWork*` and do **not** run operations in parallel inside the same UnitOfWork/session. ```csharp // Define database with Parallel mode via attribute [Database(Version = 1, Entities = [typeof(User)], ConcurrencyMode = ConcurrencyMode.Parallel)] public abstract class AppDatabase(IDatabaseProvider provider, ILogger? logger = null) : RoomDatabase(provider, logger) { public abstract IUserDao UserDao { get; } } // Build with connection factory var cs = "Data Source=app.db;Mode=ReadWriteCreate;Cache=Private"; var db = RoomDatabase.Builder() .UseSqliteWithConnectionString(cs) .UseConnectionFactory(() => new Microsoft.Data.Sqlite.SqliteConnection(cs)) .SetMaxParallelConnections(32) // optional .Build(); ``` ## Concurrency Rules & Guarantees RoomSharp enforces strict concurrency rules to prevent unsafe ADO.NET patterns: - RoomSharp never executes multiple commands concurrently on the same `DbConnection`. - `ConcurrencyMode.Parallel` enables parallelism via **multiple independent DbSessions**, not by sharing a connection. - A `DbSession` / `UnitOfWork` is **not allowed** to be used concurrently; attempting parallel execution within the same session will throw. - Parallel DAO calls inside an active UnitOfWork reuse the ambient session and therefore run serially. - Serialized mode guarantees mutual exclusion (no concurrent access), but does not guarantee FIFO task ordering. ## UnitOfWork in Parallel Mode When using Parallel mode, use `BeginUnitOfWorkAsync` to group operations under a single transaction: ```csharp await using var uow = await db.BeginUnitOfWorkAsync(); await db.UserDao.InsertAsync(new User { Email = "a@b.com" }); await db.UserDao.UpdateAsync(new User { Id = 1, Email = "c@d.com" }); await uow.CommitAsync(); ``` Do **not** run operations in parallel inside the same UnitOfWork. The operations share the ambient session and will be serialized anyway. ## SQLite Notes - Parallel mode works best for **read-heavy** workloads; writes are still single-writer. - Avoid `:memory:` in Parallel mode unless you intentionally configure a shared in-memory database (e.g. `Mode=Memory;Cache=Shared`). ## Mode Comparison | Feature | Serialized | Parallel | |---------|------------|----------| | Default | ✓ | - | | Connection Count | Single | Pool (configurable) | | Thread Safety | Internal gate | Session isolation | | Best For | SQLite, simple apps | Read-heavy, SQL Server/PostgreSQL | | Transaction Scope | Ambient | UnitOfWork | | Configuration | None required | Connection factory |