乐观锁、悲观锁、要实践

http://chenzhou123520.iteye.com/blog/1860954 《mysql悲观锁总结和实践》

http://chenzhou123520.iteye.com/blog/1863407 《mysql乐观锁总结和实践》

http://outofmemory.cn/sql/optimistic-lock-and-pessimistic-lock

注意,以下的表里面的列名,一定要用 `` 反引号来包括。

mysql> create table `t_goods` (
-> `id` bigint(11) NOT NULL AUTO_INCREMENT,
-> `status` bigint(11) DEFAULT 0,
-> `name` varchar(32) DEFAULT NULL,
-> `version` bigint(11) DEFAULT 1,
-> PRIMARY KEY (`id`)
-> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.13 sec)

mysql> insert into t_goods (`name`) values ('weapon');
Query OK, 1 row affected (0.07 sec)mysql> insert into t_goods (`name`) values ('equipment');
Query OK, 1 row affected (0.10 sec)

mysql> select * from t_goods;
+----+--------+-----------+---------+
| id | status | name | version |
+----+--------+-----------+---------+
| 1 | 0 | weapon | 1 |
| 2 | 0 | equipment | 1 |
+----+--------+-----------+---------+
2 rows in set (0.00 sec)

实验1,select for update 指定主键,只锁行:

首先要关闭autocommit:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | OFF   |
+---------------+-------+
1 row in set (0.00 sec)

如果不关闭,经过实验,的确不会相互影响。

关闭autocommit之后,普通的sql不放在事务里面也可以。

console A:mysql> select * from t_goods where id = 1 for update;
+----+--------+--------+---------+
| id | status | name   | version |
+----+--------+--------+---------+
|  1 |      0 | weapon |       1 |
+----+--------+--------+---------+
1 row in set (0.00 sec)console B:
mysql> select * from t_goods where id = 1;
+----+--------+--------+---------+
| id | status | name   | version |
+----+--------+--------+---------+
|  1 |      0 | weapon |       1 |
+----+--------+--------+---------+
1 row in set (0.00 sec)mysql> select * from t_goods where id = 2 for update;
+----+--------+-----------+---------+
| id | status | name      | version |
+----+--------+-----------+---------+
|  2 |      0 | equipment |       1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec)mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

可以看出,不加for update不影响,加了for update不是同一行,不影响(仅对于主键查询有关)。

实验2,select for update 指定非主键,锁全部:

Console A:
mysql> select * from t_goods where name = 'weapon' for update;
+----+--------+--------+---------+
| id | status | name   | version |
+----+--------+--------+---------+
|  1 |      0 | weapon |       1 |
+----+--------+--------+---------+
1 row in set (0.00 sec)Console B:
mysql> select * from t_goods;
+----+--------+-----------+---------+
| id | status | name      | version |
+----+--------+-----------+---------+
|  1 |      0 | weapon    |       1 |
|  2 |      0 | equipment |       1 |
+----+--------+-----------+---------+
2 rows in set (0.00 sec)mysql> select * from t_goods where name = 'equipment' for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transactionmysql> select * from t_goods where id = 2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

实验3,查询主键没查到,不锁:

Console A:
mysql> select * from t_goods where id=3 for update;
Empty set (0.01 sec)Console B:
mysql> select * from t_goods for update;
+----+--------+-----------+---------+
| id | status | name      | version |
+----+--------+-----------+---------+
|  1 |      0 | weapon    |       1 |
|  2 |      0 | equipment |       1 |
+----+--------+-----------+---------+
2 rows in set (0.00 sec)

说明,主键没查到数据,不加锁。

实验4,查询非主键,没查到,锁全部,table lock.

Console A:
mysql> select * from t_goods where name = 'abc' for update;
Empty set (0.00 sec)Console B:
mysql> select * from t_goods for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transactionmysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

实验5:查询主键不明确,为范围,大于小于,只锁相关的行;

Console A:
mysql> select * from t_goods where id > 1 for update;
+----+--------+-----------+---------+
| id | status | name      | version |
+----+--------+-----------+---------+
|  2 |      0 | equipment |       1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec)Console B:
mysql> select * from t_goods where id = 1 for update;
+----+--------+--------+---------+
| id | status | name   | version |
+----+--------+--------+---------+
|  1 |      0 | weapon |       1 |
+----+--------+--------+---------+
1 row in set (0.00 sec)mysql> select * from t_goods where id = 2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

实验5:查询主键不明确,!=或者<>,锁全部;

Console A:
mysql> select * from t_goods where id != 1 for update;
+----+--------+-----------+---------+
| id | status | name      | version |
+----+--------+-----------+---------+
|  2 |      0 | equipment |       1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec)Console B:
mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transactionConsole A:
mysql> select * from t_goods where id <> 1 for update;
+----+--------+-----------+---------+
| id | status | name      | version |
+----+--------+-----------+---------+
|  2 |      0 | equipment |       1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec)Console B:
mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

实验6,对于普通索引,也类似于主键的效果:

未加索引之前,锁全表:
console A:
mysql> select * from t_goods where status = 1 for update;
+----+--------+--------+---------+
| id | status | name   | version |
+----+--------+--------+---------+
|  1 |      1 | weapon |       1 |
+----+--------+--------+---------+
1 row in set (0.00 sec)console B:
mysql> select * from t_goods where id = 2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction加了索引之后,只锁行:
console A:
mysql> alter table t_goods add index index_name(`status`);
Query OK, 0 rows affected (0.15 sec)
Records: 0  Duplicates: 0  Warnings: 0mysql> select * from t_goods where status = 1 for update;
+----+--------+--------+---------+
| id | status | name   | version |
+----+--------+--------+---------+
|  1 |      1 | weapon |       1 |
+----+--------+--------+---------+
1 row in set (0.00 sec)console B:
mysql> select * from t_goods where id = 2 for update;
+----+--------+-----------+---------+
| id | status | name      | version |
+----+--------+-----------+---------+
|  2 |      0 | equipment |       1 |
+----+--------+-----------+---------+
1 row in set (0.00 sec)mysql> select * from t_goods where id = 1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

乐观锁:

从业务层面加锁,一般是加上version字段,然后sql以如下形式处理:

update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version};

自旋锁与互斥锁

http://blog.csdn.net/a675311/article/details/49096435

自旋锁就是不听的忙检测,拿不到锁就返回。

pthread中提供的锁有:pthread_mutex_t, pthread_spinlock_t, pthread_rwlock_t。pthread_mutex_t是互斥锁,同一瞬间只能有一个线程能够获取锁,其他线程在等待获取锁的时候会进入休眠状态。因此pthread_mutex_t消耗的CPU资源很小,但是性能不高,因为会引起线程切换。
pthread_spinlock_t是自旋锁,同一瞬间也只能有一个线程能够获取锁,不同的是,其他线程在等待获取锁的过程中并不进入睡眠状态,而是在CPU上进入“自旋”等待。自旋锁的性能很高,但是只适合对很小的代码段加锁(或短期持有的锁),自旋锁对CPU的占用相对较高。
pthread_rwlock_t是读写锁,同时可以有多个线程获得读锁,同时只允许有一个线程获得写锁。其他线程在等待锁的时候同样会进入睡眠。读写锁在互斥锁的基础上,允许多个线程“读”,在某些场景下能提高性能。
诸如pthread中的pthread_cond_t, pthread_barrier_t, semaphone等,更像是一种同步原语,不属于单纯的锁。

http://www.cnblogs.com/hdflzh/p/3716156.html

http://blog.csdn.net/pi9nc/article/details/39177343

Java锁相关

http://blog.csdn.net/Evankaka/article/details/44153709 (这一篇要重点看,讲了Thread Runnable等)

http://blog.csdn.net/Evankaka/article/details/51866242(Java锁技术内幕上)

http://blog.csdn.net/evankaka/article/details/51932044(Java锁技术内幕中)

[Todo] 乐观悲观锁,自旋互斥锁等等相关推荐

  1. 并发编程中常见的锁机制:乐观锁、悲观锁、CAS、自旋锁、互斥锁、读写锁

    文章目录 乐观锁 VS 悲观锁 悲观锁 乐观锁 CAS CAS机制 ABA问题 CAS的优缺点 互斥锁 VS 自旋锁 互斥锁 自旋锁 对比及应用场景 读写锁 实现方式 读写锁 VS 互斥锁 乐观锁 V ...

  2. 各类锁(互斥锁,自旋锁,读写锁,乐观锁,悲观锁,死锁)

    互斥锁 当有一个线程要访问共享资源(临界资源)之前,会对线程访问的这段代码(临界区)进行加锁.如果在加锁之后没释放锁之前其他线程要对临界资源进行访问,则这些线程会被阻塞睡眠,直到解锁,如果解锁时有一个 ...

  3. 关抢占 自旋锁_互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景

    前言 生活中用到的锁,用途都比较简单粗暴,上锁基本是为了防止外人进来.电动车被偷等等. 但生活中也不是没有 BUG 的,比如加锁的电动车在「广西 - 窃·格瓦拉」面前,锁就是形同虚设,只要他愿意,他就 ...

  4. 分布式锁:互斥锁、自旋锁、读写锁、悲观锁、乐观锁

    前言 如何用好锁,也是程序员的基本素养之一了. 高并发的场景下,如果选对了合适的锁,则会大大提高系统的性能,否则性能会降低. 所以,知道各种锁的开销,以及应用场景是很有必要的. 接下来,就谈一谈常见的 ...

  5. 悲观|乐观锁、自旋|互斥锁、公平|非公平锁

    解析锁--悲观|乐观锁.自旋|互斥锁.公平|非公平锁 悲观锁 总认为最坏的情况可能会出现,即认为数据很可能会被他人修改,因此在持有数据时总是先把资源或数据锁住.这样其他线程要请求这个资源时就会阻塞,直 ...

  6. Java中的锁机制 -- 乐观锁、悲观锁、自旋锁、可重入锁、读写锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、轻量级锁、偏向锁、分段锁、互斥锁、同步锁、死锁、锁粗化、锁消除

    文章目录 1. Java中的锁机制 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 可重入锁(递归锁) 1.5 读写锁 1.6 公平锁 1.7 非公平锁 1.8 共享锁 1.9 独占锁 1.1 ...

  7. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等...

    http://blog.51cto.com/13919357/2339446 Java 中15种锁的介绍 在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容 ...

  8. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等

    Java 中15种锁的介绍 在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 公平锁 / 非公平锁 可重入锁 / 不可重入锁 独享锁 / 共享锁 互 ...

  9. 嵌入式 自旋锁、互斥锁、读写锁、递归锁

    互斥锁(mutexlock): 最常使用于线程同步的锁:标记用来保证在任一时刻,只能有一个线程访问该对象,同一线程多次加锁操作会造成死锁:临界区和互斥量都可用来实现此锁,通常情况下锁操作失败会将该线程 ...

最新文章

  1. iOS功能-统计平均下班时间
  2. java 获取文件权限_Java中的文件权限,检查权限和更改权限 - Break易站
  3. java nio.Buffer的属性变化
  4. 虚拟化Java应用程序:最佳实践(JavaOne 2011)
  5. Linux系统:centos7下搭建Nginx和FastDFS文件管理中间件
  6. mongo 多条件筛选_excel成本统计:如何进行区域筛选,多条件求和?
  7. java 事务管理 子父线程_Java中的父线程与子线程
  8. mysql的root用户无法给普通用户授权问题处理
  9. Android WindowManager简析
  10. c标准语言库里的i o函数,C语言文件I/O和标准I/O函数
  11. Android应用开发以及设计思想深度剖析(3)
  12. POJ 3415 Common Substrings (后缀数组,长度不小于k的公共子串的个数)
  13. Unity使用UniWebview插件内嵌H5游戏
  14. 计算机学科融合信息技术,信息技术与学科教学融合课例解析
  15. led拼接屏报价_液晶拼接屏报价大概多少钱一套?
  16. Android11 使用NTP同步时间
  17. 【拼多多】六一儿童节
  18. 聊聊新股市盈率的那些事
  19. C语言实现稳定的快排
  20. Android仿Qzone底部导航栏加号弹出菜单

热门文章

  1. 为什么同事写的代码那么优雅~
  2. mysql 相关子查询使用【主表得数据需要扩展(统计数据依赖与其他表,但是与主表有关联)】...
  3. DVbbs8.2入侵思路与总结
  4. Internet概念与TCP/ IP分层模型
  5. 对测试人员或开发人员来说相互沟通有多重要?
  6. Linux 学习_在Linux下面安装tomcat
  7. DirectSound 混音的实现
  8. 请先设置tkk_理光MP2014扫描至文件夹的设置方法
  9. ubuntu linux下建立stm32开发环境: 程序烧录 openocd+openjtag
  10. 对eventloop的研究