private static void Start() { Stopwatch sw = new Stopwatch(); sw.Start(); Action action = () => { using (var db = new EFDBContext()) { db.Database.ExecuteSqlCommand("select num from stock where id=1 for update;update stock set num=num-1 where id=1"); } }; List<Task> tasks = new List<Task>(); for (var i = 0; i < 50; i++) { tasks.Add(new Task(action)); } tasks.ForEach((obj) => { obj.Start(); }); Task.WaitAll(tasks.ToArray()); sw.Stop(); Console.WriteLine("总耗时:" + sw.Elapsed.TotalSeconds + " 秒"); }
请教个几个问题:
1. 上面的代码做悲观锁正确嘛?
2. 当50个Task一起执行时,后面抛异常,无法连接数据库(是不是超时了)?
麻烦大家指点下,谢谢。
对,抛异常可能是你连接池没有连接了,另说下你这样用ef还不如直接用ado.net
ps下,如果你本意就是你sql的话你直接update就可以了。
@Daniel Cai: 感谢回复, 我改成ado.net了. 谢谢.
@Daniel Cai: 你好, 如果不用EF,直接用ado.net处理update语句, 还需要用锁吗?
@待来年山花烂漫之时: 这个和用什么框架无关,如果你仅仅只需要那个更新,你在执行update的时候就会获取一个u锁。这个锁可以展开为一个s锁和一个x锁,而s锁很快就会升级为x锁(因为找到更新行要进行更新)。而u锁对其他u锁有排他,因此这里不会产生死锁。
@Daniel Cai: 哦,那如果我需要先判断当前记录的数量,如果数量小于10,才更新数量, 就是先有判断,然后在确实是否需要更新值,这种场景需要先查记录加锁,在判断后更新吧?
@待来年山花烂漫之时:
update tb set num=num-1 where id=@id and num<10
@Daniel Cai: 哈哈, 好想法, 谢谢.
你这样说不太妥吧?你意思是说要用悲观锁就不能用EF了吗
为什么要多次using 而不是把 action放在using中
最烦那些什么你这样用ef还不如不用的“大佬”了
如果你们不会用EF就不要出来误导别人,菜刀只能用来切菜不能用来切肉吗?
如果你们学识不够就请不要回答。
关于EF用悲观锁不难,用事务+sql执行即可,具体可以看我博客。