Bootstrap

redis详解--springboot整合redis

1. java连接redis

思考: 我们之前操作redis都是通过命令行的客户端来操作。 在开发时都是通过java项目操作redis.

引入Redis依赖

<!--引入java连接redis的驱动-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>4.3.1</version>
        </dependency>
1.1 连接redis

最简单的连接方式,就是通过 Jedis 对象连接。代码如下:

//引入Redis驱动程序
import redis.clients.jedis.Jedis;

public class RedisJava {
    public static void main(String[] args) {
        //连接Redis服务--> 默认连接本地的redis 端口号6379.
        Jedis jedis = new Jedis("172.16.7.110",6379);
        // 如果设置 Redis 服务的密码,需要进行验证,若没有则可以省去
        // jedis.auth("123456");
    }
}

所有关于redis操作的功能都在该类中Jedis

//关于key的命令
        Set<String> keys = jedis.keys("*");
        System.out.println("所有的key:"+keys);

        long del = jedis.del("k1", "k2", "k3");
        System.out.println("删除key的个数:"+del);

        boolean k4 = jedis.exists("k4");
        System.out.println("判断指定的k4是否存在:"+k4);

        long k5 = jedis.expire("k5", 10);
//关于字符串类型的命令:
        String set = jedis.set("k1", "v1");
        System.out.println("存入k1的值:"+set);

        String k1 = jedis.get("k1");
        System.out.println("获取指定key的值:"+k1);

        long k2 = jedis.setnx("k2", "110");
        System.out.println("如果k2不存在,则设置k2的值:"+k2);

        long k21 = jedis.incr("k2");
        System.out.println("k2的值加1:"+k21);

        long k22 = jedis.decr("k2");
        System.out.println("k2的值减1:"+k22);

        String setex = jedis.setex("k3", 100, "v3");
        System.out.println("k3的值:"+setex);
//关于hash类型的命令:
        long hset = jedis.hset("k4", "k41", "v41");
        System.out.println("存入k4的键值对:"+hset);
        Map<String,String> map=new HashMap<>();
        map.put("name","张三");
        map.put("age","18");
        long k51 = jedis.hset("k5", map);
        System.out.println("存入k5的键值对:"+k51);
        String hget = jedis.hget("k5", "name");
        System.out.println("获取k5的name的值:"+hget);
        Map<String, String> k52 = jedis.hgetAll("k5");
        System.out.println("获取k5的所有键值对:"+k52);

1.2 java连接redis集群模式

适合ssm项目

 public static void main(String[] args) {
        Set<HostAndPort> nodes=new HashSet<>();
        nodes.add(new HostAndPort("192.168.111.188",7001));
        nodes.add(new HostAndPort("192.168.111.188",7002));
        nodes.add(new HostAndPort("192.168.111.188",7003));
        nodes.add(new HostAndPort("192.168.111.188",7004));
        nodes.add(new HostAndPort("192.168.111.188",7005));
        nodes.add(new HostAndPort("192.168.111.188",7006));
        JedisCluster jedisCluster=new JedisCluster(nodes);
        jedisCluster.set("k5","666");
        System.out.println(jedisCluster.get("k5"));
    }

2. springboot整合redis

引入依赖

       <!--引入了redis整合springboot 的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

修改配置文件

#配置redis信息
#redis服务器地址
spring.redis.host=localhost
#redis服务器端口
spring.redis.port=6379
#连接池最大连接数(使用负数表示没有限制)默认8
spring.redis.lettuce.pool.max-active=100
#连接池最大阻塞等待时间(使用负值表示没有限制)默认-1
spring.redis.lettuce.pool.max-wait=PT10S
#连接池最大空闲连接数(使用负值表示没有限制)默认8
spring.redis.lettuce.pool.max-idle=30
#连接池最小空闲连接数(使用负值表示没有限制)默认0
spring.redis.lettuce.pool.min-idle=1
#连接超时时间
spring.redis.timeout=PT10S

使用

springboot整合redis时封装了两个工具类:StringRedisTemplate和RedisTemplate.

StringRedisTemplate它是RedisTemplate的子类。StringRedisTemplate里面只能存放字符串的内容。

1. StringRedisTemplate
@Autowired
    private StringRedisTemplate stringRedisTemplate;
//关于key的操作
    @Test
    void textkey() {
        Set<String> keys = stringRedisTemplate.keys("*");
        System.out.println("查询全部:"+keys);
        Boolean k1 = stringRedisTemplate.delete("k1");
        System.out.println("删除是否成功:"+k1);
        Boolean k2 = stringRedisTemplate.hasKey("k2");
        System.out.println("查询指定k是否存在:"+k2);
        Boolean k11 = stringRedisTemplate.expire("k1", 10, TimeUnit.SECONDS);
        System.out.println("设置过期时间的k"+k11);
    }

//关于String的操作: 在封装的StringRedisTemplate类对应每种数据类型的操作 对应相应的类来完成
    @Test
    void textString(){
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        //存放数据
        opsForValue.set("k1","k1");
        //存放并设置过期时间
        opsForValue.set("k2","20",2,TimeUnit.MICROSECONDS);
        //存放(有则不存放,无则存放)并设置过期时间
        Boolean aBoolean = opsForValue.setIfAbsent("k3", "v3", 2, TimeUnit.MICROSECONDS);
        System.out.println("是否设置成功:"+aBoolean);
        //获取指定k
        String k1 = opsForValue.get("k1");
        System.out.println("获取指定k"+k1);
        //设置增量
        Long k2 = opsForValue.increment("k2", 10);
        System.out.println("获取增量后的值:"+k2);
    }

 //关于Hash的操作
    @Test
    public void testHash(){
        HashOperations<String, Object, Object> forHash = 		               stringRedisTemplate.opsForHash();
        //存放数据  hset(key,field,value)
        forHash.put("user","name","ykq");
        Map<String,String> map=new HashMap<>();
        map.put("age","18");
        map.put("adrress","北京");
        forHash.putAll("user",map);
        //获取指定的元素  hget(key,field)
        Object o = forHash.get("user", "name");
        System.out.println("获取指定的元素:"+o);
        Map<Object, Object> user = forHash.entries("user");
        System.out.println("获取所有的元素:"+user);

        Set<Object> user1 = forHash.keys("user");
        System.out.println("获取所有的key:"+user1);
        List<Object> user2 = forHash.values("user");
        System.out.println("获取所有的value:"+user2);
    }


2. RedisTemplate
它属于StringRedisTemplate的父类,它的泛型默认都是Object。它可以直接存储任意类型的key和value.
 @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void test01(){
        //指定key的序列化方式。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //指定value的序列化方式
        redisTemplate.setValueSerializer(new FastJsonRedisSerializer<>(Object.class));
		
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //发现redis的database库中出现了乱码?
        // 1.key要不要序列化。要。默认使用的是jdk序列化方式 。
        valueOperations.set("k11","v11");

        System.out.println(valueOperations.get("k11"));//能否获取值。--能

        //org.springframework.data.redis.serializer.SerializationException: 序列化
        //发现报错--序列化异常---原因-User对象没有序列化
        //把内存中的数据存入磁盘---序列化过程
        valueOperations.set("k12",new User("fwx",18));

        JSONObject k12 = (JSONObject) valueOperations.get("k12");

    }

如果使用RedisTemplate每次都需要人为指定key和value的序列化

所以可以自己配置

@Configuration
public class RedisTemplateConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {

        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(jackson2JsonRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    @Bean

    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory)
            throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

3. 集群模式
#集群模式
#在application配置文件中配置
spring.redis.cluster.nodes=192.168.111.188:7006,192.168.111.188:7001,192.168.111.188:7002,192.168.111.188:7003,192.168.111.188:7004,192.168.111.188:7005

3. 案例–短信业务

public class SendMsgUtil {
    /**
     * 使用AK&SK初始化账号Client
     * @return Client
     * @throws Exception
     */
    
    public static Client createClient() throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
                .setAccessKeyId("aliyun的账号")

                // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
                .setAccessKeySecret("aliyun的密钥");
        // Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
        config.endpoint = "dysmsapi.aliyuncs.com";
        return new com.aliyun.teaopenapi.Client(config);
    }

    /**
     * API 相关
     * @return OpenApi.Params
     */
    public static com.aliyun.teaopenapi.models.Params createApiInfo() throws Exception {
        com.aliyun.teaopenapi.models.Params params = new com.aliyun.teaopenapi.models.Params()
                // 接口名称
                .setAction("SendSms")
                // 接口版本
                .setVersion("2017-05-25")
                // 接口协议
                .setProtocol("HTTPS")
                // 接口 HTTP 方法
                .setMethod("POST")
                .setAuthType("AK")
                .setStyle("RPC")
                // 接口 PATH
                .setPathname("/")
                // 接口请求体内容格式
                .setReqBodyType("json")
                // 接口响应体内容格式
                .setBodyType("json");
        return params;
    }

    public static String sendCode(String phone) throws Exception {
        com.aliyun.teaopenapi.Client client = createClient();
        com.aliyun.teaopenapi.models.Params params = createApiInfo();
        // query params
        java.util.Map<String, Object> queries = new java.util.HashMap<>();
        queries.put("PhoneNumbers", "13388569043");
        queries.put("SignName", "短信服务的签名");
        queries.put("TemplateCode", "短信服务的模板"); //您正在申请手机注册,验证码为:${code},5分钟内有效!
        String code="123456";
        queries.put("TemplateParam", "{\"code\":\""+code+"\"}");
        // runtime options
        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
        com.aliyun.teaopenapi.models.OpenApiRequest request = new com.aliyun.teaopenapi.models.OpenApiRequest()
                .setQuery(com.aliyun.openapiutil.Client.query(queries));
        // 复制代码运行请自行打印 API 的返回值
        // 返回值为 Map 类型,可从 Map 中获得三类数据:响应体 body、响应头 headers、HTTP 返回的状态码 statusCode
        client.callApi(params, request, runtime);
        return code;
    }
}
;