网站开发自学网站,小程序商城运营方案,asp sqlserver做网站,wordpress 自动采集近日#xff0c;因人员调整接手了一个其他部门负责的项目。随后发现其中的很多关键环节是没有考虑mysql并发操作的#xff0c;现列出存在的一例问题 并分享如何解决的。问题描述#xff1a;用户账户余额转移赠送 (用户A将自己的账户剩余金额赠送给用户B),同一时刻还可能存在…近日因人员调整接手了一个其他部门负责的项目。随后发现其中的很多关键环节是没有考虑mysql并发操作的现列出存在的一例问题 并分享如何解决的。问题描述用户账户余额转移赠送 (用户A将自己的账户剩余金额赠送给用户B),同一时刻还可能存在用户A消费操作(例如赠送操作在app消费操作在手机站)。PHP 代码:$sql_select select amount from user where id 1;/**** 从mysql查询出的用户A余额,放入php 变量$amount* 做一些逻辑处理例如A用户是否有权限操作此处代码省略** 用户A账户清零* $sql_deduct update user set amount 0 where id 1;*///将 用户A金额转移给用户B$sql_transfer sprintf ( update user set amount amount%d where id 2, $amount );此种写法存在问题因1.$sql_select执行查询后有可能存在并发操作例如刚好此时 用户A有其他消费mysql 账户余额amount 被扣减。此时php 变量$amount 与 mysql amount 内容已经不一致。2. $sql_transfer 使用了php变量$amount(值已经不是最新的) 进行账户增加会导致增加与扣除的金额不一致。解决方案处理并发修改一般是要进行加锁防止其他mysql session 修改同一条内容mysql 也提供了独占锁机制解决并发更新问题。方案1InnoDB 引擎可以使用select … for update , 对要修改的表中的某一行加锁。另外此方案对MyISAM引擎无效。MyISAM可以考虑使用方案2.SET autocommit 0;$sql_select select amount from user where id 1 for update ;//这里可以写修改db 的业务逻辑COMMIT;1.执行$sql_select后,user id 1 的这一行会被mysql 锁定其他mysql session 只能读取锁定前的数据,其他mysql session要加锁或者修改涉及此行,都会被阻塞(例如修改删除此行修改表结构等)直到锁定释放 (commit提交事务 或 mysql session 结束)2.必须将mysql 自动提交关闭(SET autocommit 0;)否则锁定无效3.特定的行进行加锁仅针对“特定的索引 ” 有效例如id 1 的select查询是行锁因id 是主键索引。3.1 如果查询条件是 id1,那么mysql 会锁定整个表.3.2 如果查询条件没有使用索引,那么mysql 也会锁定整个表.建议大家尽可能使用行锁以提高mysql并发性能。另外 需要注意的是 此方案可能会造成死锁。这个还要从业务方面尽可能避免以后会继续讨论如何避免死锁。方案2:2. 使用LOCK TABLES … READ 锁表LOCK TABLES user READ//这里可以写修改db 的业务逻辑UNLOCK TABLES;此方案比较粗暴会锁定整个表的写操作但如果在MyISAM 引擎下也就只能选择这种方式了。结论mysql 加锁本质上都是通过牺牲并发性能换取数据的一致性所以在业务需求分析设计时就要考虑哪些可能存在并发写入进行规划尽可能减少锁的次数、时间。作者 白金马桶