防重复提交

前端

1、页面加遮罩层

2、按钮点击后变为disabled

3、增加控制标识,使调用始终幂相等。

var flag = false;
function commit(){
	if(flag){
		console.log("请求重复");
	}else{
		flag = true;
		console.log("提交请求");
	}
}

后端

前提:每笔交易都有唯一的流水号。

1、数据库控制

建一张包含流水号的表,将流水号设置唯一约束,每次提交时向表中插入一条数据;若插入成功则可以提交,若插入失败则说明重复提交。
缺点:效率低。

2、缓存控制

调用:

// 实际使用中通过单例模式初始化对象,启动构造方法中的定时清理
ProtectionBusiService p = new ProtectionBusiService();
String busiId = "0001";
boolean flag = p.isRecentBusi(busiId);
if(flag ){
	logger.debug("重复");
}else{
	p.recentBusiNoList.add(busiId);
	logger.debug("提交成功");
}

缓存控制类:


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.log4j.Logger;

@Service // 自定义的注解,服务启动时会通过spring扫描注入;也可手工new对象
public class ProtectionBusiService {
	
	private final Logger logger = Logger.getLogger(ProtectionBusiService.class);
	
	/**
	 * 保存最近一段时间发交易的流水号
	 * 通过Collections.synchronizedList中内置的synchronized放置并发添加
	 */
	public static List<String> recentBusiNoList = Collections.synchronizedList(new ArrayList<String>());
	
	/**
	 * 定时清理recentBusiNoList的间隔时间 5分钟
	 */
	private final long intevalPeriod = 1000 * 60 * 5;
	
	public ProtectionBusiService() {
		// 开启定时器,定时清理recentBusiNoList
		TimerTask task = new TimerTask() {
			public void run() {
				int count = recentBusiNoList.size();
				recentBusiNoList.clear();
				logger.debug("清空 recentBusiNoList 数量:" + count);
			}
		};
		Timer timer = new Timer();
		long delay = intevalPeriod;
		timer.scheduleAtFixedRate(task, delay, intevalPeriod);
	}
	
	/**
	 * 检测是否最近5分钟该流水号是否有重发过交易
	 * @param busiNo
	 * @return
	 */
	public static boolean isRecentBusi(final String busiNo) {
		return recentBusiNoList.contains(busiNo);
	}
	
}

缺点:在分布式时需要进行缓存同步。

扩展:通过spring对指定方法防重复提交

1、自定义注解 @NoRepeatSubmit 标记有必要防重复提交请求Controller。

2、通过Spring-AOP方式对所有标记了 @NoRepeatSubmit 的方法进行切入拦截。

你可能感兴趣的:(Java,java,数据库,spring)