springboot连接redis以及使用场景

springboot连接redis

1. 通过jedis类

  1. 先引依赖
  <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.3.0</version>
        </dependency>
    </dependencies>
  1. 使用
package com.daiji.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;

import java.util.Set;

/**
 * @Author 呆鸡
 * @Date 2021/4/14 16:49
 * @Version 1.0
 */
public class TestJedis {
    public static void main(String[] args) {
        Jedis jedis=new Jedis("192.168.31.52",6379);//必须运行远程连接 必须防火墙放行该端口号
        //关于字符串
        jedis.set("k1","v1");
        jedis.set("k8","18");
        jedis.mset("k2","v2","k3","v3","k4","v4");
        jedis.setnx("k1","12");
        jedis.decr("k8");

        //操作key
        Set<String> keys = jedis.keys("*");
        System.out.println("所有的key:"+keys);
        jedis.del("k1");
        jedis.expire("k2",60);
        jedis.ttl("k2");

    }
}
  1. 使用jedis连接池
package com.ykq.test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @Author 闫克起
 * @Date 2021/4/14 16:59
 * @Version 1.0
 */
public class TestPoolJedis {
    public static void main(String[] args) {
        //连接池的配置
        JedisPoolConfig config=new JedisPoolConfig();
        config.setMaxTotal(100);//设置连接池的最大连接数
        config.setMaxIdle(10);//设置最大空闲的个数
        config.setTestOnBorrow(true);//在从连接池这种获取连接对象前是否测试该对象可以。

        //创建连接池对象
        JedisPool jedisPool=new JedisPool(config,"192.168.213.188",6379);

        //获取jedis对象
        Jedis jedis = jedisPool.getResource();

        System.out.println(jedis.get("k3"));

        jedis.close();//释放资源


    }
}

2. 使用工具类RedisTemplate

  1. 引入依赖
         <!---->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  1. 配置文件
    //连接单机redis
	spring.redis.host=192.168.213.188 //ip
	spring.redis.port=6379 //端口号

	//连接哨兵集群
	spring.redis.sentinel.master=mymaster //主机的名字
	spring.redis.sentinel.nodes=192.168.213.188:26379 //主机id和端口号
	
	//去中心化集群
	spring.redis.cluster.nodes=192.168.213.188:8001,192.168.213.188:8002,192.168.213.188:8003,192.168.213.188:8004,192.168.213.188:8005,192.168.213.188:8006
  1. 使用redisTemplate该类可以存放任意类型的数据,但是该类型的数据必须实现序列,获取redis中对应的数据时,会进行反序列化。 如果使用RedisTemplate建议大家指定key,value,以及hashkey的序列化方式。
    可以通过配置文件来指定序列化方式
package com.daiji.config;

/**
 * @Author 呆鸡
 * @Date 2021/4/15 16:16
 * @Version 1.0
 */
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;

import java.time.Duration;

@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    //比如验证码
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        template.setConnectionFactory(factory);
        //key序列化方式
        template.setKeySerializer(redisSerializer);
        //value序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //value hashmap序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        return template;
    }

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600)) //缓存过期10分钟 ---- 业务需求。
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))//设置key的序列化方式
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) //设置value的序列化
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

3. 使用场景

1. 作为缓存

在这里插入图片描述

用redis做缓存:根据redis的get方法,如果有数据就是有缓存,如果没有数据就代表缓存中没有,就去访问数据库
可以使用注解来让复杂的代码简单化。

  1. 不试用注解
@Service
public class DeptService {

    @Resource
    private DeptDao deptDao;

    @Autowired
    private RedisTemplate redisTemplate;

    public Dept findById(Integer deptId){
        //1.从缓存中查询该数据
        Object o = redisTemplate.opsForValue().get("findById::" + deptId);
        if(o!=null){//表示从缓存中获取该数据
            return (Dept) o;
        }
        Dept dept = deptDao.selectById(deptId);
        redisTemplate.opsForValue().set("findById::"+deptId,dept);//把查询的结果放入缓存
        return dept;
    }


    //数据库和缓存同步问题!
    public int delete(Integer deptId){
        redisTemplate.delete("findById::"+deptId);//删除缓存
        int i = deptDao.deleteById(deptId);
        return i;
    }

    public int update(Dept dept){
        redisTemplate.delete("findById::"+dept.getDeptId());//删除缓存
        int i = deptDao.updateById(dept);
        redisTemplate.opsForValue().set("findById::"+dept.getDeptId(),dept);
        return i;
    }
}
  1. 使用注解(在启动类加上@EnableCaching注解来开启缓存注解)
@Service
public class DeptService {

    @Resource
    private DeptDao deptDao;

    //该注解作用:会先查询缓存,如果缓存存在,则不会执行代码块。 如果缓存中不存在则执行该方法,并把该方法的返回值存放到redis中
    @Cacheable(cacheNames = "findById",key = "#deptId")  //缓存的key值 为findById
    public Dept findById(Integer deptId){
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        Dept dept = deptDao.selectById(deptId);
        return dept;
    }


    //数据库和缓存同步问题!
    // beforeInvocation:是否在方法执行前就清空,缺省为 false,
    // 如果指定为 true,则在方法还没有执行的时候就清空缓存。缺省情况下,如果方法执行抛出异常,则不会清空缓存。
    @CacheEvict(cacheNames = "findById",key = "#deptId")
    public int delete(Integer deptId){
        int i = deptDao.deleteById(deptId);
        return i;
    }

    //这个注解是必须执行方法体,而且会把方法体执行的结果放入到缓存中。 如果发生异常则不操作缓存。
    @CachePut(cacheNames = "findById",key = "#dept.deptId")
    public Dept update(Dept dept){
        int i = deptDao.updateById(dept);
        return dept;
    }
}

2. 作为分布式锁

在分布式项目中,需要保证线程的安全,此时使用synchronized就不行了,因为在分布式项目中没办法使用同一个锁对象。
这时就可以通过使用redis数据库中的setnx方法,因为redis是单线程的,一次只能处理一个线程,所以如果返回true就代表你到了锁资源,如果返回false就代表没拿到锁资源。
使用完之后要删除该数据,以便后续的线程能通过setnx方法返回true

代码

@Service
public class StockService {

    @Resource
    private StockDao stockDao;

    @Autowired
    private StringRedisTemplate redisTemplate;

    public String decrStock(Integer productId) {//synchronized () 同步方法    同步代码块
        Boolean flag = redisTemplate.opsForValue().setIfAbsent("product::" + productId, "ykq",30, TimeUnit.SECONDS);
        //查询对应的id的库存
         if(flag) {//获取锁了
             try {
                 Stock stock = stockDao.selectById(productId);
                 if (stock.getNum() > 0) {
                     //根据id修改库存
                     stock.setNum(stock.getNum() - 1);
                     stockDao.updateById(stock); //异常发生
//                   int c=10/0;
                     System.out.println("库存剩余:" + (stock.getNum()));
                     return "库存减少成功";
                 } else {
                     return "库存不足";
                 }
             }catch (Exception e){
                  throw  new RuntimeException(e.getMessage());
             }
             finally {
                 redisTemplate.delete("product::" + productId);//释放锁资源 一定再finally
             }
         }else{
             System.out.println("服务器正忙请稍后再试..........");
             return "服务器正忙请稍后再试..........";
         }
    }
}

或者使用第三方插件redisson:一个专门用来解决分布式问题的插件

  1. 引依赖
       <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.13.4</version>
        </dependency>
  1. 在配置文件中配置redis的配置
   @Bean
    public RedissonClient getRedisson(){
        Config config=new Config();
        config.useSingleServer().setAddress("redis://192.168.213.188:6379");
        RedissonClient redissonClient = Redisson.create(config);
        return redissonClient;
    }
  1. 使用local或者trylock
@Service
public class StockService {

    @Resource
    private StockDao stockDao;

    @Autowired
    private RedissonClient redisson; 

        @Override
    @CachePut(cacheNames = "find",key = "#id")
    public Lock update(Integer id) {
        RLock lock = redissonClient.getLock("update::" + id);

        if (lock.tryLock()){
            try {
                Lock myLock = lockDao.selectById(id);
                    if (myLock!=null && myLock.getLockNum()>0){
                        myLock.setLockNum(myLock.getLockNum()-1);
                        lockDao.updateById(myLock);
                        System.out.println("票还剩"+myLock.getLockNum()+"张");
                        return myLock;
                    }
            }finally{
                if (lock.isLocked()){
                        lock.unlock();
                }
            }
        }

        return update(id);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用Spring Boot自带的Redis Starter来集成Redis,然后使用Redis的官方客户端Jedis或Lettuce来实现看门狗功能。具体实现可以参考Redis官方文档或相关的开源项目。 ### 回答2: Spring Boot是一个开源的Java开发框架,它简化了基于Spring的应用程序的开发过程。Redis是一种支持内存缓存的键值对数据库。 使用Spring Boot中的Redis看门狗功能可以通过监控Redis的失效事件,并在发生失效事件时执行一系列操作。在Spring Boot中,我们可以使用Spring Data Redis提供的功能来实现这一功能。 首先,我们需要在Spring Boot的配置文件中配置Redis连接信息,包括主机名,端口号和密码(如果有)。然后,我们可以使用Spring Boot提供的RedisTemplate对象来与Redis进行交互。 要使用Redis看门狗,我们需要配置一个Redis的监听器,以便在发生失效事件时触发相应的操作。我们可以使用Redis的KeyExpirationEventMessageListener监听器来实现这一功能。我们需要创建一个类并实现MessageListener接口,然后重写onMessage方法来定义触发失效事件时的操作。 在onMessage方法中,我们可以获取到失效的键名和触发失效事件的类型。根据需要,我们可以执行一系列操作,比如重新加载缓存、处理一些逻辑或通知其他组件。 为了使这个监听器生效,我们还需要将其注册到RedisTemplate中。这可以通过在RedisTemplate的配置文件中注册这个监听器来实现。 总之,使用Spring Boot中的Redis看门狗功能可以帮助我们实时监控Redis的失效事件,并在发生失效事件时执行相应的操作。这可以提高系统的稳定性和性能,并更好地利用Redis的缓存功能。 ### 回答3: Spring Boot可以使用Redis实现看门狗功能。看门狗是一种监控系统,用于检测和处理系统中出现的异常情况。 在Spring Boot中使用Redis实现看门狗功能主要包括以下步骤: 1. 在Spring Boot项目中引入Redis的依赖。可以使用Maven或Gradle添加相应的依赖项。 2. 配置Redis连接信息。在application.properties(或application.yml)文件中添加Redis连接配置,包括主机地址、端口号、密码等。 3. 使用Redis的消息队列功能实现异步处理。通过在程序中创建一个消息队列,并将需要处理的异常情况存储为消息,然后由消费者异步处理这些消息。 4. 配置定时任务。使用Spring Boot的定时任务功能,定期从Redis的消息队列中获取待处理的消息,并进行处理。 5. 根据实际需求编写相关代码。根据具体的应用场景和需求,编写代码来处理异常情况,例如发送警报、记录日志、恢复系统等。 使用Redis实现看门狗功能的好处是,Redis具有高性能、高可用性和灵活的数据结构等特点,能够支持大规模并发和高效的异步处理。此外,Redis还提供了丰富的API,方便开发人员进行操作和管理。 总而言之,Spring Boot可以通过使用Redis来实现看门狗功能,该功能可以监控和处理系统中的异常情况,提高系统的稳定性和可靠性。通过配置Redis连接信息、使用Redis的消息队列和定时任务等功能,开发人员能够根据实际需求编写代码并实现对异常情况的处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值