您好,登录后才能下订单哦!
密码登录
            
            
            
            
        登录注册
            
            
            
        点击 登录注册 即表示同意《亿速云用户服务条款》
        # C# 中怎么解决数据库并发
## 目录
1. [并发问题概述](#并发问题概述)
2. [数据库并发控制机制](#数据库并发控制机制)
3. [C# 中的事务处理](#c-中的事务处理)
4. [乐观并发控制实现](#乐观并发控制实现)
5. [悲观并发控制实现](#悲观并发控制实现)
6. [EF Core 并发解决方案](#ef-core-并发解决方案)
7. [分布式系统并发挑战](#分布式系统并发挑战)
8. [性能优化与最佳实践](#性能优化与最佳实践)
9. [实际案例解析](#实际案例解析)
10. [总结与展望](#总结与展望)
---
## 并发问题概述
(约800字)
### 什么是数据库并发
数据库并发指多个事务同时访问和修改相同数据资源的现象。在C#应用程序中,当多个用户/线程同时执行以下操作时可能引发并发问题:
- 读取-修改-写入序列
- 批量数据更新
- 长时间运行的事务
### 典型并发问题表现
1. **丢失更新**(Lost Update)
```csharp
// 线程A读取X=100
// 线程B读取X=100
// 线程A写入X=200
// 线程B写入X=150 → A的更新被覆盖
// 事务A修改X但未提交
// 事务B读取到未提交的X值
// 事务A首次读取X=100
// 事务B修改X=200并提交
// 事务A再次读取X得到不同结果
// 事务A查询得到N条记录
// 事务B插入新记录
// 事务A相同查询得到N+1条记录
(约1000字)
适用场景:读多写少、冲突概率低的环境
graph TD
    A[读取数据] --> B[修改数据]
    B --> C{提交时验证}
    C -->|版本匹配| D[提交更新]
    C -->|版本不匹配| E[回滚/重试]
适用场景:写密集、冲突概率高的环境
graph TD
    A[获取锁] --> B[执行操作]
    B --> C[释放锁]
现代数据库(如SQL Server、PostgreSQL)的核心机制
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | C#设置方式 | 
|---|---|---|---|---|
| Read Uncommitted | ✓ | ✓ | ✓ | IsolationLevel.ReadUncommitted | 
| Read Committed | × | ✓ | ✓ | IsolationLevel.ReadCommitted | 
| Repeatable Read | × | × | ✓ | IsolationLevel.RepeatableRead | 
| Serializable | × | × | × | IsolationLevel.Serializable | 
(约1200字)
using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    SqlTransaction transaction = conn.BeginTransaction(IsolationLevel.Serializable);
    
    try
    {
        using (SqlCommand cmd = new SqlCommand("UPDATE Accounts SET Balance = Balance - 100 WHERE Id = 1", conn, transaction))
        {
            cmd.ExecuteNonQuery();
        }
        
        transaction.Commit();
    }
    catch
    {
        transaction.Rollback();
        throw;
    }
}
using (TransactionScope scope = new TransactionScope(
    TransactionScopeOption.Required,
    new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
{
    // 跨多个连接的事务
    using (SqlConnection conn1 = new SqlConnection(connStr1))
    using (SqlConnection conn2 = new SqlConnection(connStr2))
    {
        // 操作多个数据库
    }
    
    scope.Complete();
}
async Task TransferFundsAsync()
{
    using (SqlConnection conn = new SqlConnection(connStr))
    {
        await conn.OpenAsync();
        using (SqlTransaction transaction = conn.BeginTransaction())
        {
            try
            {
                var cmd = new SqlCommand("UPDATE...", conn, transaction);
                await cmd.ExecuteNonQueryAsync();
                await transaction.CommitAsync();
            }
            catch
            {
                await transaction.RollbackAsync();
                throw;
            }
        }
    }
}
(约1500字)
ALTER TABLE Products ADD RowVersion rowversion;
var product = db.Products.Find(id);
product.Price = newPrice;
try
{
    db.SaveChanges(); // 自动验证RowVersion
}
catch (DbUpdateConcurrencyException ex)
{
    var entry = ex.Entries.Single();
    var dbValues = entry.GetDatabaseValues();
    
    // 处理策略选项
    if (overwrite)
    {
        entry.OriginalValues.SetValues(dbValues);
        db.SaveChanges();
    }
    else
    {
        // 提示用户冲突
    }
}
[Timestamp]
public byte[] Timestamp { get; set; }
var originalPrice = db.Products
    .AsNoTracking()
    .Where(p => p.Id == id)
    .Select(p => p.Price)
    .FirstOrDefault();
var rows = db.Products
    .Where(p => p.Id == id && p.Price == originalPrice)
    .Update(p => new Product { Price = newPrice });
if (rows == 0)
{
    throw new DbConcurrencyException();
}
(约1200字)
// 使用UPDLOCK保持更新锁
var sql = @"SELECT * FROM Orders WITH (UPDLOCK) 
            WHERE OrderId = @id";
            
using (var cmd = new SqlCommand(sql, conn, transaction))
{
    cmd.Parameters.AddWithValue("@id", orderId);
    // 处理订单...
}
// 使用MemoryCache实现简单锁
private static readonly MemoryCache _lockCache = new MemoryCache(new MemoryCacheOptions());
public bool AcquireLock(string key, TimeSpan timeout)
{
    return _lockCache.TryAdd(key, DateTime.Now, timeout);
}
public void ReleaseLock(string key)
{
    _lockCache.Remove(key);
}
// 使用Redis实现分布式锁
var redis = ConnectionMultiplexer.Connect("localhost");
var db = redis.GetDatabase();
var token = Guid.NewGuid().ToString();
if (db.LockTake("order_lock", token, TimeSpan.FromSeconds(30)))
{
    try
    {
        // 执行关键操作
    }
    finally
    {
        db.LockRelease("order_lock", token);
    }
}
(约1000字)
modelBuilder.Entity<Product>()
    .Property(p => p.RowVersion)
    .IsRowVersion()
    .IsConcurrencyToken();
graph LR
    A[SaveChanges] --> B{并发冲突?}
    B -->|是| C[DbUpdateConcurrencyException]
    C --> D[重载实体状态]
    D --> E[合并/覆盖策略选择]
    E --> F[重试机制]
    B -->|否| G[提交成功]
// 使用ExecuteUpdate避免读-修改-写
context.Products
    .Where(p => p.Category == "Electronics")
    .ExecuteUpdate(p => p.SetProperty(x => x.Price, x => x.Price * 1.1m));
(约800字)
| 方案 | 适用场景 | C#实现示例 | 
|---|---|---|
| 两阶段提交(2PC) | 强一致性要求 | MSDTC分布式事务 | 
| Saga模式 | 长业务流程 | Masstransit+Event Sourcing | 
| 乐观并发+重试 | 最终一致性 | Polly重试策略 | 
| CRDTs | 无冲突复制数据类型 | RedisGears模块 | 
(约800字)
| 因素 | 乐观并发 | 悲观并发 | 
|---|---|---|
| 冲突频率 | 低 | 高 | 
| 数据量 | 中小 | 大 | 
| 响应时间要求 | 敏感 | 不敏感 | 
| 系统架构 | 分布式 | 单体 | 
// 使用性能计数器监控
var pc = new PerformanceCounter(
    "SQLServer:Latches", 
    "Latch Waits/sec", 
    "_Total");
    
float latchWaits = pc.NextValue();
(约1000字)
// 使用存储过程实现原子操作
CREATE PROCEDURE DeductInventory
    @ProductId INT,
    @Quantity INT,
    @Version ROWVERSION
AS
BEGIN
    UPDATE Products 
    SET Stock = Stock - @Quantity
    WHERE ProductId = @ProductId 
    AND RowVersion = @Version
    
    RETURN @@ROWCOUNT
END
// C#调用
var rows = db.Database.ExecuteSqlRaw(
    "EXEC DeductInventory @p0, @p1, @p2",
    productId, quantity, version);
(约500字)
”`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。