为什么要引入锁 ?
多个用户同时对数据库的并发 *** 作时会带来以下数据不一致的问题。
select加共享锁,insert、update、delete加排他锁。
悲观锁(@R_749_3270@ Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做 *** 作之前先上锁。 通过 jdbc 实现时 sql 语句只要在整个语句之后加 for update 即可。例如: select …for update
乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适
共享锁:(读取) *** 作创建的锁。其他用户可以并发读取数据,但任何事物都不能获取数据上的排它锁,直到已释放所有共享锁。 共享锁(S锁)又称为读锁,若事务T对数据对象A加上S锁,则事务T只能读A;其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
共享锁的使用 在第一个连接中执行以下语句 begin tran select * from table1 WITH(HolDLOCK) -holdlock人为加锁 where B='b2' waitfor delay '00:00:30' --等待30秒 commit tran 在第二个连接中执行以下语句 select A,C from table1 update table1 set A='aa' 若同时执行上述两个语句,则第二个连接中的select查询可以执行 而update必须等待第一个事务释放共享锁转为排它锁后才能执行 即要等待30秒
排它锁:排它锁又称为写锁((eXclusive lock,简记为X锁)),若事物T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。 排它锁的使用
在第一个连接中执行以下语句
begin tran
update table1
set A='aa'
where B='b2'
waitfor delay '00:00:30' --等待30秒
commit tran
在第二个连接中执行以下语句
begin tran
select * from table1
where B='b2'
commit tran
若同时执行上述两个语句,则select查询必须等待update执行完毕才能执行即要等待30秒
互斥锁(Mutex)
互斥锁是一个互斥的同步对象,意味着同一时间有且仅有一个线程可以获取它。
互斥锁可适用于一个共享资源每次只能被一个线程访问的情况
using System;using System.Collections.Generic;using System.linq;using System.Text; using System.Threading; namespace MyTTCon{ class shareRes { public static int count = 0; public static Mutex mutex = new Mutex(); } class IncThread { int number; public Thread thrd; public IncThread(string name,int n) { thrd = new Thread(this.run); number = n; thrd.name = name; thrd.Start(); } voID run() { Console.Writeline(thrd.name + "正在等待 the mutex"); //申请 shareRes.mutex.WaitOne(); Console.Writeline(thrd.name + "申请到 the mutex"); do { Thread.Sleep(1000); shareRes.count++; Console.Writeline("In " + thrd.name + "ShareRes.count is " + shareRes.count); number--; } while (number > 0); Console.Writeline(thrd.name + "释放 the nmutex"); // 释放 shareRes.mutex.ReleaseMutex(); } } class DecThread { int number; public Thread thrd; public DecThread(string name,int n) { thrd = new Thread(this.run); number = n; thrd.name = name; thrd.Start(); } voID run() { Console.Writeline(thrd.name + "正在等待 the mutex"); //申请 shareRes.mutex.WaitOne(); Console.Writeline(thrd.name + "申请到 the mutex"); do { Thread.Sleep(1000); shareRes.count--; Console.Writeline("In " + thrd.name + "ShareRes.count is " + shareRes.count); number--; } while (number > 0); Console.Writeline(thrd.name + "释放 the nmutex"); // 释放 shareRes.mutex.ReleaseMutex(); } } class Program { static voID Main(string[] args) { IncThread mthrd1 = new IncThread("IncThread thread ",5); DecThread mthrd2 = new DecThread("DecThread thread ",5); mthrd1.thrd.Join(); mthrd2.thrd.Join(); } }}
小结:
悲观锁:查询加锁 【select ...... for update】
乐观锁:修改加锁 【版本号控制】
排它锁:事务A可以查询、修改,直到事务A释放为止才可以执行下一个事务
共享锁:事务A可以查询、修改,同时事务B也可以查询但不能修改
互斥锁:同一资源同一时间只能被一个线程访问
参考:http://bbs.csdn.net/topics/360017582
总结以上是内存溢出为你收集整理的SqlServer加锁全部内容,希望文章能够帮你解决SqlServer加锁所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)