重新认识Java中防止重复提交
发布日期:2021-05-27 02:53:57 浏览次数:21 分类:精选文章

本文共 4108 字,大约阅读时间需要 13 分钟。

防止重复提交的请求,可以通过在前端部署拦截器和在后端进行验证来实现。以下是后端拦截的实现思路和方法。

拦截思路

在方法执行之前,先判断该业务是否已执行过。如果已执行,则终止当前请求;否则继续处理。需要将请求的业务ID存储在内存中,并通过互斥锁保证多线程环境下的程序执行安全。最简单的方法是使用HashMap存储业务ID,或者通过Guava Cache achiev相同效果,但HashMap的性能更优。

升级方法

  • 双重检测锁(DCL):这是对HashMap的升级版本,通过锁的双重检查机制,提升频繁重复提交业务的执行效率。
  • LRUMap:采用基于LRU算法的映射方式,这样可以自动清除过期数据,避免内存无限占用。
  • 方式二的升级:在固定大小数组的基础上,进一步提升性能和安全性。
  • 具体实现方式

    方式一:使用HashMap

    @RestControllerpublic class DemoController1 {    private Map
    map = new HashMap<>(); @RequestMapping("addUser1") public String addUser(String id) { synchronized (this.getClass()) { if (map.containsKey(id)) { System.out.println("请勿重复提交..." + id); return "请求失败"; } map.put(id, 1); } System.out.println("添加用户ID:" + id); return "请求成功"; }}

    方式二:使用固定大小数组

    @RestControllerpublic class DemoController2 {    private static String[] cache = new String[100];    private static Integer counter = 0;    @RequestMapping("addUser2")    public String addUser(String id) {        synchronized (this.getClass()) {            if (Arrays.asList(cache).contains(id)) {                System.out.println("请勿重复提交..." + id);                return "请求失败";            }            if (counter >= cache.length) {                counter = 0;            }            cache[counter] = id;            counter++;        }        System.out.println("添加用户ID:" + id);        return "请求成功";    }}

    方式三:双重检测锁升级方式

    @RestControllerpublic class DemoController3 {    private Map
    map = new HashMap<>(); @RequestMapping("addUser3") public String addUser(String id) { if (map.containsKey(id)) { System.out.println("请勿重复提交..." + id); return "请求失败"; } synchronized (this.getClass()) { if (map.containsKey(id)) { System.out.println("请勿重复提交..." + id); return "请求失败"; } map.put(id, 1); } System.out.println("添加用户ID:" + id); return "请求成功"; }}

    方式四:固定大小数组升级方式

    @RestControllerpublic class DemoController4 {    private static String[] cache = new String[100];    private static Integer counter = 0;    @RequestMapping("addUser4")    public String addUser(String id) {        if (Arrays.asList(cache).contains(id)) {            System.out.println("请勿重复提交..." + id);            return "请求失败";        }        synchronized (this.getClass()) {            if (Arrays.asList(cache).contains(id)) {                System.out.println("请勿重复提交..." + id);                return "请求失败";            }            if (counter >= cache.length) {                counter = 0;            }            cache[counter] = id;            counter++;        }        System.out.println("添加用户ID:" + id);        return "请求成功";    }}

    方式五:使用LRUMap

    @RestControllerpublic class DemoController5 {    private LRUMap
    lruMap = new LRUMap<>(100); @RequestMapping("addUser5") public String addUser(String id) { if (lruMap.containsKey(id)) { System.out.println("请勿重复提交..." + id); return "请求失败"; } synchronized (this.getClass()) { if (lruMap.containsKey(id)) { System.out.println("请勿重复提交..." + id); return "请求失败"; } lruMap.put(id, 1); } System.out.println("添加用户ID:" + id); return "请求成功"; }}

    方式六:工具化封装版本

    public class IdempotentUtil {    private static LRUMap
    lruMap = new LRUMap<>(100); public static boolean check(String id, Object lockClass) { synchronized (lockClass) { if (lruMap.containsKey(id)) { System.out.println("请勿重复提交..." + id); return false; } lruMap.put(id, 1); } return true; }}@RestControllerpublic class DemoController6 { @RequestMapping("addUser6") public String addUser(String id) { if (!IdempotentUtil.check(id, this.getClass())) { return "请求失败"; } System.out.println("添加用户ID:" + id); return "请求成功"; }}

    后续优化

    可以进一步通过自定义注解、反射机制或应用程序拦截器等技术实现防重提交。这些方法结合前端拦截和后端验证,可以更灵活地处理重复请求问题。

    上一篇:自定义幂等性校验之annotation+reflection+interceptor练习
    下一篇:JDK8特性之lambda

    发表评论

    最新留言

    表示我来过!
    [***.240.166.169]2025年05月01日 09时21分37秒

    关于作者

        喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
    -- 愿君每日到此一游!

    推荐文章