Java|SpringBoot整合Redis


Jedis ✍


Jedis是一个高性能的开源Java客户端,是Redis官方推荐的Java开发工具。
创建一个maven项目,配置如下:

		<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
cd 到pom所在文件夹下:
mvn -f pom.xml dependency:copy-dependencies

数据操作

以下代码展示部分操作方式:

import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.HashMap;
import java.util.Map;

public class JedisDemo {
    @Test
    public void operateString(){
        System.out.println("-----------Jedis String 相关命令测试-----------");
        Jedis jedis = new Jedis("xxx.xxx.xxx.xxx",6379);
        jedis.auth("xxxxx");
        System.out.println("Jedis.ping():"+jedis.ping());
        jedis.set("key0","123456");
        System.out.println("jedis.get(key0)"+jedis.get("key0"));
        jedis.mset("key1","val1","key2","val2");
        System.out.println("jedis.get(key*)"+jedis.keys("key*"));
        System.out.println("jedis.get(key1)):"+jedis.get("key1"));
        System.out.println("返回key的长度:"+jedis.strlen("key0"));
        System.out.println("追加字符串:"+jedis.append("key0","app"));
        System.out.println("打印key0:"+jedis.get("key0"));
        System.out.println("---------------------------------------------");
        jedis.close();
    }


    @Test
    public void operateList(){
        System.out.println("-----------Jedis List 相关命令测试-----------");
        Jedis jedis = new Jedis("xxx.xxx.xxx.xxx",6379);
        jedis.auth("xxxxx");
        System.out.println("Jedis.ping():"+jedis.ping());
        jedis.del("list1");

        //从List尾部添加3个元素
        jedis.rpush("list1","alice","bob","cindy");

        System.out.println("获取类型:"+jedis.type("list1"));
        System.out.println("遍历区间[0.-1],获取全部的元素:"+jedis.lrange("list1",0,-1));
        System.out.println("获取List的长度:"+jedis.llen("list1"));
        System.out.println("---------------------------------------------");
        jedis.close();
    }

    @Test
    public void oprateHash(){
        System.out.println("-----------Jedis Hash 相关命令测试-----------");
        Jedis jedis = new Jedis("xxx.xxx.xxx.xxx",6379);
        jedis.auth("xxxxx");

        jedis.del("config");
        jedis.hset("config","ip","127.0.0.1");
        System.out.println("获取Hash的Field关联的Value:"+jedis.hget("config","ip"));
        System.out.println("获取类型:"+jedis.type("config"));

        //批量添加field-value对
        Map<String,String> configFields = new HashMap<>();
        configFields.put("port","8080");
        configFields.put("maxalive","3600");
        configFields.put("weight","1.0");
        //执行批量添加
        jedis.hmset("config",configFields);
        System.out.println("批量获取:"+jedis.hgetAll("config"));
        System.out.println("获取所有的key:"+jedis.hkeys("config"));
        System.out.println("获取所有的val:"+jedis.hvals("config"));
        System.out.println("获取长度:"+jedis.hlen("config"));
        System.out.println("---------------------------------------------");
        jedis.close();
    }

}

运行结果:


事务操作

import com.alibaba.fastjson.JSONObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class JedisTransTest {
    /**
     * Jedis的事务测试
     */
    public static void main(String[] args){
        Jedis jedis = new Jedis("49.235.200.38",6379);
        jedis.auth("2472500609cn#");
        System.out.println("Jedis.ping():"+jedis.ping());

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name1","alice");
        jsonObject.put("name2","bob");

        //开启事务
        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();
        jedis.flushDB();
        //jedis.watch(result);
        try {
            multi.set("user1",result);
            multi.set("user2",result);
            multi.exec(); //执行事务
        }catch (Exception e){
            multi.discard();//放弃事务
            e.printStackTrace();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.close();//关闭连接
        }

    }
}

JedisPool

数据库连接的底层是一条Socket通道,其创建和销毁很耗时间,需要有三次握手和四次挥手。
在数据库连接过程中,为了防止数据库连接的频繁创建、销毁带来的性能损耗,常常会用到连接池。
例如淘宝的Druid连接池、Tomcat的DBCP连接池。



SpringBoot整合Redis ✍


依赖

创建一个SpringBoot的项目,pom.xml文件redis依赖:

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

ctrl键 : spring-boot-starter-data-redis

	<dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-redis</artifactId>
      <version>2.4.8</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>io.lettuce</groupId>
      <artifactId>lettuce-core</artifactId>
      <version>6.0.4.RELEASE</version>
      <scope>compile</scope>
    </dependency>

发现有lettuce但没有jedis

在SpringBoot2.x之后,原本使用的jedis被替换为了lettuce。

  • jedis:采用直连,多个线程操作的话是不安全的,如果要避免不安全的情况,要使用JedisPool连接池,像BIO,又有其他问题。
  • lettuce:底层采用netty,实例可以在多个线程中进行共享,不存在线程不安全的情况,可以减少线程的数量,更像NIO模式。

自动配置

SpringBoot所有的配置类都有一个自动配置类,
自动配置类都会绑定一个properties配置文件。

打开RedisAutoConfiguration,源码如下:

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public RedisTemplate<Object, Object> redisTemplate
    (RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public StringRedisTemplate stringRedisTemplate
    (RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

@EnableConfigurationProperties({RedisProperties.class})用在配置类的注解,开启RedisProperties类的属性配置功能,将RedisProperties组件自动注入到容器中。
RedisProperties源码截图:

RedisProperties类上的注解:
@ConfigurationProperties(prefix = "spring.redis")
这个注解让类与配置文件application.properties绑定

类里的属性都是可以配置的内容:
	private int database = 0;
    private String url;
    private String host = "localhost";
    private String username;
    private String password;
    private int port = 6379;
    private boolean ssl;
    private Duration timeout;
    private Duration connectTimeout;
    private String clientName;
    private RedisProperties.ClientType clientType;
    private RedisProperties.Sentinel sentinel;
    private RedisProperties.Cluster cluster;
    private final RedisProperties.Jedis jedis = new RedisProperties.Jedis();
    private final RedisProperties.Lettuce lettuce = new RedisProperties.Lettuce();

配置类

RedisAutoConfiguration有两个模板方法:

	@Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )//可以自己定义一个redisTemplate来替换这个默认的
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    //默认的RedisTemplate没有过多的设置,redis对象需要序列化
    //两个泛型都是Object,Object的类型,使用需要强制转换为String,Object
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    //String是redis中最常使用的类型,所以单独一个方法
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

配置文件:


这里有个点需要注意一下,如果你想连接远程的Redis服务器的话,redis.conf文件里:

这个要注释掉,不然会连接失败。

测试:

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.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class SpnnredisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {

        //获取redis的连接对象
        RedisConnection connection =
         redisTemplate.getConnectionFactory().getConnection();
        System.out.println(connection.ping());
        connection.flushDb();

        //字符串操作
        redisTemplate.opsForValue().set("key1","ablice");
        System.out.println(redisTemplate.opsForValue().get("key1"));
        //List操作
        //redisTemplate.opsForList();
        //Set操作
        //redisTemplate.opsForSet();
        //balabala好多操作
        
    }

}


源码分析

再来看RedisAutoConfiguration类的注解:

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() { }

注意最后一个@Import

//将指定类型的组件导入
//给容器自动创建出指定类的无参构造器返回的组件
@Import({User.class,XXX.class})

这里@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})就是自动创建Lettucexxx、Jedisxxx类的无参构造器返回的组件。不过默认是LettuceConnectionConfiguration生效。


再看redisTemplate方法,返回的是一个RedisTemplate类。

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

查看RedisTemplate类源码,截取部分:


自定义RedisTemplate

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * 可以当作一个固定模板
 */

@Configuration
public class RedisConfig {

    //从RedisAutoConfiguration复制模板过来
    //修改成自己的
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        //为了平时开发方便,使用<String,Object>
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //连接Redis工厂
        template.setConnectionFactory(redisConnectionFactory);

        //序列化操作 Json序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //转译
        ObjectMapper objectMapper = new ObjectMapper();
        //方便的方法允许更改底层VisibilityCheckers的配置,以更改自动检测哪些属性的详细信息
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // String的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        //key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        //把所有的properties Set进去
        template.afterPropertiesSet();

        return template;
    }

}

@SpringBootTest
class SpnnredisApplicationTests {

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    @Test
    public void testU() throws JsonProcessingException {
        redisTemplate.opsForValue().set("user1", new User("alice",1));
        Object user1 = redisTemplate.opsForValue().get("user1");
        System.out.println(user1);
    }

}

没有乱码了。

平时开发可以创建一个RedisUtil类去封装操作。

@SpringBootTest
class SpnnredisApplicationTests {

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisUtil redisUtil;

    @Test
    public void testUtil(){
        redisUtil.set("name","alice");
        System.out.println(redisUtil.get("name"));
    }

}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值