文章目录
一、使用Jedis操作Redis
Jedis是老牌的 Redis 的 Java 实现客户端,提供了比较全面的 Redis 命令的支持,其官方网址是https://github.com/redis/jedis
Jedis的语法与redis的API相同,所以学习成本低,但是其实例不是线程安全的,所以需要通过连接池来使用 Jedis。
Jedis初体验
- 添加jedis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
- 编写测试类
public class JedisTest {
private Jedis jedis;
@BeforeEach
void setUp(){
//redis的IP及端口号
jedis = new Jedis("XXX.XX.XXX.XX",6379);
// jedis = JedisConnFactory.getJedis();
//redis的密码
jedis.auth("123465");
//选择第几个数据库
jedis.select(0);
}
@Test
void testString(){
String res = jedis.set("name", "张三");
String name = jedis.get("name");
System.out.println(name);
}
@AfterEach
void tearDown(){
if (jedis!=null){
//记得关闭连接
jedis.close();
}
}
}
- 测试结果
通过连接池使用Jedis
上面说到,因为Jedis的实例是线程不安全的,所以我们要通过连接池来使用 Jedis。
- 编写Jedis连接工厂类
public class JedisConnFactory {
private static final JedisPool jedisPool;
static {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//设置最大连接数
jedisPoolConfig.setMaxTotal(8);
//设置最大空闲连接数
jedisPoolConfig.setMaxIdle(8);
//设置最小空闲连接数
jedisPoolConfig.setMaxIdle(0);
//设置最大等待时长
jedisPoolConfig.setMaxWaitMillis(1000);
jedisPool = new JedisPool(jedisPoolConfig,"XXX.XX.XXX.XX",6379,1000,"123465");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
- 修改测试类,并且我们这次测试Hash类型
public class JedisTest {
private Jedis jedis;
@BeforeEach
void setUp(){
jedis = JedisConnFactory.getJedis();
}
@Test
void testString(){
String res = jedis.set("name", "张三");
String name = jedis.get("name");
System.out.println(name);
}
@Test
void testHash(){
jedis.hset("user:4","name","IDEA");
jedis.hset("user:4","age","23");
Map<String, String> res = jedis.hgetAll("user:4");
System.out.println(res);
}
@AfterEach
void tearDown(){
if (jedis!=null){
jedis.close();
}
}
}
- 测试结果
二、SpringDataRedis操作redis
redisTemplate操作redis,不像Jedis那样有和redis API完全一样的语句,但是redisTemplate更接近java语法。
例如,opsForValue操作String类型,opsForHash操作Hash类型等,我将在下面给大家演示。
- 添加依赖
- 编写配置文件
spring:
redis:
host: XXX.XX.XXX.XX
port: 6379
password: 123465
lettuce:
pool:
max-idle: 8
max-wait: 1000ms
max-active: 8
min-idle: 0
- 编写测试类
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
void testString(){
redisTemplate.opsForValue().set("name3","操作工");
Object name = redisTemplate.opsForValue().get("name3");
System.out.println("name3 = " + name);
}
}
- 测试结果
通过控制台打印的“name3 = 操作工”,这个结果似乎是正确的,的确是我们存进去的key和value。
但是在redis的可视化工具中我们看到的是有乱码。不管是key还是value。
其实,这是因为我们没有序列化key-value。那接下来我们就设置一下。
redis序列化
- 编写配置类
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
//创建redistem对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
//设置连接工厂
template.setConnectionFactory(redisConnectionFactory);
//创建json序列化工具
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//设置key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
//设置value的序列化
template.setValueSerializer(genericJackson2JsonRedisSerializer);
template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
return template;
}
}
- 修改测试类,并测试存入一个对象
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Test
void testSaveUser(){
redisTemplate.opsForValue().set("user:1",new User("操作工",22));
User user = (User) redisTemplate.opsForValue().get("user:1");
System.out.println(user);
}
}
- 测试结果
通过测试结果可以看到,虽然我们存入对象成功了,但是数据里多了一行@class的数据,这会占用我们的内存。
使用StringRedisTemplate
StringRedisTemplate的key,value都是String类型,所以当我们的value是对象的时候,要先转换成String类型的json串。
- 编写测试类
@SpringBootTest
public class StringRedisTest {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void testString(){
stringRedisTemplate.opsForValue().set("name2","操作工2");
String name2 = stringRedisTemplate.opsForValue().get("name2");
System.out.println(name2);
}
@Test
void testSaveUser(){
User user = new User("操作工2",23);
String s = JSONObject.toJSONString(user);
stringRedisTemplate.opsForValue().set("user:2",s);
String s1 = stringRedisTemplate.opsForValue().get("user:2");
System.out.println(s1);
}
@Test
void testHash(){
stringRedisTemplate.opsForHash().put("user:3","name","操作工3");
stringRedisTemplate.opsForHash().put("user:3","age","23");
Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:3");
System.out.println(entries);
}
}
三、实现粉丝和关注
- 创建用户表、关注数据表
CREATE TABLE `tb_user` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`userId` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
`phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号码',
`password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '密码,加密存储',
`userName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '昵称,默认是用户id',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '人物头像',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `uniqe_key_phone` (`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1019 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT;
CREATE TABLE `tb_follow` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id',
`follow_user_id` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '关注的用户id',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT;
-
使用mybatisPlus生成pojo、service、mapper
-
编写controller层代码
@RestController
@RequestMapping("/follow")
@Api("粉丝关注")
public class FollowController {
@Resource
private FollowService followService;
@PostMapping("/follow")
@ApiOperation("关注/取关")
public Result follow(@RequestBody FollowParam followParam){
Boolean follow = followService.follow(followParam);
return Result.success(follow);
}
@GetMapping("/queryFollow")
@ApiOperation("关注列表")
public Result queryFollow(@RequestParam String userId){
List<FollowInfo> list = followService.queryFollows(userId);
return Result.success(list);
}
}
- 编写service接口
public interface FollowService extends IService<Follow> {
Boolean follow(FollowParam followParam);
List<FollowInfo> queryFollows(String userId);
}
- 编写service实现类
@Slf4j
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow>
implements FollowService{
private final StringRedisTemplate stringRedisTemplate;
private final UserMapper userMapper;
public FollowServiceImpl(StringRedisTemplate stringRedisTemplate, UserMapper userMapper) {
this.stringRedisTemplate = stringRedisTemplate;
this.userMapper = userMapper;
}
@Override
public Boolean follow(FollowParam followParam) {
String key = "follow:" +followParam.getCurUserId();
LambdaQueryWrapper<User> wrapper1 = new LambdaQueryWrapper<>();
wrapper1.eq(User::getUserId,followParam.getFollowId());
User user = userMapper.selectOne(wrapper1);
String name = user.getUserName();
String desc = user.getRemark();
FollowInfo followInfo = new FollowInfo(followParam.getFollowId(),name,desc);
if(followParam.getIsFollow()){
Follow follow = new Follow();
follow.setFollow_user_id(followParam.getFollowId());
follow.setUser_id(followParam.getCurUserId());
follow.setCreate_time(new Date());
boolean save = this.save(follow);
if(save){
stringRedisTemplate.opsForSet().add(key, JSONObject.toJSONString(followInfo));
}
return save;
}else {
LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Follow::getFollow_user_id,followParam.getFollowId()).eq(Follow::getUser_id,followParam.getCurUserId());
boolean remove = this.remove(wrapper);
if (remove){
stringRedisTemplate.opsForSet().remove(key,JSONObject.toJSONString(followInfo));
}
return remove;
}
}
@Override
public List<FollowInfo> queryFollows(String userId) {
String key = "follow:" +userId;
Set<String> follows = stringRedisTemplate.opsForSet().members(key);
List<FollowInfo> followVos = new ArrayList<>();
if(CollectionUtils.isEmpty(follows)){
LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Follow::getUser_id,userId);
List<Follow> list = this.list(wrapper);
for (Follow follow : list) {
LambdaQueryWrapper<User> wrapper1 = new LambdaQueryWrapper<>();
wrapper1.eq(User::getUserId,follow.getFollow_user_id());
User user = userMapper.selectOne(wrapper1);
String name = user.getUserName();
String desc = user.getRemark();
FollowInfo followInfo = new FollowInfo(follow.getFollow_user_id(),name,desc);
followVos.add(followInfo);
}
return followVos;
}else {
for (String fan : follows) {
FollowInfo followInfo = JSONObject.parseObject(fan, FollowInfo.class);
followVos.add(followInfo);
}
return followVos;
}
}
}
- 入参及出参
@Data
public class FollowParam implements Serializable {
private String curUserId;
private String followId;
private Boolean isFollow;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FollowInfo implements Serializable {
private String userId;
private String name;
private String desc;
}
- 测试结果