并发控制概述
在现代软件开发中,并发控制是确保数据一致性和完整性的关键技术。对于轻量级嵌入式数据库 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是单线程数据库,文章强调了在应用层实现适当的锁策略和同步技术的重要性,以确保数据一致性和完整性。