如何在发放优惠码时保证同一个码不会被重复发出多次?

2015-03-16 12:15:05 +08:00
 kran

表结构如下:

`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
`coupon` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '优惠券码',
`type` tinyint(1) unsigned NOT NULL COMMENT '类型',
`is_use` enum('N','Y') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'N' COMMENT '是否使用',
`use_date` int(10) unsigned NOT NULL COMMENT '使用时间',
`is_del` enum('N','Y') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'N' COMMENT '是否删除',
`creation_date` int(10) unsigned NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `type` (`type`,`is_use`,`is_del`)

现在使用这样的查询,会锁表:

begin;
select * from coupon_list where is_use='N' and type=5 and is_del='N' limit 1 for update;

如何才能触发行锁而不是表锁?

6469 次点击
所在节点    MySQL
37 条回复
abelyao
2015-03-16 13:13:22 +08:00
这是把所有优惠码都先创建好、然后去表里找没有使用的吗?
换个思路、在用户领取的时候再创建优惠码呢?
c742435
2015-03-16 13:14:48 +08:00
不懂数据库。
但是为什么要先生成优惠码。为什么不在发放的时候向数据库存入优惠码。
zhicheng
2015-03-16 13:22:57 +08:00
用派发终端数做取余。
loading
2015-03-16 13:26:28 +08:00
发放时再取优惠码,根据 timestamp 计算 md5 就可以直接用,查找数据库,已有就重新取。
kran
2015-03-16 13:55:54 +08:00
@abelyao
@c742435

这是因为客户在自己的系统里生成的优惠码,我们负责发放。自己生成的在客户那边用不了。


@zhicheng
不好意思啊,没有看明白,能细说说吗?

@loading
没理解错的话是用程序生成而不是在库里取现有的吧?要是这样不满足要求
hackwjfz
2015-03-16 14:01:11 +08:00
加一个flag,发出去了从1变0.不知道这样可否。
zhicheng
2015-03-16 14:02:08 +08:00
比如有两个终端,编号为 0和1。
那么0号终端永远取,id % 2 == 0 的记录。1 号终端永远取 id % 2 == 1 的记录。依此类推。
kran
2015-03-16 14:03:19 +08:00
@hackwjfz
表里的`is_use`就相当于一个标志, 但是多个会话同时请求的话还是会得到同一条记录。
kran
2015-03-16 14:06:54 +08:00
@zhicheng
不太一样,这个是通过web发码,如果对客户端信息做一定的计算,应该是能降低取到同一条记录的概率,但还是会重复。
zhicheng
2015-03-16 14:16:45 +08:00
通过web发码也是要经过服务器的。
kran
2015-03-16 14:24:16 +08:00
@zhicheng
我的理解是:根据终端号分配优惠码的区段(也就是一个码只会对应到一个终端),条件是终端数目是有限的,web的情况是终端数是无限的。不知道我理解的对不对?
justlikemaki
2015-03-16 14:25:17 +08:00
对于取兑换码的这个过程写个同步可以么?
zhicheng
2015-03-16 14:28:07 +08:00
你要分清楚终端和顾客的区别,顾客是无限的,终端是有限的。比如你准备10台服务器抢优惠码,那这10台服务器就是10个终端。
kran
2015-03-16 14:28:55 +08:00
@justlikemaki
我没太理解,能细说一下吗?
同步指的是加队列还是什么?
fityme
2015-03-16 14:31:42 +08:00
我的做法是,给这批优惠码加一个索引存redis,依赖redis做锁,不锁数据库。
这样做的问题就是多依赖了一个点,然后虽然不会一个优惠码多发,但是异常情况可能会造成活动结束有些码没有真的发出去,细节可以再考虑一下。
laoyur
2015-03-16 14:32:21 +08:00
数据库那块不太精通
不过要我来做的话,我会想办法在应用层来处理这个资源竞争的问题,比如用semaphore之类
happywowwow
2015-03-16 14:32:23 +08:00
http://haicang.blog.51cto.com/2590303/1085388
http://www.cnblogs.com/funsion/p/4017779.html
就上面行锁的需求来说,需要对条件字段加索引
kran
2015-03-16 14:33:07 +08:00
@zhicheng
嗯。。现在的情况是,一台服务器负责发码,每一个访问网站的人都可以*即时*得到一个优惠码。顾客是直连到服务器的。
kran
2015-03-16 14:36:19 +08:00
@fityme
这个可行,直接把码放到redis队列里。只是程序已经上线,如果能用现有的工具解决最好了。
zhicheng
2015-03-16 14:43:25 +08:00
那10个进程?
原来你只有一台服务器,who the fucking care....
如果你的QPS不到10K,请直接锁库。如果QPS不到100K,请使用队列。我设计的是100K以上的需求。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/177228

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX