思路分析:
由于用户网速以及其他原因,前端的js限制没有起作用,所以要在后端加判断。由于并发量还算比较大,所以不采用线程锁。
思路1:
在数据库表格中添加唯一索引
例如:将userId 和 createTime 绑定成一组唯一索引。如果这两个值同时相同,不予许插入。
语句类似于 CONSTRAINT col_2_u UNIQUE (col_1, col_2)
思路2:
在数据库表格中添加一个字段
例如:
将userId 和 createTime 用,隔开,列为一个新列,添加时先去查这个列的值是否已经存在。由于消耗资源太多不采用。
思路3:
运用缓存机制 redis
redis 有一个计数器功能, incr 提供保存时间,提供key值就能将key值缓存在redis中并生成一个计数(这个计数起始值是可以指定的,并且在有效时间内每多存一次加一)
最终选用思路3
使用的incr方法
/***
*
* @param key 要存的数据
* @param delta 起始值
* @param timeout 过期时间
* @param unit 过期时间单位
* @return
*/
public Long incr(final String key, final int delta, final long timeout,
final TimeUnit unit) {
if (timeout <= 0 || unit == null) {
return incr(key, delta);
}
List<Object> result = redisTemplate
.executePipelined(new SessionCallback<Object>() {
@Override
public <K, V> Object execute(
RedisOperations<K, V> operations)
throws DataAccessException {
ValueOperations<K, V> ops = operations.opsForValue();
ops.increment((K) key, delta);
operations.expire((K) key, timeout, unit);
return null;
}
});
return (Long) result.get(0);
}
使用的类
//redisService = SpringHelper.getBean("redisService");
//话费支付用户, 使用 redis计数器30秒清空一次 如果30秒内用户多次点击购买 incr就不为1 不做处理即可
private boolean checkShoppingRepeat(Req10132 req) {
if(req.getPay_type() == 0){
Long incr = redisService.incr(req.getUser_id(), 1, 30, TimeUnit.SECONDS);
if(1 != incr){
return true;
}
}
return false;
}