`

java高并发下的唯一性验证

阅读更多

做java ee程序基本上都会遇到唯一性的问题,我们通常不考虑并发性的问题的情况下的做法是:先根据条件去数据中查询是否存在,如果存在则提示不唯一,否则插入

 

下面是一个简单的例子, 向表t_test_curr插入数据,t_test_curr表包含两个字段,一个id(主键,自增长),一个username,要求唯一

1 不考虑并发性的做法:

  

    public void testConcurr (String username) {
        //t_test_curr并发测试表名
        String uniqueSql = new StringBuilder("select 1 from t_test_curr where username = ?").toString();
        List<SerializableJSONObject> uniqueList = this.baseDao.sqlQueryResult4Cache(uniqueSql, new Object[]{username});
        if (uniqueList != null && uniqueList.size() > 0) {
            throw new OperateFailureException("用户名重复!");
        }
        String saveSql = new StringBuilder("insert into t_test_curr(username) values (?)").toString();
        this.baseDao.executeDdlSql(saveSql, new Object[]{username});
    }

 测试代码:

 

class TestConThread implements Runnable {

    private ActivityService activityService;

    TestConThread (ActivityService activityService) {
        this.activityService = activityService;
    }

    @Override
    public void run () {
        activityService.testConcurr("malone");
    }
}

    public static void main (String[] args) throws Exception{
        ApplicationContext ctx = BaseTest.getCtx();
        ActivityService activityService = (ActivityService)ctx.getBean("activityService");
        TestConThread testConThread = new TestConThread(activityService);
        Thread[] threads = new Thread[10];
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(testConThread);
            threads[i].start();
        }
        for (int i = 0; i < 10; i++) {
            threads[i].join();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

    用上面的代码测试,启动十个线程,数据库中插入了9条记录,所以这种代码在并发的情况下没有任何抵抗能力,代码中打印出来的结果为:2582

 

2 使用锁,锁上当前方法:

  

    public void testConcurr2 (String username) {
        lock.lock();
        try {
            String uniqueSql = new StringBuilder("select 1 from t_test_curr where username = ?").toString();
            List<SerializableJSONObject> uniqueList = this.baseDao.sqlQueryResult4Cache(uniqueSql, new Object[]{username});
            if (uniqueList != null && uniqueList.size() > 0) {
                throw new OperateFailureException("用户名重复!");
            }
            String saveSql = new StringBuilder("insert into t_test_curr(username) values (?)").toString();
            this.baseDao.executeDdlSql(saveSql, new Object[]{username});
        } finally {
            lock.unlock();
        }
    }

   上面的线程类的run方法调用当前方法,这样数据不会重复,只会有一条,但是用锁会对吞吐量造成一定的影响,代码打印结果:3683,从打印结果来看,基本上慢了1/3

 

3 使用并发集合:

  

    public void testConcurr1 (String username) {
        if (isInCache(username)) {
            throw new OperateFailureException("你输入的用户名已经存在!");
        }
        String uniqueSql = new StringBuilder("select 1 from t_test_curr where username = ?").toString();
        List<SerializableJSONObject> uniqueList = this.baseDao.sqlQueryResult4Cache(uniqueSql, new Object[]{username});
        if (uniqueList != null && uniqueList.size() > 0) {
            throw new OperateFailureException("用户名重复!");
        }
        String saveSql = new StringBuilder("insert into t_test_curr(username) values (?)").toString();
        this.baseDao.executeDdlSql(saveSql, new Object[]{username});
        removeFromCache(username);
    }

    public boolean isInCache (String username) {
        if (map.containsKey(username)) {
            return true;
        } else {
            map.put(username, username);
            return false;
        }
    }

    public void removeFromCache (String username) {
        map.remove(username);
    }

     上面的代码逻辑为:在service中放一个ConcurrentHashMap,当请求来时,就把username和map里的数据比较,如果重复,就直接提示重复,如果不重复就放入的集合中,然后在验证在数据库中是否重复,如果重复则提示,不重复则插入,并移除并发集合中的username;这样做的好处时,不会锁住代码,系统吞吐量不会受影响,而且在并发环境下不会出现重复数据,测试代码打印结果:2459

分享到:
评论
2 楼 abc08010051 2018-02-07  
张延龙地盘 写道
多实例下就不行了吧

是的,多实例直接上分布式锁
1 楼 张延龙地盘 2018-01-02  
多实例下就不行了吧

相关推荐

    Java高并发秒杀API

    Java高并发秒杀API是一个典型的企业级应用场景,主要用于处理大量用户在同一时间抢购限量商品的情况。在设计这样的系统时,我们需要关注多个关键知识点,包括但不限于数据库操作、并发控制、性能优化以及分布式协调...

    java统计高并发首页访问量,记录客户登录信息

    在Java开发中,统计高并发环境下首页访问量并记录客户登录信息是一项常见的需求,这涉及到系统性能优化、数据持久化以及并发控制等多个方面。在这个项目中,开发框架选择了Spring,这是一个广泛使用的Java企业级应用...

    java中设置登录名的唯一性

    6. 异步验证:在高并发环境下,为了避免线程安全问题,可以使用异步方法或者线程安全的数据结构来验证登录名的唯一性,确保多个请求不会互相干扰。 7. 错误处理:当出现唯一性冲突时,应提供合适的错误提示,如“该...

    详解java解决分布式环境中高并发环境下数据插入重复问题

    java解决分布式环境中高并发环境下数据插入重复问题 本文主要介绍了java解决分布式环境中高并发环境下数据插入重复问题的解决方案。该问题是指在高并发环境下,服务器同时接受到的重复请求,导致数据重复插入或修改...

    java并发编程与高并发解决方案笔记

    Java并发编程是开发人员在构建高并发应用时必须掌握的关键技术。高并发环境下,接口幂等性成为确保系统稳定性和正确性的必要条件。幂等性指的是一个操作无论执行多少次,其结果始终相同,这对于避免重复操作导致的...

    高并发秒杀案例

    在构建高并发秒杀系统的过程中,我们面临的主要挑战是如何在短时间内处理大量的用户请求,确保系统的稳定性和用户体验。这里,我们将围绕“高并发秒杀案例”这一主题,结合使用SpringMVC和Mybatis两大技术框架,深入...

    官方Java端口的Sqids生成短唯一的id从数字.zip

    通过对时间戳、序列号和工作节点ID的巧妙组合, Sqids能够在分布式环境中有效地保证ID的唯一性,同时保持较高的生成速度。在实际项目中,正确理解和使用这个库对于提升系统的效率和可扩展性至关重要。

    抽奖系统(java)

    可以使用`java.lang.Thread`或`java.util.concurrent`包中的并发工具类来实现。 7. **设计模式**: - 单例模式:控制抽奖类的实例只有一个,保证全局唯一。 - 工厂模式:用于创建参与者和奖品对象,隐藏了具体的...

    SpringBoot开发的高并发限时抢购秒杀系统(含数据库文件).zip

    【标题】:基于SpringBoot的高并发限时抢购秒杀系统设计与实现 ...通过学习和实践这个项目,开发者可以深入了解如何在实际场景中应用SpringBoot,以及如何处理高并发、数据一致性和系统稳定性等问题。

    seckill-code-note:Java高并发秒杀API之业务分析与DAO层原始码和整理的笔记seckill是项目源码note是整理的笔记

    秒杀系统是电商领域中一个重要的技术挑战,它涉及到高并发、数据一致性、用户体验等多个关键因素。本资源“seckill-code-note”是一个关于Java实现高并发秒杀API的业务分析和DAO层源码解读的笔记,配合“seckill”...

    用户名唯一校验

    因此,MySQL在创建新用户时,也会进行用户名的唯一性验证。 实现用户名唯一校验的技术手段通常包括以下步骤: 1. 数据库查询:系统会在用户注册或创建新账号时,查询数据库中是否存在相同的用户名。如果找到,系统...

    API市场网关鉴权java

    7. **高并发处理**:在Java高并发环境下,API网关需要设计合理的缓存策略,如使用Redis或Memcached存储短期有效的Token,减少数据库查询压力。同时,使用线程池进行异步处理,避免阻塞主线程。 8. **安全策略**:...

    java秒杀项目源码-seckill:Java高并发秒杀API之业务分析与DAO层源码和整理的笔记seckill是项目源码note是整理的笔记

    综上所述,`seckill`项目源码包含了从业务设计到具体实现的全方位细节,对于学习和理解Java高并发处理以及秒杀系统的实现具有很高的参考价值。通过阅读和分析源码,开发者可以了解到如何在实际项目中应对高并发挑战...

    JAVA8虚拟机(jvm)规范_Chinese version.rar

    双亲委派模型是类加载的一种策略,保证了类的唯一性。 4. **JIT编译**:Just-In-Time编译器将频繁执行的热点代码编译为机器码,提升执行效率。Java8引入了Lambda表达式和方法引用来优化JIT编译。 5. **字符串常量...

    高级Java课程设计-学生基本信息管理(client版)

    8. **设计模式**:除了MVC,可能还使用了其他设计模式,如工厂模式用于创建对象,单例模式确保数据库连接的唯一性,或者装饰器模式来动态扩展功能。 9. **单元测试**:通过TestStudent1.5,可以看出开发者进行了...

    java的高级运用

    双亲委托模型是Java类加载的默认机制,它确保了类加载的唯一性,避免了类的多次加载和冲突。通过编写和运行模拟类加载的demo,我们可以直观地看到类加载的过程,从而在实际编程中更加灵活地控制类的生命周期。 接...

    java 短网址

    5. **分布式ID生成器**:在高并发场景下,为了防止短码冲突,可以采用分布式ID生成器,如Twitter的Snowflake或者美团的Leaf。这些算法能保证在分布式环境下生成全局唯一的ID,然后将其转换为短码。 6. **JSP技术**...

    Java安全性编程指南

    9. **并发安全**:Java提供了并发工具类,如synchronized关键字、Semaphore、ReentrantLock等,以确保多线程环境下的数据一致性,防止竞态条件和死锁。 10. **安全框架与库**:Spring Security、OWASP Java Encoder...

    高并发核心技术 - 订单与库存1

    这里利用Redis存储和校验token,通过`createToken`和`checkToken`方法实现原子性操作,确保token的唯一性和有效性。 ```java // 示例代码简化版,仅作理解用途 public String createToken(User user) { // 生成...

    最近5年133个Java面试问题列表

    了解如何实现`equals()`和`hashCode()`方法对于确保集合中元素的唯一性至关重要。 ### Java基础:equals与hashcode - 在Java中,正确地重写`equals()`和`hashCode()`方法对于确保对象之间的相等性和哈希表的正确...

Global site tag (gtag.js) - Google Analytics