第五节 唯一性与无序性的好朋友Set

一、Set典型应用场景

        Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。从实际业务角度来考虑其应用场景。首先,Set它是一个集合,自然能够存放多个对象。多个对象之间各不相同,另外存放的顺序也是不固定的。

        典型的应用场景就是来做唯一性校验。如果某张表有个字段是唯一的,例如用户绑定的电话号码、手机号,那么在插入这张表之前,需要校验插入的电话号码、手机号是否已经与数据库中已经有的数据出现重复。

        另外一个无序性的特点的典型应用场景是随机返回一个数据。例如随机展示你感兴趣的歌曲、随机展示问卷调查数据、游戏里随机的防挂机的验证题目等等等等。只要是随机的,都可以考虑Redis的Set这种数据类型。

二、唯一性校验示例

       注册的时候,要求邮箱号不能重复。下面是具体的业务逻辑。

先检查email在不在缓存里面,
   如果在缓存里面,说明已经被注册,抛异常

   如果不在缓存里面 ,则查询数据库

         如果在数据库里面,说明已经被注册,抛异常
         如果不在数据库里面,插入数据库
                插入成功,则加入缓存。 
                插入失败,则抛异常,事务回滚

    public Integer registerUser(MUser user) {
        //是否在缓存中
        Boolean isInCache = getSetOperations().isMember(Constant.USER_REGISTER_KEY, user.getEmail());

        if (isInCache) {
            throw new InvalidArgumentException("email已经被注册");
        }

        //查询数据库
        MUser userInDB = mapper.selectByEmail(user.getEmail());
        if (userInDB != null && userInDB.getId() > 0) {
            throw new InvalidArgumentException("email已经被注册");
        } else {
            //插入并返回数据库生成的主键ID,以此判断是否插入成功
            mapper.insertSelective(user);
            if (user.getId() > 0) {
                //把新用户的email加入缓存
                getSetOperations().add(Constant.USER_REGISTER_KEY, user.getEmail());
                return user.getId();
            } else {
                throw new InvalidArgumentException("插入失败");
            }
        }
    }

   private SetOperations<String, String> getSetOperations() {
        return redisTemplate.opsForSet();
    }

三、随机性返回示例

        上面的例子展示了校验注册用户的邮箱。

        下面的例子是,随机返回一个用户数据。业务场景很简单,就是把所有用户的数据存放到Redis的Set中,每次随机返回一个,并且返回的用户数据从Set中删除。如果Set中的所有用户数据都被删除了,那么就再重新查询所有用户数据,并把它们加入到Redis的Set中。

        初始化缓存数据是新增操作,返回用户数据是删除操作。这两步操作在同一个方法里,因此这个方法是可能出现线程安全问题的。所以编写方法的时候需要考虑线程安全问题,为方法加锁就能解决。

业务逻辑:

         从缓存中取随机一个用户数据

                 如果有用户y数据,则返回

                 如果没有用户数据,则查询所有用户数据并加入缓存中。再拿一次缓存用户数据。

public synchronized MUser randomUser() {
        MUser user = null;
        //取出随机一条缓存中的用户数据
        user = getUserSetOperations().pop(Constant.USER_RANDOM_KEY);
        if (user == null) {
            //如果缓存中没有数据,则查询数据库,将所有用户数据加入缓存并返回
            List<MUser> userList = this.initCache();
            if (userList == null || userList.size() == 0) {
                throw new IllegalArgumentException("暂无任何用户数据,请稍后再试");
            }
            //取出随机一条缓存中的用户数据
            user = getUserSetOperations().pop(Constant.USER_RANDOM_KEY);
        }
        return user;
    }
发布了315 篇原创文章 · 获赞 243 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/yanluandai1985/article/details/104343042