面试题答案
一键面试事务管理
在Entity Framework Core中,可以使用DbContext.Database.BeginTransaction
方法来开始一个事务。当所有操作完成后,调用DbContext.SaveChanges
方法保存更改,并调用DbContext.Database.CommitTransaction
提交事务。如果出现异常,调用DbContext.Database.RollbackTransaction
回滚事务。
锁机制
- 悲观锁:可以在查询时使用
ForUpdate
(SQL Server)或ForShare
(PostgreSQL)等方法获取锁。例如,在获取库存数据时,确保其他事务不能修改该数据。 - 乐观锁:在库存表中添加一个版本字段(如
RowVersion
)。每次更新库存时,EF Core会检查该版本字段的值是否与数据库中的一致。如果不一致,说明数据已被其他事务修改,此时会抛出异常,应用程序需要处理该异常并重试操作。
避免死锁
- 按相同顺序访问资源:确保所有事务以相同的顺序访问库存数据,避免循环依赖导致的死锁。
- 设置合理的超时时间:在获取锁或执行事务时,设置合理的超时时间,当超过该时间未获取到锁或完成事务时,自动放弃操作并回滚事务。
关键代码示例
以下是使用悲观锁和事务管理的示例代码:
using (var transaction = _context.Database.BeginTransaction())
{
try
{
// 使用悲观锁获取库存数据
var inventory = _context.Inventories
.Where(i => i.ProductId == productId)
.ForUpdate()
.FirstOrDefault();
if (inventory != null)
{
// 库存增减操作
if (isIncrease)
{
inventory.Quantity += quantity;
}
else
{
if (inventory.Quantity >= quantity)
{
inventory.Quantity -= quantity;
}
else
{
// 库存不足处理
throw new InvalidOperationException("库存不足");
}
}
_context.SaveChanges();
transaction.Commit();
}
}
catch (Exception ex)
{
transaction.Rollback();
// 异常处理
throw;
}
}
以下是使用乐观锁的示例代码:
- 数据库表结构:库存表添加
RowVersion
字段(在SQL Server中类型为rowversion
,在其他数据库中有类似的实现)。 - C#代码:
using (var transaction = _context.Database.BeginTransaction())
{
try
{
var inventory = _context.Inventories
.Where(i => i.ProductId == productId)
.FirstOrDefault();
if (inventory != null)
{
// 库存增减操作
if (isIncrease)
{
inventory.Quantity += quantity;
}
else
{
if (inventory.Quantity >= quantity)
{
inventory.Quantity -= quantity;
}
else
{
// 库存不足处理
throw new InvalidOperationException("库存不足");
}
}
try
{
_context.SaveChanges();
transaction.Commit();
}
catch (DbUpdateConcurrencyException ex)
{
// 乐观锁冲突处理,重试逻辑
var entry = ex.Entries.Single();
var clientValues = (Inventory)entry.Entity;
var databaseEntry = entry.GetDatabaseValues();
if (databaseEntry == null)
{
throw new InvalidOperationException(
"无法从数据库中重新加载实体。");
}
var databaseValues = (Inventory)databaseEntry.ToObject();
if (databaseValues.Quantity != clientValues.Quantity)
{
// 库存已被其他事务修改,重新获取库存并处理
var newInventory = _context.Inventories
.Where(i => i.ProductId == productId)
.FirstOrDefault();
// 重新计算操作
//...
_context.SaveChanges();
transaction.Commit();
}
}
}
}
catch (Exception ex)
{
transaction.Rollback();
// 异常处理
throw;
}
}
通过上述方法,可以在高并发的Web应用程序中,利用Entity Framework Core的特性,结合合理的事务管理和锁机制,保证数据的一致性和并发性能,同时避免死锁等问题。