思路分析:
由於用戶網速以及其他原因,前端的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;
}