最近开发账户系统中,需要使用到账户余额,其中用到了行级锁。比如用户充值、提现、投资都需要对账户余额进行操作。
SELECT
ua.user_account_id,
ua.user_id,
AES_DECRYPT(ua.balance_amount, #aesKey#) AS balance_amount,
AES_DECRYPT(ua.freeze_amount, #aesKey#) AS freeze_amount,
AES_DECRYPT(ua.free_withdraw, #aesKey#) AS free_withdraw,
ua.raw_add_time,
ua.raw_update_time
FROM
user_account AS ua
WHERE ua.user_account_id = #userAccountId#
FOR UPDATE
使用限制,user_account_id字段必须为主键或者有索引。
问题一:为什么要用到行级锁?
如果同时开了2个窗口,用户余额有1000元,1个窗口进行全款投资,另1个窗口进行全额提现,如果操作几乎同时进行,则有可能同时完成了1000元的投资和1000元的提现。
问题二:什么是行级锁?
myisam存储引擎默认是表级锁
innodb存储引擎默认是行级锁
DBD存储引擎默认是页面锁
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。
行级锁:开锁大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
行级锁是Mysql中锁定粒度最细的一种锁,能大大减少数据库操作的冲突,由于其粒度小,加锁的开销最大。行级锁分为共享锁和排他锁。
共享锁(S LOCK)
用法:SELECT * LOCK IN SHARE MODE;
Mysql会对查询结果中的每行都加共享锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞。其他线程也可以读取使用了共享锁的表,而且这些线程读取的是同一个版本的数据。
排他锁(X LOCK)
用法:SELECT * FOR UPDATE;
Mysql会对查询结果中的每行都加排他锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞。
行级锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁。行级锁的缺点是:由于需要请求大量的锁资源,所以速度慢,内存消耗大。
问题三:MySql的锁机制详细说明
http://blog.csdn.net/xifeijian/article/details/20313977