学了数据库理论知识,我们都知道数据库中有个锁概念,但是我们在软件开发过程中似乎从来没特别指定过锁,那么这个锁到底存不存在呢?
在类似 SQL Server 这类大型数据库管理系统中是存在的,程序中没指定锁的话,就是自动的。
示例一、
代码执行顺序为:
在数据库管理系统中执行顺序为:
没啥区别呀,这有啥锁呀?不急,继续看:
示例二、
代码执行顺序为:
在数据库管理系统中执行顺序为:
这次仅仅因为第 1 步由读取记录变成了更新记录,所以事务 B 就得等事务 A 执行完了再执行,所以说呀,这个锁是自动的,而且还挺聪明,能够识别加什么样的锁。
事务 B 为什么要去等事务 A 呢?试想一下,如果事务 A 最后 1 步更新时失败,就会导致第 1 步被会撤销(事务的特性就是这样,要么都成功,要么都失败),为了避免事务 B 读取的数据是被撤销的数据,所以就让事务 B 等一等了,等事务 A 完成,确认数据不会被撤销了,再来读取。
小结一下:在事务 A,当执行到 update 时,就会在这里开始加锁,事务 B 若在加锁后执行到 select、update 相同的表时,就会等待事务 A 结束。(注意是执行到 select、update 相同的表时开始等待,并不是事务 B 一开始就等待。)
示例三、
代码执行顺序为:
在数据库管理系统中执行顺序为:
嘿,这回又变了,足见锁的聪明:
它知道事务 A 的第 1 步更新并不与事务 B 冲突,所以事务 B 并没有等待;
事务 A 的最后 1 步本身就位于事务 B 的后面,它更新成功与否不影响事务 B 的脏不脏读问题,所以按顺序执行。
我们在实际使用过程中,如果要求不是很严格,并发量不是很大,大多数也不需要关注上述理论,只需要知道有这么回事即可。但如果并发量很大,要求又高(比如金融),这就必须考虑,此时可以认真阅读一下本文。如果你想亲自测试一下,我们建议用两个线程,再加 Thread.Sleep 让代码执行顺序固定下来,看看最终在数据库管理系统中的执行顺序与代码执行顺序有何差别。
扩展一下
在同一事务中:
1、事务开始
2、更新表记录
3、选取表记录
4、更新表记录(这次失败了,事务撤销)
最终数据库中的表记录没有更新,但第 3 步选出来的记录仍然是第 2 步更新之后的记录。
相关阅读