您的位置:首页 > 数据库 > MySQL

mysql的锁--行锁,表锁,乐观锁,悲观锁

2016-08-02 20:31 525 查看
一 引言--为什么mysql提供了锁

  最近看到了mysql有行锁和表锁两个概念,越想越疑惑。为什么mysql要提供锁机制,而且这种机制不是一个摆设,还有很多人在用。在现代数据库里几乎有事务机制,acid的机制应该能解决并发调度的问题了,为什么还要主动加锁呢?

  后来看到一篇文章,“防止更新丢失,并不能单靠数据库事务控制器来解决,需要应用程序对要更新的数据加必要的锁来解决”。瞬间,世界观都崩塌了。非常不敢相信,于是自己写了代码检验一下。

  数据库表是这样的。用count字段来做100次累加。

  

public class TestLockOcc {
public static void main(String[] args) throws InterruptedException {
//创建线程池,里面有10个线程,共执行100次+1操作
final int THREAD_COUNT=10;
final int RUN_TIME=100;

ExecutorService threadPool=Executors.newFixedThreadPool(THREAD_COUNT);
//用CountDownLatch保证主线程等待所有任务完成
CountDownLatch count=new CountDownLatch(RUN_TIME);

for(int i=0;i<RUN_TIME;i++)
threadPool.execute(new LostUpdateOcc(count));

threadPool.shutdown();
count.await();
//提示所有任务执行完
System.out.println("finish");
}
}


View Code
  任务类里就有比较多要注意的

  a. 为了不断的重试,用了一个while。因为while的终止条件一般要读了数据后才知道,所以while只放了try_times,把结束条件放在了里面的if。

  b. 在while里的每一次循环就重新起一个事务。因为更新失败我们要回滚的。下一次要重起一个。

  c. 这里的事务执行条件,能执行且需要执行。比如id=1的记录被删掉了,那就不能执行了;需要执行,比如程序为了把商品记录status由未上架改为已上架,但发现已经被改了,那就不需要执行。可想而知,在多线程条件每次都要判断的。

  d. try_times这个东西还是设置一下。至于设多少,要看并发量。

  e. 每次更新,都要检测一次冲突

  f. 冲突了,要睡一阵子再重试,避开冲突。怎么设置这个值,我突然想起计网的拥塞控制,说笑的~

  顺手做了个小实验,还是执行100次,冲突睡眠100ms,

  


  总结一下:

  乐观锁更适合并发竞争少的情况,最好隔那么3-5分钟才有一次冲突。当并发量为10时就能明显感觉乐观锁更慢;

  上面只是一读一写。考虑如果一个事务中有3个写,如果每次写都是九死一生,事务提交比小蝌蚪找妈妈还难,这时就更要考虑是不是要用乐观锁了。

  但是,当分布式数据库规模大到一定程度后,又另说了。基于悲观锁的分布式锁在集群大到一定程度后(从几百台扩展到几千台时),性能开销就打得无法接受。所以目前的趋势是大规模的分布式数据库更倾向于用乐观锁来达成external consistency。

  如果对乐观锁和悲观锁的选择还不清楚,看这篇

  

五 待更

  mvcc:http://blog.csdn.net/chen77716/article/details/6742128

  意向锁,间隙锁,加锁的查看

参考:

数据库锁协议等原理:http://blog.csdn.net/gklifg/article/details/38752691

InnoDB的几种锁:http://www.cnblogs.com/chenqionghe/p/4845693.html

InnoDB的几种锁:http://blog.csdn.net/xifeijian/article/details/20313977
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: