Redis基础---Java客户端应用

目录

一、介绍

二、Jedis的使用

 三、SpringDataRedis(SpringBoot)的使用

        创建:

四、Redis使用小案例


一、介绍

        在Redis官网,提供了多种编程语言的客户端,如Java、C++等,官网地址:Clients | Redis

        而对于Java的客户端有很多,但是用的最多的就是下图的前两个:

二、Jedis的使用

        创建一个普通javamaven项目:

        在pom.xml文件中引入依赖:

    <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.7.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

        建立连接:

                创建测试类:

package com.jedis.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import redis.clients.jedis.Jedis;

@RunWith(JUnit4.class)
public class JedisTest {
    private Jedis jedis;
    @Test
    public void run(){
        jedis=new Jedis("127.0.0.1",6379);
        jedis.select(0);
        String jedisTest = jedis.set("jedisTest", "123");
        System.out.println(jedisTest);
        String s = jedis.get("jedisTest");
        System.out.println(s);
        if(jedis!=null){
            jedis.close();
        }
    }
}

        运行结果:

        jedis提供的方法和指令名称是相同的,因此比较好上手。

        通过上述操作,我们可以看出jedis的使用,还是非常方便的,只需要三步就可以实现:

                1、导入依赖。

                2、建立连接。

                3、执行方法(和命令同名)。

        jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此,我们使用jedis连接池来代替上述这种直连的方式。

package com.jedis.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@RunWith(JUnit4.class)
public class JedisTest {
    private JedisPool jedisPool;
    @Test
    public void run2(){
        JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
        //最大连接
        jedisPoolConfig.setMaxTotal(8);
        //最大空闲连接
        jedisPoolConfig.setMaxIdle(8);
        //最小空闲连接数量
        jedisPoolConfig.setMinIdle(0);
        //设置最长等待时间
        jedisPoolConfig.setMaxWaitMillis(200);
        jedisPool=new JedisPool(jedisPoolConfig,"127.0.0.1",6379,1000);
        //通过连接池获取连接
        Jedis resource = jedisPool.getResource();
        String myTest = resource.set("myTest", "1234");
        System.out.println(myTest);
        String s = resource.get("myTest");
        System.out.println(s);
    }
}

        输出结果:

 三、SpringDataRedis(SpringBoot)的使用

        SpringData是Spring中数据操作的模块,官网地址:Spring Data Redis
        包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis

                提供了对不同Redis客户端的整合(Lettuce和Jedis)

                提供了RedisTemplate统一API来操作Redis

                支持Redis的发布订阅模型

                支持Redis哨兵和Redis集群

                支持基于Lettuce的响应式编程

                支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化支持基于Redis的JDKCollection实现

        SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。RedisTemplate,是根据命令种类来分类的方法。并且将不同数据类型的操作API封装到了不同的类型中:

        创建:

        SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单。

        首先,创建SpringBoot项目:

        导入相关依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- 连接池依赖 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        在resource目录下创建application.yaml文件:

        并填充内容:

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100

        测试代码:

package com.example.springdataredistest;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class SpringDataRedisTestApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("redisTemplate","success");
        String o = (String) redisTemplate.opsForValue().get("redisTemplate");
        System.out.println(o);
    }
}

        运行结果:

        但是我们发现,Redis数据库中存入的并非我们所想的内容:

        这是因为采用了SpringDataRedis默认的序列化方式。
        RedisTemplate可以接收任意0bject作为值写入Redis,只不过写入前会把0bject序列化为字节形式,默认是采用IDK序列化,得到的结果是上面这样的。

        这种方式有很大的缺点:1、可读性差。2、内存占用大。

        因此,我们可以自定义序列化方式,来得到我们想要的结果。

        我们创建一个配置类:

package com.example.springdataredistest.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration
public class SpringDataRedisConfig {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        //创建Template
        RedisTemplate<String,Object> redisTemplate=new RedisTemplate<>();
        //设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer=new GenericJackson2JsonRedisSerializer();
        //key和hashkey采用spring序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        //value和hashvalue采用json序列化
        redisTemplate.setValueSerializer(jsonRedisSerializer);
        redisTemplate.setHashKeySerializer(jsonRedisSerializer);
        return redisTemplate;
    }
}

        导入依赖:

        <!--  Jackson依赖  -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

        测试方法:

package com.example.springdataredistest;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
public class Test2 {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Test
    public void run(){
        redisTemplate.opsForValue().set("redisTemplateNew","successNew");
        String o = (String) redisTemplate.opsForValue().get("redisTemplateNew");
        System.out.println(o);
    }
}

        执行结果:

        数据库展示:

四、Redis使用小案例

        我们现在可以用Redis来模拟一下“抢红包”的场景。

        对于抢红包来说,我们需要从发红包的人和抢红包的人两个角度分别考虑。

        对于发红包来说,我们发一个红包链接,可以指定红包总金额以及红包数量,但是每个红包金额不能为0,最低为0.01。同时,如果一个红包链接上面的红包未领完,我们不能再次用这个链接来发放红包。

        对于抢红包来说,我们根据一个红包链接去抢红包,获得一个随机金额的红包,如果红包数量为0,就不能再抢了。

        通常情况下,发红包的频率要原低于抢红包的频率,而且,为了同时多个用户抢红包时,避免较慢的查询,因此,我们将数据存入内存,可以采用Redis来存储,同时在红包发放后,便指定好每一个红包的随机金额,抢红包的直接取数据,而不再需要通过计算获得,这样更加快捷。

        基于上述SpringDataRedis(SpringBoot)来实现,仍采用上述配置。

        可以用web场景来更好的交互。

        导入web场景依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        在启动类的同包或者自包下,创建controller:

package com.example.springdataredistest.controller;

import io.netty.util.internal.StringUtil;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.DoubleStream;

@Controller
public class MyController {

    @Resource
    private RedisTemplate redisTemplate;


    /**
     * 发放红包请求
     * @param suid 发放链接的参数
     * @param money 发放的金额
     * @param count 发放的红包总额
     * @return
     */
    @RequestMapping("/sendRedPackage")
    @ResponseBody
    public String sendRedPackage(String suid,Double money,Integer count){
        Object leftPop = redisTemplate.opsForList().leftPop(suid);
        if(leftPop!=null){//判断此红包链接是否发放完
            return "该红包发放连接,红包未领取完,不可以再次发送,请换一个连接发放!";
        }
        Random random=new Random();
        List<Double> result=new LinkedList<>();
        Double sum=0.0;
        for(int i=1;i<count;i++){//循环红包数量-1
            Double b=getRandomFloat(0.01,money);
            System.out.println(b);
            money-=b;
            result.add(b);
        }
        //最后一个红包的金额,由剩余金额决定
        money = Math.round(money * 100) / 100.0; // 保留两位小数,乘以100后进行四舍五入取整。
        //每个红包的钱不能为0
        if(money==0.0){
            money=0.01;
            for(int i=0;i<result.size();i++){//找一个红包中的钱大于0.01,从中扣除,补上金额为0的红包
                if(result.get(i)>0.01){
                    result.set(i,result.get(i)-0.01);
                    break;
                }
            }
        }
        result.add(money);//加上最后一个红包的金额
        System.out.println(result);
        redisTemplate.opsForList().leftPushAll(suid,result);//存入redis中
        return "发放成功!";
    }
    public Double getRandomFloat(Double min, Double max) {//得到浮点型的随机数
        Random random = new Random();
        Double result=min + random.nextDouble() * (max - min);
        result = Math.round(result * 100) / 100.0; // 保留两位小数
        return result;
    }

    /**
     * 抢红包的链接方法
     * @param suid 发放红包的链接参数
     * @return
     */
    @RequestMapping("/getRedPackage")
    @ResponseBody
    public String getRedPackage(String suid){
        Double d = (Double) redisTemplate.opsForList().leftPop(suid);
        if(d==null){
            return "红包连接无效,或者该用户的红包已经被抢完了!";
        }else{
            return "您抢到了"+d+"元";
        }
    }
}

        测试:

  • 16
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值