LiteDB 并发控制与多线程访问深度解析

并发控制概述

在现代软件开发中,并发控制是确保数据一致性和完整性的关键技术。对于轻量级嵌入式数据库 LiteDB 来说,有效的并发控制机制尤为重要。本文将详细探讨 LiteDB 中的并发控制策略、多线程访问模式以及在多设备数据同步中的应用。

Nuget 安装LiteDB

图片

LiteDB 并发控制基础

锁机制原理

LiteDB 提供了多种锁定机制来管理并发访问:

复制
using LiteDB; namespace App13 { publicclass User { publicstring Name { get; set; } publicint Age { get; set; } } internal class Program { // 数据库实例 privatestatic LiteDatabase _database; // 创建一个静态对象作为锁对象 privatestatic readonly object _lock = new object(); static void Main(string[] args) { ExclusiveLockExample(); SharedLockExample(); } // 共享锁:允许多个读取操作同时进行 public static void SharedLockExample() { using (var db = new LiteDatabase(@"MyData.db")) { // 使用共享锁进行读取操作 var collection = db.GetCollection<User>("users"); // 多线程并发读取不会相互阻塞 Parallel.For(0, 10, i => { var users = collection.Find(u => u.Age > 18); Console.WriteLine($"Thread {i} read {users.Count()} users"); }); } } // 排他锁:确保写入操作的原子性 public static void ExclusiveLockExample() { using (var db = new LiteDatabase(@"MyData.db")) { var collection = db.GetCollection<User>("users"); // 使用静态锁对象替代 this lock (_lock) { // 写入操作 var newUser = new User { Name = "张三", Age = 30 }; collection.Insert(newUser); } } } } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.

图片

多线程访问模式

读-写并发控制
复制
using LiteDB; namespace App13 { // 产品模型类 publicclass Product { public ObjectId Id { get; set; } publicstring Name { get; set; } public decimal Price { get; set; } publicint Stock { get; set; } public DateTime CreateTime { get; set; } } publicclass MultiThreadAccess : IDisposable { private readonly object _lockObject = new object(); privateconststring DbPath = @"MyData.db"; private readonly ConnectionString _connectionString; public MultiThreadAccess() { // 配置连接字符串,启用文件共享 _connectionString = new ConnectionString { Filename = DbPath, Connection = ConnectionType.Shared // 使用共享连接模式 }; // 初始化数据库 InitializeDatabase(); } private void InitializeDatabase() { using (var db = new LiteDatabase(_connectionString)) { var collection = db.GetCollection<Product>("products"); // 如果集合为空,添加测试数据 if (!collection.Find(Query.All()).Any()) { var products = new List<Product> { new Product { Name = "旧产品", Price = 150.00m, Stock = 10, CreateTime = DateTime.Now.AddDays(-10) }, new Product { Name = "常规产品", Price = 99.99m, Stock = 20, CreateTime = DateTime.Now.AddDays(-5) } }; collection.InsertBulk(products); } } } public void SafeConcurrentAccess() { try { // 为每个操作创建单独的数据库连接 Parallel.Invoke( () => ReadProducts(), () => WriteProducts(), () => UpdateProducts(), () => DeleteProducts(), () => QueryProducts() ); } catch (Exception ex) { Console.WriteLine($"并发操作出错: {ex.Message}"); } } private void ReadProducts() { using (var db = new LiteDatabase(_connectionString)) { try { var collection = db.GetCollection<Product>("products"); var products = collection.Find(p => p.Price > 100); Console.WriteLine($"读取到 {products.Count()} 个高价产品"); foreach (var product in products) { Console.WriteLine($"产品: {product.Name}, 价格: {product.Price:C}"); } } catch (Exception ex) { Console.WriteLine($"读取操作失败: {ex.Message}"); } } } private void WriteProducts() { using (var db = new LiteDatabase(_connectionString)) { lock (_lockObject) { try { var collection = db.GetCollection<Product>("products"); var newProduct = new Product { Name = $"新产品_{DateTime.Now.Ticks}", Price = 199.99m, Stock = 5, CreateTime = DateTime.Now }; collection.Insert(newProduct); Console.WriteLine($"成功添加新产品: {newProduct.Name}"); } catch (Exception ex) { Console.WriteLine($"写入操作失败: {ex.Message}"); } } } } private void UpdateProducts() { using (var db = new LiteDatabase(_connectionString)) { lock (_lockObject) { try { var collection = db.GetCollection<Product>("products"); var product = collection.FindOne(p => p.Name == "旧产品"); if (product != null) { product.Price *= 1.1m; product.Stock -= 1; collection.Update(product); Console.WriteLine($"更新产品价格: {product.Name} 新价格: {product.Price:C}"); } } catch (Exception ex) { Console.WriteLine($"更新操作失败: {ex.Message}"); } } } } private void DeleteProducts() { using (var db = new LiteDatabase(_connectionString)) { lock (_lockObject) { try { var collection = db.GetCollection<Product>("products"); var result = collection.DeleteMany(p => p.Stock == 0); Console.WriteLine($"删除了 {result} 个库存为0的产品"); } catch (Exception ex) { Console.WriteLine($"删除操作失败: {ex.Message}"); } } } } private void QueryProducts() { using (var db = new LiteDatabase(_connectionString)) { try { var collection = db.GetCollection<Product>("products"); var query = collection.Query() .Where(p => p.Price >= 100 && p.Stock > 0) .OrderByDescending(p => p.CreateTime) .Select(p => new { p.Name, p.Price, p.Stock }) .Limit(5) .ToList(); Console.WriteLine("\n最新的5个高价产品:"); foreach (var item in query) { Console.WriteLine($"名称: {item.Name}, 价格: {item.Price:C}, 库存: {item.Stock}"); } } catch (Exception ex) { Console.WriteLine($"查询操作失败: {ex.Message}"); } } } public void Dispose() { // 实现 IDisposable GC.SuppressFinalize(this); } } internal class Program { static void Main(string[] args) { Console.WriteLine("开始多线程数据库访问测试...\n"); using (var demo = new MultiThreadAccess()) { // 执行多次并发测试 for (int i = 0; i < 3; i++) { Console.WriteLine($"\n=== 测试轮次 {i + 1} ===\n"); demo.SafeConcurrentAccess(); Thread.Sleep(1000); // 暂停一秒后进行下一轮测试 } } Console.WriteLine("\n测试完成!按任意键退出..."); Console.ReadKey(); } } }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.179.180.181.182.183.184.185.186.187.188.189.190.191.192.193.194.195.196.197.198.199.200.201.202.203.204.205.206.207.208.209.210.211.212.213.214.215.216.217.218.219.220.221.222.223.224.225.226.227.228.229.230.231.232.233.234.235.236.

图片

Connection = ConnectionType.Shared 这是重点。

性能注意事项

LiteDB 是单线程数据库,并发控制依赖于应用层锁对于高并发场景,考虑使用更强大的数据库系统优化锁的使用范围,减少锁定时间尽可能使用细粒度锁避免长时间持有锁使用 Parallel.For 和 Task 进行并发操作实现详细的错误处理和日志记录

总结

这篇文章主要讨论了LiteDB数据库的并发控制机制。文章介绍了共享锁和排他锁两种锁机制的实现方式,以及在多线程环境下如何安全地进行数据读写操作。同时还探讨了多设备数据同步的实现方案,包括时间戳比对和冲突解决策略。由于LiteDB是单线程数据库,文章强调了在应用层实现适当的锁策略和同步技术的重要性,以确保数据一致性和完整性。

THE END