EF CORE 使用排他锁 干货 方法 悲观锁 entity framework 悲观锁
这几天在升级.NET CORE版本,结果发现坑太大了,最后还是退级了。。原因是作为长期支持版本的3.1居然一大堆bug 官方没有解决。。
查询了国内官方的基本没人讨论过EF怎么加悲观锁,很是蛋疼,去谷歌搜了一圈,把资料搬回来了。
废话不多说,一般来说EF是用不了排他锁的,也就是悲观锁,但是可以用曲线救国的办法实现,这对并发处理是至关重要的,不知道为什么官方居然不支持。
首先我用的数据库是mysql,引擎必须要InnoDB才支持行级锁,如果你的引擎不是可以用这个修改
alter table 表名 engine=InnoDB;
每个表的引擎都可以是单独不一样的,很多人使用锁失败可能是一开始就用不对引擎,以为全局引擎是lnnoDB就以为表也是这个引擎了,其实不是,查看办法可以用mysql for Navicat 设计-选项自己看看。
要加锁的话必须在查询背后添加 for update,这样查询的时候就会开始等待
for update 只能用来等待加了for update 的,如果你的select 没有加for update ,那也是等于无锁,这个网上很多解释了,反正你想等待,那就得一起加上for update ,否则有一个没加的,那那个就可以直接查询到结果而不会等待。不赘述了,网上解释一大堆。
好了,在EF CORE使用,那就引用一个事务,套个框框即可
using (var context = new DatabaseContext()) {
//套上事务 using (IDbContextTransaction transaction = context.Database.BeginTransaction()) { string sqlQuery = "select * from 表名 where id =1 for update"; var info = context.表名.FromSql(sqlQuery).FirstOrDefault();
//这个时候查询已经被锁住了,可以做你要的事了
//TODO
//完成提交事务即可
transaction.Commit();
} }
记得用using哦,这样如果操作失败,EF会自动调用transaction.Rollback()进行数据回滚,不会造成脏数据~一个事务就是一个最小的操作单元,要么都成功要么都失败!
如果要锁住行,这个查询条件一定要是可以索引的,或者是主键,否则会锁住整个表,非常不好。
关键点:
1:所有需要等待的语句必须都使用for update
2:表的引擎一定要是InnoDB,而不是全局引擎
3:查询条件一定要加索引,或者主键
这样基本就ok了,我现在还是在用EFCORE1.0,升级成3.0后就没有FromSql了,变成FromSqlRaw,为什么不升级3.0,是因为官方存在内存泄露,顶级投影被削弱,重要的关键根本没改进,还不如不要,折腾了我一整个春节。。有感兴趣的我再说吧。。