暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

C# LiteDB 事务管理深度解析

技术老小子 2025-02-23
13

在现代软件开发中,数据的可靠性和一致性至关重要。每一个数据库操作都潜藏着风险:一个意外的系统崩溃、一个未处理的异常,都可能导致数据的部分损坏或完全丢失。这就是为什么事务管理成为数据库设计中最关键的特性之一。

对于追求轻量级、高效率的开发者来说,LiteDB 是一个令人兴奋的选择。它不仅提供了简单直观的 API,还内置了强大的事务管理机制。本文将深入探索 LiteDB 的事务世界,揭示如何通过精妙的事务控制,为您的应用程序构建坚不可摧的数据保护屏障。

无论您是一名经验丰富的开发者,还是刚开始接触数据库编程的新手,这篇文章都将为您呈现 LiteDB 事务管理的方方面面:从基本的 ACID 特性,到复杂的事务处理模式,我们将带您穿越数据一致性的迷雾,直达技术的璀璨之巅。

事务的ACID特性

事务(Transaction)是数据库管理系统中确保数据一致性和完整性的关键机制。在 LiteDB 中,事务遵循经典的 ACID 特性:

A - 原子性(Atomicity)

  • 事务中的所有操作要么全部成功,要么全部回滚
  • 保证了数据操作的不可分割性

C - 一致性(Consistency)

  • 事务执行前后,数据库的状态必须保持一致
  • 防止事务导致数据库处于不合法的状态

I - 隔离性(Isolation)

  • 并发执行的事务相互隔离,互不影响
  • 防止多个事务同时操作同一数据时产生冲突

D - 持久性(Durability)

  • 事务一旦提交,其修改将永久保存
  • 即使系统发生故障,已提交的事务不会丢失

LiteDB 显式事务管理

Nuget 安装LiteDB

基本显式事务示例

// 用户实体类
public class User
{

    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

复制
using LiteDB;

namespace App12
{
    internal class Program
    {

        static void Main(string[] args)
        
{
            PerformExplicitTransaction();
        }

        public static void PerformExplicitTransaction()
        
{
            // 使用数据库连接字符串创建数据库实例
            using (var db = new LiteDatabase(@"MyDatabase.db"))
            {
                try
                {
                    // 开始显式事务
                    db.BeginTrans();

                    // 获取用户集合
                    var users = db.GetCollection<User>("users");

                    // 执行多个操作
                    var newUser = new User
                    {
                        Name = "张三",
                        Age = 30
                    };
                    users.Insert(newUser);

                    // 更新另一个用户
                    var existingUser = users.FindOne(u => u.Name == "李四");
                    if (existingUser != null)
                    {
                        existingUser.Age += 1;
                        users.Update(existingUser);
                    }

                    // 提交事务
                    db.Commit();
                    Console.WriteLine("事务成功提交");
                }
                catch (Exception ex)
                {
                    // 发生异常时回滚事务
                    db.Rollback();
                    Console.WriteLine($"事务回滚:{ex.Message}");
                }

            }
        }
    }
}

复制

事务回滚场景

using LiteDB;  
namespace App12  
{  
    // 定义银行账户类  
    publicclass BankAccount  
    {

        public ObjectId Id { get; set; }  
        publicstring AccountNumber { get; set; }  
        public decimal Balance { get; set; }  
    }  

    internal class Program  
    {

        static void Main(string[] args)  
        
{  
            // 先初始化数据  
            InitializeDatabase();  

            Console.WriteLine("转账演示开始...");  
            Console.WriteLine("-------------------");  

            // 显示初始余额  
            DisplayAllAccounts();  

            // 执行转账操作  
            TransactionRollbackDemo();  

            // 显示转账后的余额  
            Console.WriteLine("\n转账后的账户余额:");  
            DisplayAllAccounts();  
        }  

        // 初始化数据库  
        public static void InitializeDatabase()  
        
{  
            using (var db = new LiteDatabase(@"MyDatabase.db"))  
            {  
                var accounts = db.GetCollection<BankAccount>("accounts");  

                // 清空已有数据  
                accounts.DeleteAll();  

                // 插入初始账户  
                accounts.Insert(new BankAccount { AccountNumber = "1001", Balance = 1000 });  
                accounts.Insert(new BankAccount { AccountNumber = "1002", Balance = 1000 });  

                Console.WriteLine("数据库初始化完成");  
            }  
        }  

        // 显示所有账户余额  
        public static void DisplayAllAccounts()  
        
{  
            using (var db = new LiteDatabase(@"MyDatabase.db"))  
            {  
                var accounts = db.GetCollection<BankAccount>("accounts");  
                var allAccounts = accounts.FindAll();  

                Console.WriteLine("\n当前所有账户余额:");  
                foreach (var account in allAccounts)  
                {  
                    Console.WriteLine($"账户 {account.AccountNumber}: {account.Balance:C}");  
                }  
            }  
        }  

        public static void TransactionRollbackDemo()  
        
{  
            using (var db = new LiteDatabase(@"MyDatabase.db"))  
            {  
                db.BeginTrans();  

                try
                {  
                    var accounts = db.GetCollection<BankAccount>("accounts");  

                    // 模拟银行转账  
                    var fromAccount = accounts.FindOne(a => a.AccountNumber == "1001");  
                    var toAccount = accounts.FindOne(a => a.AccountNumber == "1002");  

                    decimal transferAmount = 1500// 转账金额大于余额,将触发异常  
                    Console.WriteLine($"\n尝试从账户 {fromAccount.AccountNumber} 转账 {transferAmount:C} 到账户 {toAccount.AccountNumber}");  

                    // 检查余额是否充足  
                    if (fromAccount.Balance < transferAmount)  
                    {  
                        // 余额不足,抛出异常触发回滚  
                        thrownew InvalidOperationException("余额不足,无法转账");  
                    }  

                    // 扣除转出账户余额  
                    fromAccount.Balance -= transferAmount;  
                    accounts.Update(fromAccount);  

                    // 增加转入账户余额  
                    toAccount.Balance += transferAmount;  
                    accounts.Update(toAccount);  

                    // 提交事务  
                    db.Commit();  
                    Console.WriteLine("转账成功");  
                }  
                catch (Exception ex)  
                {  
                    // 发生异常,回滚所有操作  
                    db.Rollback();  
                    Console.WriteLine($"转账失败:{ex.Message}");  
                }  
            }  
        }  
    }  
}

复制

LiteDB 隐式事务应用

单一操作的隐式事务

LiteDB 对于单个操作(如插入、更新、删除)会自动管理事务:

using LiteDB;

namespace App12
{
    publicclass Product
    {

        public ObjectId Id { get; set; }  // 使用 LiteDB 的 ObjectId 作为主键  
        publicstring Name { get; set; }
        public decimal Price { get; set; }
        publicint Stock { get; set; }     // 添加库存字段  
        public DateTime CreatedDate { get; set; }
    }

    internal class Program
    {

        static void Main(string[] args)
        
{
            // 初始化产品数据  
            InitializeProducts();

            Console.WriteLine("初始产品列表:");
            DisplayAllProducts();

            // 测试隐式事务  
            ImplicitTransactionDemo();

            Console.WriteLine("\n操作后的产品列表:");
            DisplayAllProducts();
        }

        public static void InitializeProducts()
        
{
            using (var db = new LiteDatabase(@"MyDatabase.db"))
            {
                var products = db.GetCollection<Product>("products");

                // 清空现有数据  
                products.DeleteAll();

                // 插入初始产品数据  
                products.Insert(new Product
                {
                    Name = "智能手机",
                    Price = 3999.99m,
                    Stock = 50,
                    CreatedDate = DateTime.Now
                });

                products.Insert(new Product
                {
                    Name = "平板电脑",
                    Price = 4599.99m,
                    Stock = 30,
                    CreatedDate = DateTime.Now
                });

                // 创建索引  
                products.EnsureIndex(x => x.Name);

                Console.WriteLine("产品数据初始化完成");
            }
        }

        public static void DisplayAllProducts()
        
{
            using (var db = new LiteDatabase(@"MyDatabase.db"))
            {
                var products = db.GetCollection<Product>("products");
                var allProducts = products.FindAll();

                Console.WriteLine("\n产品列表:");
                Console.WriteLine("----------------------------------------");
                Console.WriteLine("名称\t\t价格\t\t库存\t创建时间");
                Console.WriteLine("----------------------------------------");

                foreach (var product in allProducts)
                {
                    Console.WriteLine($"{product.Name,-16}{product.Price,10:C}{product.Stock,8}\t{product.CreatedDate:yyyy-MM-dd}");
                }
                Console.WriteLine("----------------------------------------");
            }
        }

        public static void ImplicitTransactionDemo()
        
{
            using (var db = new LiteDatabase(@"MyDatabase.db"))
            {
                var products = db.GetCollection<Product>("products");

                try
                {
                    // 1. 插入新产品(单一操作,LiteDB 自动管理事务)  
                    var newProduct = new Product
                    {
                        Name = "笔记本电脑",
                        Price = 5999.99m,
                        Stock = 20,
                        CreatedDate = DateTime.Now
                    };
                    products.Insert(newProduct);
                    Console.WriteLine("\n新产品添加成功:" + newProduct.Name);

                    // 2. 更新现有产品价格(原子操作)  
                    var existingProduct = products.FindOne(p => p.Name == "智能手机");
                    if (existingProduct != null)
                    {
                        decimal oldPrice = existingProduct.Price;
                        existingProduct.Price -= 500;
                        products.Update(existingProduct);
                        Console.WriteLine($"\n产品'{existingProduct.Name}'价格更新成功:");
                        Console.WriteLine($"原价:{oldPrice:C} -> 新价:{existingProduct.Price:C}");
                    }

                    // 3. 补充库存(原子操作)  
                    var tabletProduct = products.FindOne(p => p.Name == "平板电脑");
                    if (tabletProduct != null)
                    {
                        int oldStock = tabletProduct.Stock;
                        tabletProduct.Stock += 10;
                        products.Update(tabletProduct);
                        Console.WriteLine($"\n产品'{tabletProduct.Name}'库存更新成功:");
                        Console.WriteLine($"原库存:{oldStock} -> 新库存:{tabletProduct.Stock}");
                    }

                    // 4. 删除过期产品(如果存在)  
                    var result = products.DeleteMany(p => p.CreatedDate < DateTime.Now.AddYears(-1));
                    if (result > 0)
                    {
                        Console.WriteLine($"\n删除了 {result} 个过期产品");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"\n操作出错:{ex.Message}");
                }
            }
        }

        // 添加一个辅助方法来搜索产品  
        public static void SearchProducts(string keyword)
        
{
            using (var db = new LiteDatabase(@"MyDatabase.db"))
            {
                var products = db.GetCollection<Product>("products");
                var searchResults = products.Find(p => p.Name.Contains(keyword));

                Console.WriteLine($"\n搜索结果 (关键词: {keyword}):");
                Console.WriteLine("----------------------------------------");
                foreach (var product in searchResults)
                {
                    Console.WriteLine($"{product.Name} - {product.Price:C} - 库存:{product.Stock}");
                }
                Console.WriteLine("----------------------------------------");
            }
        }
    }
}

复制

批量操作的隐式事务

对于批量操作,建议使用显式事务以获得更好的性能和控制:

using LiteDB;
using System;
using System.Collections.Generic;
using System.Linq;

namespace App12
{
    publicclass Order
    {

        public ObjectId Id { get; set; }
        publicstring OrderNumber { get; set; }
        public DateTime OrderDate { get; set; }
        public decimal TotalAmount { get; set; }
        publicstring CustomerName { get; set; }
        publicstring Status { get; set; }  // 订单状态:Pending, Completed, Cancelled  
        public List<OrderItem> Items { get; set; }
    }

    publicclass OrderItem
    {

        publicstring ProductName { get; set; }
        publicint Quantity { get; set; }
        public decimal UnitPrice { get; set; }
        public decimal Subtotal => Quantity * UnitPrice;
    }

    internal class Program
    {

        static void Main(string[] args)
        
{
            var program = new Program();

            Console.WriteLine("开始批量订单操作演示...");
            program.BatchOperationDemo();

            Console.WriteLine("\n订单统计信息:");
            program.DisplayOrderStatistics();
        }

        public void BatchOperationDemo()
        
{
            using (var db = new LiteDatabase(@"MyDatabase.db"))
            {
                var orders = db.GetCollection<Order>("orders");

                // 清空现有订单  
                orders.DeleteAll();

                // 创建索引  
                orders.EnsureIndex(x => x.OrderNumber, unique: true);
                orders.EnsureIndex(x => x.OrderDate);
                orders.EnsureIndex(x => x.CustomerName);

                // 使用显式事务处理批量操作  

                try
                {
                    db.BeginTrans();
                    Console.WriteLine("开始生成订单...");

                    // 批量插入订单  
                    var newOrders = GenerateOrders(100);
                    orders.InsertBulk(newOrders);

                    // 模拟一些额外的操作  
                    UpdateRandomOrderStatus(orders);

                    db.Commit();
                    Console.WriteLine($"成功插入 {newOrders.Count()} 个订单");

                    // 显示一些示例订单  
                    DisplaySampleOrders(orders);
                }
                catch (Exception ex)
                {
                    db.Rollback();
                    Console.WriteLine($"批量操作失败:{ex.Message}");
                }

            }
        }

        private IEnumerable<Order> GenerateOrders(int count)
        {
            var random = new Random();
            var customers = new[] { "张三""李四""王五""赵六""钱七" };
            var products = new[]
            {
                ("笔记本电脑"5999m),
                ("智能手机"3999m),
                ("平板电脑"2999m),
                ("智能手表"1999m),
                ("蓝牙耳机"999m)
            };

            for (int i = 0; i < count; i++)
            {
                var orderItems = new List<OrderItem>();
                var itemCount = random.Next(14); // 每个订单1-3个商品  

                for (int j = 0; j < itemCount; j++)
                {
                    var product = products[random.Next(products.Length)];
                    orderItems.Add(new OrderItem
                    {
                        ProductName = product.Item1,
                        Quantity = random.Next(14),
                        UnitPrice = product.Item2
                    });
                }

                var order = new Order
                {
                    OrderNumber = $"ORD{DateTime.Now:yyyyMMdd}{i + 1:D4}",
                    OrderDate = DateTime.Now.AddDays(-random.Next(030)),
                    CustomerName = customers[random.Next(customers.Length)],
                    Status = "Pending",
                    Items = orderItems,
                    TotalAmount = orderItems.Sum(item => item.Subtotal)
                };

                yield return order;
            }
        }

        private void UpdateRandomOrderStatus(ILiteCollection<Order> orders)
        
{
            var random = new Random();
            var statuses = new[] { "Completed""Cancelled" };

            // 随机更新一些订单状态  
            var someOrders = orders.Find(Query.All(), limit: 20);
            foreach (var order in someOrders)
            {
                if (random.Next(2) == 0// 50% 的概率更新状态  
                {
                    order.Status = statuses[random.Next(statuses.Length)];
                    orders.Update(order);
                }
            }
        }

        private void DisplaySampleOrders(ILiteCollection<Order> orders)
        
{
            Console.WriteLine("\n示例订单信息:");
            Console.WriteLine("----------------------------------------");

            var sampleOrders = orders.Find(Query.All(), limit: 5);
            foreach (var order in sampleOrders)
            {
                Console.WriteLine($"订单号: {order.OrderNumber}");
                Console.WriteLine($"客户: {order.CustomerName}");
                Console.WriteLine($"日期: {order.OrderDate:yyyy-MM-dd}");
                Console.WriteLine($"状态: {order.Status}");
                Console.WriteLine("商品列表:");
                foreach (var item in order.Items)
                {
                    Console.WriteLine($"  - {item.ProductName} x {item.Quantity} @ {item.UnitPrice:C} = {item.Subtotal:C}");
                }
                Console.WriteLine($"总金额: {order.TotalAmount:C}");
                Console.WriteLine("----------------------------------------");
            }
        }

        public void DisplayOrderStatistics()
        
{
            using (var db = new LiteDatabase(@"MyDatabase.db"))
            {
                var orders = db.GetCollection<Order>("orders");

                var totalOrders = orders.Count();
                var totalAmount = orders.FindAll().Sum(o => o.TotalAmount);
                var pendingOrders = orders.Count(Query.EQ("Status""Pending"));
                var completedOrders = orders.Count(Query.EQ("Status""Completed"));
                var cancelledOrders = orders.Count(Query.EQ("Status""Cancelled"));

                Console.WriteLine($"订单总数: {totalOrders}");
                Console.WriteLine($"订单总金额: {totalAmount:C}");
                Console.WriteLine($"待处理订单: {pendingOrders}");
                Console.WriteLine($"已完成订单: {completedOrders}");
                Console.WriteLine($"已取消订单: {cancelledOrders}");

                // 按客户统计  
                var customerOrders = orders.FindAll()
                    .GroupBy(o => o.CustomerName)
                    .Select(g => new
                    {
                        Customer = g.Key,
                        OrderCount = g.Count(),
                        TotalAmount = g.Sum(o => o.TotalAmount)
                    })
                    .OrderByDescending(x => x.TotalAmount);

                Console.WriteLine("\n客户订单统计:");
                Console.WriteLine("----------------------------------------");
                foreach (var stat in customerOrders)
                {
                    Console.WriteLine($"客户: {stat.Customer}");
                    Console.WriteLine($"订单数: {stat.OrderCount}");
                    Console.WriteLine($"总金额: {stat.TotalAmount:C}");
                    Console.WriteLine("----------------------------------------");
                }
            }
        }
    }
}

复制

5. 注意事项

  • LiteDB 是一个轻量级的嵌入式数据库,事务管理相对简单
  • 对于高并发场景,可能需要考虑更复杂的并发控制机制
  • 始终关注异常处理和事务回滚逻辑
  • 对于复杂的、多步骤的数据库操作,始终使用显式事务
  • 尽可能缩小事务的作用范围,提高并发性能
  • 捕获并处理可能的异常,确保事务能正确回滚
  • 对于大批量数据操作,考虑分批处理以减少内存压力

结论

通过合理使用 LiteDB 的事务管理机制,可以确保数据的一致性和完整性,为应用程序提供可靠的数据持久化解决方案。


如果你正在从事上位机、自动化、机器视觉、物联网(IOT)项目或数字化转型方面的工作,欢迎加入我的微信圈子!在这里,我们不仅可以轻松畅聊最新技术动态和行业趋势,还能够在技术问题上互相帮助和支持。我会尽量利用我的知识和经验来帮助你解决问题,当然也期待从大家的专业见解中学习和成长。无论你是新手还是老鸟,期待与志同道合的朋友交流心得,一起进步!



文章转载自技术老小子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论