Spring之Redis访问(Spring-data-redis)详解数据库

  Spring-data-redis,是spring-data框架中,比较常用的,基于key-value键值对的数据持久层框架。Spring-data-redis,是一个基于Template模板开发的数据访问层框架。都是基于配置+template方法调用,实现redis数据CRUD操作的。

  没有Spring-data-redis的时候,使用jedis-client来实现redis的访问。需要自己控制jedis中的具体逻辑,实现redis数据的CURD操作。

  spring-data框架中的每个子模块其版本未必一致,毕竟对应不同数据服务的访问层框架,更新时间和周期是不同的。在本案例中,使用的spring-data-redis版本为1.8.14。spring-data-redis框架的执行需要jackson组件的辅助,建议导入jackson版本为2.7+(对应当前环境中的spring-data-redis版本)。

  包依赖:

<!-- spring-data-redis核心 --> 
<dependency> 
    <groupId>org.springframework.data</groupId> 
    <artifactId>spring-data-redis</artifactId> 
    <version>1.8.14.RELEASE</version> 
</dependency> 
<!-- redis-client核心 --> 
<dependency> 
    <groupId>redis.clients</groupId> 
    <artifactId>jedis</artifactId> 
    <version>2.9.0</version> 
</dependency> 
<!-- spring-data-redis做数据转换使用的辅助插件 --> 
<dependency> 
    <groupId>com.fasterxml.jackson.core</groupId> 
    <artifactId>jackson-databind</artifactId> 
    <version>2.9.5</version> 
</dependency>

  全局配置applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop.xsd 
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd"> 
    <!-- 配置读取properties文件的工具类 --> 
    <context:property-placeholder location="classpath:redis/redis.properties"/> 
     
    <!-- Jedis连接池,高效连接 value配置来自文件redis.properties--> 
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> 
        <property name="maxTotal" value="${redis.pool.maxTotal}"/> 
        <property name="maxIdle" value="${redis.pool.maxIdle}"/> 
        <property name="minIdle" value="${redis.pool.minIdle}"/> 
    </bean> 
    <!-- redis集群配置 --> 
    <bean id="redisClusterConfig" class="org.springframework.data.redis.connection.RedisClusterConfiguration"> 
        <constructor-arg name="clusterNodes"> 
            <list> 
                <value>192.168.2.124:7001</value> 
                <value>192.168.2.124:7002</value> 
                <value>192.168.2.124:7003</value> 
                <value>192.168.2.124:7004</value> 
                <value>192.168.2.124:7005</value> 
                <value>192.168.2.124:7006</value> 
            </list> 
        </constructor-arg> 
    </bean> 
    <!-- Jedis的连接工厂,不可缺少的。是用于构建连接对象jedis的。 --> 
    <bean id="jedisConnectionFactory"  
            class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> 
        <!-- 单机版访问配置 --> 
        <property name="hostName" value="${redis.conn.hostName}"/> 
        <property name="port" value="${redis.conn.port}"/> 
        <property name="poolConfig" ref="poolConfig"/> 
        <!-- 集群版访问配置 --> 
        <!-- <constructor-arg name="clusterConfig" ref="redisClusterConfig" /> 
        <constructor-arg name="poolConfig" ref="poolConfig" /> --> 
    </bean> 
    <!-- Redis模板对象,类似JDBCTemplate。模板方法模式开发的代码。RedisTemplate中定义了若干的方法,用于实现数据的CRUD操作。 --> 
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> 
        <property name="connectionFactory" ref="jedisConnectionFactory"/> 
        <!-- 序列化器:能够把我们储存的key与value做序列化处理的对象,是一个类似于converter的工具。 
            可以实现传入的java对象->redis可以识别的数据类型。 如:字符串。 
            默认的Serializer是StringRedisSerializer。 
            设定默认的序列化器是字符串序列化器,原因是redis可以存储的数据只有字符串字节数组 
            一般来说,我们代码中操作的数据对象都是java对象。 
            如果代码中,使用的数据载体就是字符串对象,那么使用Jackson2JsonRedisSerializer来做序列化器是否会有问题? 
            如果jackson插件的版本不合适,有错误隐患的话,可能将字符串数据转换为json字符串 -> {chars:[], bytes:[]} 
            使用StringRedisSerializer就没有这个问题。不处理字符串转换的。认为代码中操作的key和value都是字符串。 
         --> 
        <!-- 配置默认的序列化器 --> 
        <!-- keySerializervalueSerializer 配置Redis中的String类型key与value的序列化器 --> 
        <!-- HashKeySerializerHashValueSerializer 配置Redis中的Hash类型key与value的序列化器 --> 
        <property name="keySerializer"> 
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> 
        </property> 
        <property name="valueSerializer"> 
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> 
        </property> 
    </bean> 
</beans>

  Redis数据库连接配置:redis.properties

redis.pool.maxTotal=20 
redis.pool.maxIdle=10 
redis.pool.minIdle=5 
 
redis.conn.hostName=127.0.0.1 
redis.conn.port=6379

  测试类:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:redis/applicationContext.xml") 
public class RedisTest { 
 
    @Autowired 
    private RedisTemplate<String, Object> redisTemplate; 
     
    /** 
     * 添加键值对 - 字符串类型 
     * redisTemplate中,提供了若干的Operations,每一个Operations对应一个Redis中的数据类型。 
     * 如:ValueOperations - 字符串类型。  HashOperations - hash类型*/ 
    @Test 
    public void test1(){ 
        ValueOperations<String, Object> ops = this.redisTemplate.opsForValue(); 
        ops.set("key", "test"); 
    } 
     
    /** 
     * 获取redis中的数据 
     */ 
    @Test 
    public void test2(){ 
        String str = (String)this.redisTemplate.opsForValue().get("key"); 
        System.out.println(str); 
         
        // 新增/更新数据,并设置有效期。 
        // this.redisTemplate.opsForValue().set("key", "test", 10L, TimeUnit.SECONDS); 
         
        // 设置数据有效期。 
        this.redisTemplate.expire("key", 10, TimeUnit.SECONDS); 
    } 
     
    /** 
     * 添加Users 
     * 将java对象,存储到redis中,可以使用两种存储方式。 
     * 1 - 使用JDK提供的Serializable,实现对象序列化。 
     *  改变valueSerilizer的序列化器。JdkSerializationRedisSerializer 
     *  用JDKSerializationRedisSerializer做序列化,有不好的地方。 
     *  JDKSerialization序列化结果太长。占用更多的字节空间。进行序列化和反序列化的效率较低。 
     *  并且对象必须实现序列化接口,如public class Users implements Serializable 
     */ 
    @Test 
    public void test3(){ 
        Users users = new Users(); 
        users.setUserage(30); 
        users.setUserid(1); 
        users.setUsername("张三"); 
        //更换序列化器,通过API来更换序列化器,好处是有针对性。需要什么序列化器就提供什么序列化器。默认都使用StringRedisSerializer 
        this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); 
        this.redisTemplate.opsForValue().set("users", users); 
    } 
     
    /** 
     * 获取Users 
     *  
     */ 
    @Test 
    public void test4(){ 
        //更换序列化器 
        this.redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); 
        Users users = (Users)this.redisTemplate.opsForValue().get("users"); 
        System.out.println(users); 
    } 
 
    /** 
     * 添加Users JSON格式 
     * JSON数据,人机皆可使用。 
     * JSON数据占用的存储空间小,且和java对象的转换效率高。 
     * 缺陷 - 不能描述双向关系。如果使用json来描述双向关联关系,则会出现无限嵌套,是一个死循环。会有内存溢出错误, OutOfMemeryError 
     * class A{ B b; } 
     * class B{ A a; } 
     * A a = new A(); 
     * json - { .... , b : { ... , a : { ...., b : { ...., a : { }}}}} 
     */ 
    @Test 
    public void test5(){ 
        Users users = new Users(); 
        users.setUserage(30); 
        users.setUserid(2); 
        users.setUsername("李四"); 
         
        this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Users>(Users.class)); 
        this.redisTemplate.opsForValue().set("usersjson", users); 
    } 
     
    /** 
     * 获取Uesrs JSON格式 
     */ 
    @Test 
    public void test6(){ 
        this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Users>(Users.class)); 
        Users users = (Users)this.redisTemplate.opsForValue().get("usersjson"); 
        System.out.println(users); 
    } 
     
    /** 
     * 常用API 
     */ 
    @Test 
    public void test7(){ 
        // 设置有效期 
        this.redisTemplate.expire("usersjson", 300, TimeUnit.SECONDS); 
         
        try { 
            Thread.sleep(2000); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
         
        // 查询有效期 
        long expire = this.redisTemplate.getExpire("usersjson"); 
        System.out.println("expire = " + expire); 
         
        try { 
            Thread.sleep(10000); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
        // 删除有效期 
        this.redisTemplate.persist("usersjson"); 
    } 
}

  User实体类:

@Entitypublic class Users implements Serializable{ 
private Integer userid;private String username;private Integer userage;

public Users(String username, Integer userage){ this.username = username; this.userage = userage; } public Integer getUserid() { return userid; } public void setUserid(Integer userid) { this.userid = userid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getUserage() { return userage; } public void setUserage(Integer userage) { this.userage = userage; } @Override public String toString() { return "Users [userid=" + userid + ", username=" + username + ", userage=" + userage + "]"; } }

  知识补充(序列化:Serialize)

  功能 – 将内存中的java对象与字节数组做双向转换。

  作用 – 只要涉及到IO操作的时候,IO中可以传递的数据只有字节,java对象是不能通过IO传递的。所以,需要使用IO传递java对象的时候,必须涉及到序列化和反序列化

  序列化ID – 是用于区分字节信息和java类型直接关系的一个基础数据。如果设计上,不怕麻烦,建议给不同的类型,定义尽可能不同的序列化ID,可以提升序列化和反序列化的效率。但是,对效率的提升不是很明显。

  序列化ID,只有一个要求,就是一样的类型的对象,必须使用相同值的序列化ID

  一般开发的时候,序列化ID都设置为-1/1。

原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/tech/database/3804.html

(0)
上一篇 2021年7月16日 18:28
下一篇 2021年7月16日 18:28

相关推荐

发表回复

登录后才能评论