解决外挂刷mysql记录状态的几个技巧

前言

有这样一个场景,用户每天可以领取一个礼品(也可以是其他的东西,反正一天只能领取一次,不能重复领取),在这种情况下,或许有人就会心怀不轨,利用脚本或者其他形式的工具(俗称:外挂)疯狂刷领取礼品的接口,下面就来分析下这个过程。其实这个涉及到安全的问题

正常逻辑

正常写代码的时候业务逻辑,可能是这样的:

1.首先判断该用户领取礼品的标识字段是否为1(也可以是其他,这里只是假定1就是:已领取)

2.如果是1,则已经领取

3.如果是0,则没有领取,可以发放礼品,并将这个标识字段修改成1

那么问题来了,大家仔细想想,如果我疯狂的请求这个过程,是不是会出现,我还没来得及将0修改成1的时候,第二个请求来判断是否是1的时候,这个标识字段还是0(因为还没来得及修改成1),这个时候就出问题,礼品就会发放(其实第一个请求已经发过了),所以这样的处理是有问题的,下面就介绍下解决方法。

解决方法

首先新建一个这样的数据表(我这边已经精简)

CREATE TABLE `gift_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `flag` tinyint(2) DEFAULT NULL,
  `uid` int(11) DEFAULT NULL,
  `date_time` varchar(20) CHARACTER SET latin1 DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

我这里模拟了一条数据,仅仅是为了更形象的让大家理解

id        flag      uid        date_time
1           0        1            20160407

方法一

1.首先判断

select flag from gift_log where uid = 1

2.没有发放礼品就再更新

update gift_log set flag = 1 where flag = 0

3.判断影响的行数

如果影响行数为1,表示是从0=>1的过程,如果影响行数是0,表示是从1=>1的过程,只有影响行数是1的才能发放礼品。是不是很赞!

方法二(其实跟方法类似)

1.首先判断是否有记录

select flag from gift_log where uid = 1 and date_time = '20160408'

2.没有发放礼品就再更新

update gift_log set flag = 1,date_time='20160408' where date_time != '20160408'

3.判断影响的行数

如果影响行数为1,才能发放礼品。这个其实跟上面那个原理很相似,只是这个是用日期来做,主要还是看业务上有没有这个需求。