十、锁
锁的目的是为了解决并发
锁的层次来说有两种:程序锁、数据库锁.
一、程序锁
二、数据库锁
1、锁的场景
1、建一个表,主键唯一,一个系统处理业务,就往表里添加数据,现在连个业务系统ID是一致的,业务ID又是唯一的,以当一个系统添加数据时,另一个系统是无法往表中添加数据的。插入数据成功的系统就可以操作业务逻辑,插入失败的系统就不能操作执行业务逻辑了。这就实现了数据库锁。
2、
T1:select * from table (请想象它需要执行1个小时之久,后面的sql语句请都这么想象)
T2: update table set column1=‘hello’
3、比如一个商品数量为1 业务一你查询耗时0.4毫秒更新耗费了0.6毫秒 业务二和业务一同一时间,也查询到商品数量为一耗时0.4毫秒的时候,然后,业务二也去更新 导致商品数量为负数了
(这种情况,查询和修改都不能分开,还必须放在一起,程序级分开的话,程序语句先执行查询,然后在修改,中间的间隔都会都会发生并发即程序执行查询操作共计0.4毫秒(其内程序运行耗时0.2毫秒,sql则也是0.2),修改操作共计则也是0.4(其内程序耗时0.2毫秒,sql则也是0.2)然后在程序修改的0.2内,业务2 查询也卡这里了)这也是 查询和修改不可以分开
写在一起的话,两种 一种是 sql 判断写在一个语句内,第二种 事务
sql查询不会用锁,但是修改的话, 比如 业务一查询0.2 业务二0.3 , 业务二执行查询0.2后又执行更新0.4毫秒,但是业务二执行查询0.3秒,而业务一更新0.4毫秒还没还没执行完。
总结:锁尽量在sql 内,而sql 查询没必要使用锁,因为共享状态,而对语句的修改、添加、删除的的操作,又因为先查询,不能写在一个sql内,写在一个sql 也行就必须即有查询又有操作的语句进行单独加锁,而事务也是另一种处理展示(方便回滚,又方便关联多条查询语句,写法也是写在事务外部-如何语句的话会累死每一条拼的sql) 这也是 很多 事务与锁关键子多的原因。
4、
--这种一句sql写的方法
if not exists(select * from Admin where id=1 AND PassWord='123465') --这个跟判断商品一样 判断商品编码 然后数量=0 是否存在,不存在就是可以减少更新操作
update Admin set remark='da' where id=1;
--这种一句sql 也不知道 有没有加锁,万一 我在sql 开两个窗口 写一个 循环呢,同时更新呢
--还不如事务的写法(也是一句sql,但是有区别会回滚、和锁写在外层,上面如果判断条件多的话,会很繁琐)当然事务也需要加锁
2、事务与锁关系
事务是用来操作处理插入多条数据一条失败,多条回滚。
锁则是多方操作一条,或者多方操作多条都场景下(即多条就涉及到事务),总结-两种1、锁-单行 2、事务与锁-多行(多行关系则用事务关联)
2、锁的使用
数据库没有解锁的概念,只有不加锁的概念,语句如下:
NOLOCK(不加锁)
此选项被选中时,SQL Server 在读取或修改数据时不加任何锁。 在这种情况下,用户有可能读取到
2、实践案例
一、示例一
--业务2查询数据
select * from Admin WITH (UPDLOCK) where Id=1 --sqlserver2008行锁
WAITFOR DELAY '00:00:01' --等待一秒后执行查询
--业务1执行更新操作
update Admin set Remark='524wwwwww' where Id=1 WAITFOR DELAY '00:00:05' --耗时5秒后执行查询
----仅延迟执行,并不是耗时响应
一、示例二
第一步:在当前会话中锁定数据行。 --声明数据库引用 use testss; go --声明数据库行锁 begin tran tran1 select * from test1 with(rowlock,updlock) where id='1'; waitfor delay '00:00:10'; commit tran; go 第二步:开启新会话,进行更新锁定数据行。 update test1 set sex='女' where id='1';
示例结果:事务延迟提交十秒,在事务未提交之前进行更新会发生进程阻塞,更新是失败的,事务提交完成后行锁被释放更新才能成功。