LiteDB 并發(fā)控制與多線程訪問(wèn)深度解析
并發(fā)控制概述
在現(xiàn)代軟件開(kāi)發(fā)中,并發(fā)控制是確保數(shù)據(jù)一致性和完整性的關(guān)鍵技術(shù)。對(duì)于輕量級(jí)嵌入式數(shù)據(jù)庫(kù) LiteDB 來(lái)說(shuō),有效的并發(fā)控制機(jī)制尤為重要。本文將詳細(xì)探討 LiteDB 中的并發(fā)控制策略、多線程訪問(wèn)模式以及在多設(shè)備數(shù)據(jù)同步中的應(yīng)用。
Nuget 安裝LiteDB
圖片
LiteDB 并發(fā)控制基礎(chǔ)
鎖機(jī)制原理
LiteDB 提供了多種鎖定機(jī)制來(lái)管理并發(fā)訪問(wèn):
using LiteDB;
namespace App13
{
publicclass User
{
publicstring Name { get; set; }
publicint Age { get; set; }
}
internal class Program
{
// 數(shù)據(jù)庫(kù)實(shí)例
privatestatic LiteDatabase _database;
// 創(chuàng)建一個(gè)靜態(tài)對(duì)象作為鎖對(duì)象
privatestatic readonly object _lock = new object();
static void Main(string[] args)
{
ExclusiveLockExample();
SharedLockExample();
}
// 共享鎖:允許多個(gè)讀取操作同時(shí)進(jìn)行
public static void SharedLockExample()
{
using (var db = new LiteDatabase(@"MyData.db"))
{
// 使用共享鎖進(jìn)行讀取操作
var collection = db.GetCollection<User>("users");
// 多線程并發(fā)讀取不會(huì)相互阻塞
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");
// 使用靜態(tài)鎖對(duì)象替代 this
lock (_lock)
{
// 寫入操作
var newUser = new User
{
Name = "張三",
Age = 30
};
collection.Insert(newUser);
}
}
}
}
}
圖片
多線程訪問(wèn)模式
讀-寫并發(fā)控制
using LiteDB;
namespace App13
{
// 產(chǎn)品模型類
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 // 使用共享連接模式
};
// 初始化數(shù)據(jù)庫(kù)
InitializeDatabase();
}
private void InitializeDatabase()
{
using (var db = new LiteDatabase(_connectionString))
{
var collection = db.GetCollection<Product>("products");
// 如果集合為空,添加測(cè)試數(shù)據(jù)
if (!collection.Find(Query.All()).Any())
{
var products = new List<Product>
{
new Product
{
Name = "舊產(chǎn)品",
Price = 150.00m,
Stock = 10,
CreateTime = DateTime.Now.AddDays(-10)
},
new Product
{
Name = "常規(guī)產(chǎn)品",
Price = 99.99m,
Stock = 20,
CreateTime = DateTime.Now.AddDays(-5)
}
};
collection.InsertBulk(products);
}
}
}
public void SafeConcurrentAccess()
{
try
{
// 為每個(gè)操作創(chuàng)建單獨(dú)的數(shù)據(jù)庫(kù)連接
Parallel.Invoke(
() => ReadProducts(),
() => WriteProducts(),
() => UpdateProducts(),
() => DeleteProducts(),
() => QueryProducts()
);
}
catch (Exception ex)
{
Console.WriteLine($"并發(fā)操作出錯(cuò): {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()} 個(gè)高價(jià)產(chǎn)品");
foreach (var product in products)
{
Console.WriteLine($"產(chǎn)品: {product.Name}, 價(jià)格: {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 = $"新產(chǎn)品_{DateTime.Now.Ticks}",
Price = 199.99m,
Stock = 5,
CreateTime = DateTime.Now
};
collection.Insert(newProduct);
Console.WriteLine($"成功添加新產(chǎn)品: {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 == "舊產(chǎn)品");
if (product != null)
{
product.Price *= 1.1m;
product.Stock -= 1;
collection.Update(product);
Console.WriteLine($"更新產(chǎn)品價(jià)格: {product.Name} 新價(jià)格: {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} 個(gè)庫(kù)存為0的產(chǎn)品");
}
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個(gè)高價(jià)產(chǎn)品:");
foreach (var item in query)
{
Console.WriteLine($"名稱: {item.Name}, 價(jià)格: {item.Price:C}, 庫(kù)存: {item.Stock}");
}
}
catch (Exception ex)
{
Console.WriteLine($"查詢操作失敗: {ex.Message}");
}
}
}
public void Dispose()
{
// 實(shí)現(xiàn) IDisposable
GC.SuppressFinalize(this);
}
}
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("開(kāi)始多線程數(shù)據(jù)庫(kù)訪問(wèn)測(cè)試...\n");
using (var demo = new MultiThreadAccess())
{
// 執(zhí)行多次并發(fā)測(cè)試
for (int i = 0; i < 3; i++)
{
Console.WriteLine($"\n=== 測(cè)試輪次 {i + 1} ===\n");
demo.SafeConcurrentAccess();
Thread.Sleep(1000); // 暫停一秒后進(jìn)行下一輪測(cè)試
}
}
Console.WriteLine("\n測(cè)試完成!按任意鍵退出...");
Console.ReadKey();
}
}
}
圖片
Connection = ConnectionType.Shared 這是重點(diǎn)。
性能注意事項(xiàng)
- LiteDB 是單線程數(shù)據(jù)庫(kù),并發(fā)控制依賴于應(yīng)用層鎖
- 對(duì)于高并發(fā)場(chǎng)景,考慮使用更強(qiáng)大的數(shù)據(jù)庫(kù)系統(tǒng)
- 優(yōu)化鎖的使用范圍,減少鎖定時(shí)間
- 盡可能使用細(xì)粒度鎖
- 避免長(zhǎng)時(shí)間持有鎖
- 使用 Parallel.For 和 Task 進(jìn)行并發(fā)操作
- 實(shí)現(xiàn)詳細(xì)的錯(cuò)誤處理和日志記錄
總結(jié)
這篇文章主要討論了LiteDB數(shù)據(jù)庫(kù)的并發(fā)控制機(jī)制。文章介紹了共享鎖和排他鎖兩種鎖機(jī)制的實(shí)現(xiàn)方式,以及在多線程環(huán)境下如何安全地進(jìn)行數(shù)據(jù)讀寫操作。同時(shí)還探討了多設(shè)備數(shù)據(jù)同步的實(shí)現(xiàn)方案,包括時(shí)間戳比對(duì)和沖突解決策略。由于LiteDB是單線程數(shù)據(jù)庫(kù),文章強(qiáng)調(diào)了在應(yīng)用層實(shí)現(xiàn)適當(dāng)?shù)逆i策略和同步技術(shù)的重要性,以確保數(shù)據(jù)一致性和完整性。