一、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;
}