java 先查询再插入

在测试代码时发现一个问题:
要实现一个数据库表中user_id和手机号两个字段觉得数据的唯一性,所以我要先进行查询,如果数据存在,则不插入,数据不存在则插入数据。可是当前台打开多个页面时,同时触发这个操作之后,第一个访问来了判断没有数据便进行插入,但还没有插入完成时第二个访问也来了,此时查询还没有数据,便也插入,但这样一来就有两条重复数据了。
所以要需要控制一下这样的问题我找到一些方法:
1、 可以用sql语句进行控制,有插入的不允许有重复的值插入:

  INSERT INTO marketing_vote (user_id, mobile_number, type) 
  SELECT '18210141111my', '18210141111', 'vote' FROM  DUAL  WHERE 
NOT EXISTS ( 
SELECT 
*
FROM 
marketing_vote 
WHERE 
mobile_number = '18210141111my' and user_id='18210141111');

这样在插入的时候可以先时行判断,如果条件里的用户存在数据库表中,那么not exists里返加false,则条件不存在不会插入数据,反则会将数据插入到数据库表中。

2、 可以在表中利用唯一索引进行控制,这样不就可以插 入重复数据;
3、. 还可以在插入之前做一个删除操作,当然这种方法不是特别合理;
4、后经过测试,最终选择用redis锁的方式来确保一段代码的串行执行,redis 单进程单线程模式,采用队列模式将并发访问变成串行访问,且在多个请求在对redis进行访问的时间也不存在竞争关系 ;代码如下:

/**
setnx命令: set if not eXists 如果不存在,则Set的简写
           隐藏的意思是:key存在的情况下,不操作redis内存;也就是返回值是0; Long result = jedis.setnx(key, value);
           返回值result :设置成功,返回 1 。设置失败,返回 0 
           这种加锁的思路是,如果 key 不存在,将 key 设置为 value,如果 key 已存在,则 SETNX 不做任何动作.
           
expire命令:redis通过expire命令来设置key的过期时间。
           语法:redis.expire(key, expiration)           
**/
 public static boolean getDLock(String key, String holder, long timeout){
        Jedis jedis = DRJedis.getJedisPool();
        long end = System.currentTimeMillis() + timeout;

        while(System.currentTimeMillis() < end) {
            try {
                if(jedis.setnx(LOCK_PREFIX + key, holder).longValue() == 1L) {
                    jedis.expire(LOCK_PREFIX + key, 60);
                    return true;
                }

                Thread.sleep(100L);
            } catch (Exception var11) {
                log.error("获取 DLock 异常", var11);
            } finally {
                returnResource(jedis);
            }
        }

        returnResource(jedis);
        System.out.println("获取 DLock 超时");
        return false;
    }  

public static Jedis getJedisPool()
  {
    int total = 1;
    do
    {
      try
      {
        Jedis jedis = pool.getResource();
        total = 1;
        return jedis;
      } catch (JedisConnectionException e) {
        log.error("redis 链接失败已超过" + total + "次,请检查服务器...", e);
        total++;
        try {
          Thread.sleep(1000L);
        } catch (InterruptedException e1) {
          log.error(e);
        }
      }
    }
    while (
      total < 3);
    log.error("redis 链接失败已超过3次,redis已失效");
    return null;
  }
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值