Redis

作者: 番薯IT | 来源:发表于2017-10-30 14:17 被阅读82次

1. 设置密码

  • config set requirepass 123456

  • config get requirepass


2. 登陆

2.1 linux

  • 开启服务,使用 redis-conf 的配置 :
    ./redis-server ../redis-conf

  • 开启数据库,使用密码 123456 登陆
    ./redis-cli -h 127.0.0.1 -p 6379 -a 123456

2.2 windows

redis-cli -h 127.0.0.1 -p 6379 123456


3. spring-data-redis

3.1 spring 和 redis 整合

spring的强大,我们都知道。springspring-data-redis就是spring提供的和redis整合的包装jar。

3.1.1 maven

目前最新的版本是1.7.2

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.7.2.RELEASE</version>
</dependency>

3.1.2 配置RestTemplate

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxIdle" value="${redis.maxIdle}" />
    <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
    <property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>

<bean id="jedisConnectionFactory"
    class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="usePool" value="true" />
    <property name="hostName" value="${redis.hostName}" />
    <property name="port" value="${redis.port}" />
    <property name="password" value="${redis.password}" />
    <property name="database" value="1" />
    <property name="poolConfig" ref="jedisPoolConfig" />
</bean>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>

3.1.3 注入和使用RestTemplate

public class Example {

    // inject the actual template
    @Autowired
    private RedisTemplate<String, String> template;

    // inject the template as ListOperations
    // can also inject as Value, Set, ZSet, and HashOperations
    @Resource(name="redisTemplate")
    private ListOperations<String, String> listOps;

    public void addLink(String userId, URL url) {
        listOps.leftPush(userId, url.toExternalForm());
        // or use template directly
        redisTemplate.boundListOps(userId).leftPush(url.toExternalForm());
    }
}

3.2 数据类型

redis有五种数据结构,分别是:string,hash,list,set,zset。spring提供了这5种方式,下图是我从官方文档中截取的。提供了对应5中类型的包装类。这5个类都可以由RedisTemplate获取得到。

123.png

3.3 序列化

  • spring-data-redis对key和value都有做序列化。相关序列化的方法在相应jar的org.springframework.data.redis.serializer包下面。

  • spring-data-redis 提供了很多张序列化的方法。序列化方式需要在配置文件中配置,如果没有配置,那么就使用默认的配置方式。

3.3.1 序列化配置

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <!-- 默认 key 和 value 的序列化方式 -->
    <property name="defaultSerializer">
        <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
    </property>
    <!-- 非 hash 的 key 的序列化方式 -->
    <property name="keySerializer" >
        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    </property>
    <!-- 非 hash 的 value 的序列化方式 -->
    <property name="valueSerializer">
        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    </property>
    <!-- hash 的 key 的序列化方式 -->
    <property name="hashKeySerializer">
        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    </property>
    <!-- hash 的 value 的序列化方式 -->
    <property name="hashValueSerializer">
        <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    </property>
</bean>

如果redisTemplate中没有配置defaultSerializer,那么默认会使用JdkSerializationRedisSerializer,我们可以看下RedisTemplate中的afterPropertiesSet()方法下的部分源码:

if (defaultSerializer == null) {
defaultSerializer = new JdkSerializationRedisSerializer(
        classLoader != null ? classLoader : this.getClass().getClassLoader());
}

如果没有设置keySerializer和valueSerializer,那么默认的就是defaultSerializer。

3.3.2 序列化策略

StringRedisSerializer

序列化成String类型。当然这种方式是最高效的,redis设计就是这样的。但是这种策略是不能满足我们的。我们是有实体的,这种不好存储实体

JdkSerializationRedisSerializer

序列化成16进制字节序列。这种方式用的比较多吧,虽然是最消耗内存的,但是既然用缓存了,也就不在乎内存了吧!

OxmSerializer

序列化成xml。略过

Jackson2JsonRedisSerializer

序列化成json。这种方式比较笨重,每次都要指定对应的实体。执行效率比>较低。在后面我们会比较为什么执行效率低。

JacksonJsonRedisSerializer

此序列方式在spring-data-redis-1.7.2.RELEASE.jar中已经过时了。取而代之的是上面的方式。都是为了序列换成json的方式

3.3.3 序列化方式

  • 这里讨论实体的序列化,如果只是String或者是基本类型的话,也就不需要上面那么多种策略了。

  • redis是key-value的nosql的内存数据库。对于java的实体而言,存储起来就有点麻烦。当然redis的hash是可以存储实体的,但是我们必须指定各个字段所对应的key。保存时将对应的实体属性一个个的放入hash,获取时,又得一个个的封装到实体。我们当然希望有更简单的方式。

  • 那么我们能想到的当然是json,xml什么的。xml就算了,我现在用xml的地方不多。所以我直接忽略了(如果以后用到了,那在说吧)。

  • 由上策略可知,我们转化的方式就是JdkSerializationRedisSerializer和Jackson2JsonRedisSerializer(xml方式不讨论)。以下就简称为json方式和jdk方式。

3.3.3.1 前期定义

(1). 定义一个实体 StringDemo。自己添加getter和setter以及toString方法。实现Serializer方法,才能序列化。

public class StringDemo implements Serializable{
    private static final long serialVersionUID = -6209797447467016710L;
    private String id;
    private String name;
    private int age;
    private Date birth;
}

(2). 定义实现方式

@Service
public class RedisStringServiceImpl implements RedisStringService {
    
    @Resource
    private RedisTemplate<String, StringDemo> redisTemplate;
    
    private ValueOperations<String, StringDemo> valueOperation;
    
    @Resource(name = "redisTemplate")
    private ValueOperations<String, String> valueOps;
    
    @PostConstruct
    public void init(){
        valueOperation = redisTemplate.opsForValue();
    }
    
    /**
     * JDK序列化方式序列对象
     * applicationContent.xml中valueSeriazer 需要配置成 JdkSerializationRedisSerializer
     */
    @Override
    public void object2JDKSerializer(StringDemo demo){
        valueOperation.set("jdk2Object", demo);
    }
    
    /**
     * 从 REDIS 中获取对象
     * @return
     */
    @Override
    public StringDemo jdkSerializer2Object(){
        return valueOperation.get("jdk2Object");
    }
    
    
    /**
     * jackson的方式要指定 class。所以在配置总不好配置,所以就在程序中手动配置。
     * <p>
     * json的处理方式jackson是一种,还有的直接将实体转换成json,但是泛型的方式也要做相应的修改 <br>
     * 至于使用哪一种来序列化。就随便了。fastjson、gson等等
     */
    @Override
    public void Object2JacksonSerializer(StringDemo demo){
        Jackson2JsonRedisSerializer<StringDemo> jackson = new Jackson2JsonRedisSerializer<StringDemo>(StringDemo.class);
        redisTemplate.setValueSerializer(jackson);
        valueOperation.set("jackson2Object", demo);
    }
    
    @Override
    public StringDemo jacksonSerializer2Object(){
        Jackson2JsonRedisSerializer<StringDemo> jackson = new Jackson2JsonRedisSerializer<StringDemo>(StringDemo.class);
        redisTemplate.setValueSerializer(jackson);
        return valueOperation.get("jackson2Object");
    }
    
    /**
     * 使用fastjson的方式序列化
     * applicationContent.xml中valueSeriazer 需要配置成 StringRedisSerializer
     */
    @Override
    public void object2Fastjson(StringDemo demo){
        String demoStr = JSON.toJSONString(demo);
        valueOps.set("fastjson2Object", demoStr);
    }
    
    @Override
    public StringDemo fastjson2Object(){
        String demoStr = valueOps.get("fastjson2Object");
        return JSON.parseObject(demoStr, StringDemo.class);
    }
}

(3). 测试类

public class RedisStringServiceTest {
    private ApplicationContext ctx;
    private RedisStringService redisStringService;
    private long start;
    private long end;

    @Before
    public void init() {
        ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        redisStringService = ctx.getBean(RedisStringServiceImpl.class);
        start = System.currentTimeMillis();
    } 
    
    @After
    public void after(){
        end = System.currentTimeMillis();
        System.out.println("cost time : " + (end - start) + "ms");
    }
    
    @Test
    public void testSerializer(){
        redisStringService.testSerializer();
    }
    
    @Test
    /**
     * \xAC\xED\x00\x05sr\x007com.roachfu.study.module.string.model.entity.StringDemo\xA9\xD2^\x1FX\x99\xDD\xFA\x02\x00\x04I\x00\x03ageL\x00\x05birtht\x00\x10Ljava/util/Date;L\x00\x02idt\x00\x12Ljava/lang/String;L\x00\x04nameq\x00~\x00\x02xp\x00\x00\x00\x19sr\x00\x0Ejava.util.Datehj\x81\x01KYt\x19\x03\x00\x00xpw\x08\x00\x00\x01W\x03\xBF\xD8\xB5xt\x00\x0510000t\x00\x05roach
     * <p>
     * 由上得出,以16进制保存的方式将实体的信息都保存了。可见占用的内存比较大。如果实体改变了包名,那么将不能反序列化
     * 结果耗时是:35ms左右
     */
    public void object2JDKSerializerTest(){
        StringDemo demo = new StringDemo();
        demo.setId("10000");
        demo.setAge(25);
        demo.setName("roach");
        demo.setBirth(new Date());
        
        redisStringService.object2JDKSerializer(demo);
    }
    
    /**
     * 平均耗时75ms左右
     */
    @Test
    public void jdkSerializer2ObjectTest(){
        StringDemo demo = redisStringService.jdkSerializer2Object();
        System.out.println(demo);
    }
    
    /**
     * 平均180ms左右
     */
    @Test
    public void Object2JacksonSerializerTest(){
        StringDemo demo = new StringDemo();
        demo.setId("10000");
        demo.setAge(25);
        demo.setName("roach");
        demo.setBirth(new Date());
        
        redisStringService.Object2JacksonSerializer(demo);
    }
    
    /**
     * 平均190ms左右
     * <br>
     * 在 REDIS 中查看可得知,日期已经转换为时间戳
     */
    @Test
    public void jacksonSerializer2Object(){
        StringDemo demo = redisStringService.jacksonSerializer2Object();
        System.out.println(demo);
    }
    
    /**
     * 85ms左右
     * <br>
     * 在 REDIS 中查看可得知,日期已经转换为时间戳
     */
    @Test
    public void object2FastjsonTest(){
        StringDemo demo = new StringDemo();
        demo.setId("10000");
        demo.setAge(25);
        demo.setName("roach");
        demo.setBirth(new Date());
        redisStringService.object2Fastjson(demo);
    }
    
    /**
     * 85ms左右
     */
    @Test
    public void fastjson2Object(){
        StringDemo demo = redisStringService.fastjson2Object();
        System.out.println(demo);
    }
}

3.3.3.2 JDK方式序列化实体

  • 需要在相应的配置文件当中(例如在applicationContent.xml)配置valueSeriazer为JdkSerializationRedisSerializer。

  • 需要定义对应的实体泛型。

  • 这种序列化方式,是将value序列化成16进制的字节序列。比如一个实体StringDemo,序列化完之后的值为:

\xAC\xED\x00\x05sr\x007com.roachfu.study.module.string.model.entity.StringDemo\xA9\xD2^\x1FX\x99\xDD\xFA\x02\x00\x04I\x00\x03ageL\x00\x05birtht\x00\x10Ljava/util/Date;L\x00\x02idt\x00\x12Ljava/lang/String;L\x00\x04nameq\x00~\x00\x02xp\x00\x00\x00\x19sr\x00\x0Ejava.util.Datehj\x81\x01KYt\x19\x03\x00\x00xpw\x08\x00\x00\x01W\x03\xBF\xD8\xB5xt\x00\x0510000t\x00\x05roach
  • 由上得出,以16进制保存的方式将实体的信息都保存了。可见占用的内存比较大。如果实体改变了包名,那么将不能反序列化。但是这种方式执行的效率比较高,速度比较快。

3.3.3.3 JSON方式序列化实体

将value序列化成JSON的方式又分两种:

(1) jackson序列化方式

  • 这是spring-data-redis自带方式,即Jackson2JsonRedisSerializer的实现方式。

  • 因为jackson的方式必须指定实体,所以在配置文件中配置会比较繁杂。所以一般都在方法总进行配置。比如

public void Object2JacksonSerializer(StringDemo demo){
    Jackson2JsonRedisSerializer<StringDemo> jackson = new Jackson2JsonRedisSerializer<StringDemo>(StringDemo.class);
    redisTemplate.setValueSerializer(jackson);
    valueOperation.set("jackson2Object", demo);
}
  • 如上可知,我们指定序列化StringDemo实体为json数据,在方法中定义了redisTemplate的valueSerializer,然后再存储数据。相比jdk的方式,代码上缺失了优雅性,需要同时设置redisTemplate和valueOperation。执行的速度也比jdk方式慢的多。

(2) 直接将实体序列化成json的方式

  • 这里使用fastjson进行javabean和json之间的转换,也可以使用其它的方式(gson,json-lib都是可以的)。

  • 这种方式是直接将javabean转换成json,返回的类型是String。valueSerializer需要设置成StringRedisSerializer。获取数据时,在通过fastjson将String转换成实体。

public void object2Fastjson(StringDemo demo){
    String demoStr = JSON.toJSONString(demo);
    valueOps.set("fastjson2Object", demoStr);
}
  • 如上所示:这种方式的代码优雅度比jackson方式高。经过测试,这种方式的执行效率比jackson高,比jdk方式低。

3.3.3.4 总结

通过下面方法的验证,得出下面的结论:

(1) jdk方式执行的速度是最快的,但是由于存储的16进制字节序列,所占用的内存就比其他方式占用的多。

(2) jackson 这种序列化的方式最麻烦,代码的优雅度也相对较低,最惨的是执行的速度是最慢的。

(3) 直接转json方式(此处使用fastjson,其他的方式也是可以的。gson什么的)。写入的时候将javabean转成json,获取的时候又反序列成实体。这种方式比jdk方式慢点,比jackson方式快。

(4) jackson方式完败了(当然我的测试相对片面的),写出来的代码的可读性优雅度也没有其他两种好。

(5) 如果是公司的服务的内存强大,那就使用jdkSerializer这种方式。毕竟快。如果内存有限,那还是手动转json吧!

相关文章

网友评论

      本文标题:Redis

      本文链接:https://www.haomeiwen.com/subject/uoxdgttx.html