mysql的锁机制,以及乐观锁,悲观锁,以及热点账户余额问题

mysql的简单锁机制。

myisam

1、只支持表级锁,所以经常更新的表结构不适宜用。

2、select也会产生锁表

innodb

1、支持事务,行级锁,表级锁,执行行级锁的前提是sql语句的索引有效,否则,执行表级锁。

2、不存在字段锁问题,直接锁行的。

3、select不会请求锁,自然也不会产生锁表,update,insert,delete都会请求锁,所以会产生锁表

执行串行并行问题

1、同一个connection下,串行执行。

2、不同connection下,并行关系。验证方法:执行一个慢查询中间执行一个快查询便可验证

3、所以java这种非页面级的mysql连接,一般有连接线程池。以提高并行执行效率。

4、但是从微观角度来说,所有执行都是串行的。譬如自增id永远不会重复出现一样。

像php这种页面级的mysql连接,则不存在连接线程池问题,因为每个页面过来其实都是新开一个线程的问题。

事务的乐观锁和悲观锁

悲观锁:

begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2;
//4.提交事务
commit;/commit work;

我们使用了select…for update的方式,这样就通过开启排他锁的方式实现了悲观锁,id为1的 那条数据就被我们锁定了,其它的事务必须等本次事务提交之后才能执行, InnoDB默认行级锁。行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁把整张表锁住,这点需要注意。悲观并发控制实际上是“先取锁再访问”的保守策略,则执行for update的时候锁定了t_goods表,也就是说没有commit之前已经锁表了,根据微观串行可知,是线程安全的。

死锁:

假如两个并行事务s1和s2,s1先锁定t1,s2先锁定t2,然后s1需要等待t2解锁,s2需要等待t1解锁。就陷入无限等待的情况。

 

乐观锁:

begin;

1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods 
set status=2,version=version+1
where id=#{id} and version=#{version};
commit;
 

一般我们使用版本号的方式来实现乐观锁,乐观锁直到commit的时候才去锁定,乐观锁由于是commit才锁定,所以不存在死锁问题。但是也存在线程安全问题,假如两个connection实例,同时在commit之前修改了同一数据,commit先后的时候就会出现数据version不一致的问题。

 

 热点账户解决方案

 

posted @ 2017-06-28 16:38  zenghansen  阅读(542)  评论(0编辑  收藏  举报