使用举例
  要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,也是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交
  mysql> set autocommit = 0;
  Query OK, 0 rows affected (0.01 sec)
  mysql> select @@autocommit;
+--------------+
| @@autocommit |
+--------------+
|            0 |
+--------------+
1 row in set (0.00 sec)
Connect a:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select age from users where id =1 for update;
+-----+
| age |
+-----+
|  24 |
+-----+
1 row in set (0.00 sec)
mysql> update users set age = 25 where id =1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
Connect b: 在a长时间未提交的时候
mysql> select * from users where id =1 for update;
ERROR 1205 : Lock wait timeout exceeded; try restarting transaction
mysql> update users set age = 22 where id =1;
ERROR 1205 : Lock wait timeout exceeded; try restarting transaction
  connectb只有在connecta提交之后才会执行,否则会一直等待
  在事务中,只有SELECT...FORUPDATE或LOCKINSHAREMODE会等待其它事务结束后才执行,一般SELECT...则不受此影响
  MySQLselect…forupdate的RowLock与TableLock
  上面我们提到,使用select…forupdate会把数据给锁住,不过我们需要注意一些锁的级别,MySQLInnoDB默认Row-LevelLock,所以只有「明确」地指定主键/索引,MySQL才会执行Rowlock(只锁住被选取的数据),否则MySQL将会执行TableLock(将整个数据表单给锁住)
  如果一个条件无法通过索引快速过滤,存储引擎层面会将所有记录加锁后返回,再由MySQLServer层进行过滤,但在实际使用过程当中,MySQL做了一些改进,在MySQLServer过滤条件,发现不满足后,会调用unlock_row方法,把不满足条件的记录释放锁(违背了二段锁协议的约束)。这样做,保证了后只会持有满足条件记录上的锁,但是每条记录的加锁操作还是不能省略的。可见即使是MySQL,为了效率也是会违反规范的
  这种情况同样适用于MySQL的默认隔离级别RR。所以对一个数据量很大的表做批量修改的时候,如果无法使用相应的索引,MySQLServer过滤数据的的时候特别慢,会出现虽然没有修改某些行的数据,但是它们还是被锁住了的现象
  优缺点
  悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;
  另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务必须等待该事务处理完才可以处理那行数据
  悲观的缺陷是不论是页锁还是行锁,加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也是说悲观锁的并发访问性不好
  乐观锁则认为其他用户企图改变你正在更改的对象的概率是很小的,因此乐观锁直到你准备提交所作的更改时才将对象锁住,当你读取以及改变该对象时并不加锁。可见乐观锁加锁的时间要比悲观锁短,乐观锁可以用较大的锁粒度获得较好的并发访问性能