Entity Framework Core与MySQL中并发异常未触发的问题排查
解决MySQL下EF Core并发异常未触发的问题
1. 正确配置实体与Fluent API
首先确保实体类的RowVersion属性为byte[]类型(适配MySQL的BINARY(8)字段):
public class EntityType { // 其他业务属性 public byte[] RowVersion { get; set; } }
在DbContext的OnModelCreating方法中完成并发令牌配置:
modelBuilder.Entity<EntityType>() .Property(a => a.RowVersion) .IsConcurrencyToken() // 标记该字段为并发校验令牌 .ValueGeneratedOnAddOrUpdate() // 指定字段值由数据库在新增/更新时自动生成 .HasColumnType("BINARY(8)"); // 映射到MySQL的BINARY(8)字段类型
2. 配置MySQL自动维护RowVersion值
MySQL没有SQL Server原生的自动timestamp机制,需通过触发器实现新增/更新时自动刷新RowVersion:
-- 新增数据时生成RowVersion DELIMITER // CREATE TRIGGER tr_entitytype_insert_rowversion BEFORE INSERT ON EntityType FOR EACH ROW BEGIN SET NEW.RowVersion = UUID_TO_BIN(UUID(), 1); -- 生成紧凑的8字节UUID作为版本值 END // DELIMITER ; -- 更新数据时刷新RowVersion DELIMITER // CREATE TRIGGER tr_entitytype_update_rowversion BEFORE UPDATE ON EntityType FOR EACH ROW BEGIN SET NEW.RowVersion = UUID_TO_BIN(UUID(), 1); END // DELIMITER ;
若偏好使用TIMESTAMP类型,可简化配置(无需触发器,MySQL自动维护):
modelBuilder.Entity<EntityType>() .Property(a => a.RowVersion) .IsConcurrencyToken() .ValueGeneratedOnAddOrUpdate() .HasColumnType("TIMESTAMP") .HasDefaultValueSql("CURRENT_TIMESTAMP") .HasUpdateTimestamp(); // 告知EF Core此字段会在更新时自动刷新
3. 升级MySQL EF Core驱动版本
旧版本的MySQL EF驱动存在并发检测bug,建议升级至最新版的:
- Pomelo.EntityFrameworkCore.MySql(社区维护,推荐)
- 或MySql.EntityFrameworkCore(官方驱动)
4. 兜底方案:手动校验更新行数
若上述配置仍未自动抛出异常,可在调用SaveChanges后手动检测受影响行数并抛出异常:
int affectedRows = await _context.SaveChangesAsync(); if (affectedRows == 0) { throw new DbUpdateConcurrencyException("并发冲突:数据已被其他用户修改"); }
验证逻辑
- 第一个请求修改实体并保存,数据库
RowVersion自动更新 - 第二个请求先查询旧实体(携带旧
RowVersion),修改后执行保存 - EF Core生成的Update语句会包含
WHERE ... AND RowVersion = @oldRowVersion条件,因第一个请求已更新版本值,此语句受影响行数为0,EF Core会自动抛出DbUpdateConcurrencyException
内容的提问来源于stack exchange,提问作者TiGreX
相关产品推荐
相关产品推荐

