Redis learn three (advanced features).

A sort

redis support sort list, set and zset elements, ordered time complexity is O (N + M * log (M)). (N is the set size, M being the number of elements returned)

sort key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]
  • [BY pattern]: sort order sort default collection element, by "BY pattern" key using external data ordering as a weight.
  • [LIMIT offset count]: Returns the number after the sorting element may be limited by LIMIT modifiers, modifier accepted offset (the number of elements to be skipped, i.e., the starting position) and a count (number of elements) return two parameters.
  • [GET pattern [GET pattern ...]]: get ordering may be taken based on the result of the corresponding key, "get #" represents a return to the element itself, "get pattern" can return the data to the external key.
  • [ASC | DESC] [ALPHA]: select the order, or reverse ordered string, SET collection (itself without an index value) must be specified sorting operations ALPHA.
  • [STORE destination]: By default, sort sorting operation simply returns a result, the save operation does not perform any. By giving store option to specify a key parameter, to sort the results can be saved on a given key.

Suppose now that the user data is as follows:

127.0.0.1:6379> sadd uid 1 2 3 4
127.0.0.1:6379> mset user_name_1 admin user_level_1 9999
127.0.0.1:6379> mset user_name_2 jack user_level_2 10
127.0.0.1:6379> mset user_name_3 peter user_level_3 25
127.0.0.1:6379> mset user_name_4 mary user_level_4 70

First, the direct use of the elements in the set to do a sort operation:

127.0.0.1:6379> sort uid
1) "1"
2) "2"
3) "3"
4) "4"

Then, we try [BY pattern] and [GET pattern [GET pattern ...]] operations:

127.0.0.1:6379> sort uid by user_name_* get # get user_name_* get user_level_* alpha
 1) "1"
 2) "admin"
 3) "9999"
 4) "2"
 5) "jack"
 6) "10"
 7) "4"
 8) "mary"
 9) "70"
10) "3"
11) "peter"
12) "25"

This statement is a bit obscure, so try to understand "by user_name_ *", user_name_ * is occupied by a symbol, it first takes a value in the uid, then use this value spliced ​​into foreign keys, and really it is these sort of external keys value; "get # get user_name_ * get user_level_ *" meaning also can be understood, get # represents a return to their elements, [get pattern] represents a return to an external key.

Second, the transaction

redis transaction mechanism is mainly done by following a few instructions:

  • multi: mark the start of a block transaction
  • exec: execute all commands in the transaction block
  • discard: cancel the transaction, all transaction block of instruction execution to give up
  • watch key [key ...]: monitoring one or more key, if this (or these key) are other command changes before the transaction execution, the change is also known as CAS error, the transaction will be interrupted
  • unwatch: Cancellation watch command to monitor all the key

When multi redis received instruction, the connection will enter a transaction context, the connection is not performed immediately subsequent commands, but rather into a first queue; exec command after subjected to the connector, the execution queue in the sequence will redis All command. And package the operating results of all commands together to return to the client. Then the connection ended transaction context.

Is there redis will watch command is divided into ordinary type of transaction and CAS (Check And Set) transaction types, no watch command is common transaction type, transaction type CAS has to watch command.

Reasons for the failure of the transaction can be divided into static error (such as the command does not exist) and false (such as CAS error, with lpop for string operations, etc.) is running. Static error when submitting the exec will return an error message, so that the transaction can not be executed; and in addition to running outside the CAS when the error does not prevent the transaction to proceed. Thus, Redis transaction mechanisms are not atomic.

127.0.0.1:6379> multi
OK
127.0.0.1:6379> lpush list java
QUEUED
127.0.0.1:6379> scard list
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> lrange list 0 -1
1) "java"

We can see that even a command error, the transaction still has not been rolled back. Therefore, redis transaction mechanism is too primitive, is not recommended.

Note that, if we use the AOF persistent way, there may be cases transactions are written part (redis hang during the transaction, etc.) leading to exit redis failed to start, you can use redis-check-aof repair tool .

Third, the pipeline (pipeline)

Redis provided in the transaction queue, you can batch tasks, so performance is relatively high, but the use of multi ... exec command transaction is overhead, because it will detect and lock corresponding sequence of commands. Sometimes we want to execute a series of commands using the batch queue without any additional conditions, then you can use redis pipeline (pipeline) technology.

See how the pipeline functions in spring-data-redis, note that the sequence of RedisTemplate need to use StringRedisSerializer, can not be used JdkSerializationRedisSerializer, otherwise it will lead to serialization failure.

    @Test
    public void pipeline() {
        // 1.executePipelined 重写 入参 RedisCallback 的doInRedis方法
        List<Object> resultList = redisTemplate.executePipelined(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection redisConnection) throws DataAccessException {
                // 2.redisConnection 给本次管道内添加 要一次性执行的多条命令
                // 2.1 一个set操作
                redisConnection.set("hello".getBytes(), "world".getBytes());
                // 2.2一个批量mset操作
                Map<byte[], byte[]> tuple = new HashMap();
                tuple.put("m_hello_1".getBytes(), "m_world_1".getBytes());
                tuple.put("m_hello_2".getBytes(), "m_world_2".getBytes());
                tuple.put("m_hello_3".getBytes(), "m_world_3".getBytes());
                redisConnection.mSet(tuple);
                // 2.3一个get操作
                redisConnection.get("m_hello_1".getBytes());
                // 3 这里一定要返回null,最终pipeline的执行结果,才会返回给最外层
                return null;
            }
        });
        // 4. 最后对redis pipeline管道操作返回结果进行判断和业务补偿
        for (Object str : resultList) {
            System.out.println(str);
        }
    }

Fourth, publish and subscribe

Following RxJava, Reactor, CompletableFuture Spring and event-driven model, we have to one kind of contact with the Observer pattern it! redis as a pub / sub server, between the subscriber and the publisher has played a message routing function. Subscribers can subscribe to a channel they are interested in redis server through subscribe and psubscribe command; publisher sends a message to the channel redis server through the command publish, subscribe to the channel's entire client will receive this message. A client may subscribe to multiple channel, you can send messages to a plurality of channel.

Subscribe channel:

127.0.0.1:6379> subscribe channel
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel"
3) (integer) 1
1) "message"
2) "channel"
3) "Hello,World"

Published news channel:

127.0.0.1:6379> publish channel Hello,World
(integer) 1

Next we look at how to publish and subscribe functions in spring-data-redis in. First, we need a message listener, as long as it can achieve MessageListener interface:

public class ChannelListener implements MessageListener {

    @Override
    public void onMessage(Message message, byte[] pattern) {
        System.out.println("channel is:" + new String(message.getChannel()));
        System.out.println("channel content:" + new String(message.getBody()));
    }
}

So, how do below it? Of course, the news is bound listener and channel, so the message listener know which channel messaging:

    /**
     * redis 消息监听器容器, 绑定消息监听器和 channel
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        //订阅了一个叫 channel 的通道
        container.addMessageListener(channelAdapter(), new PatternTopic("channel"));
        //这个 container 可以添加多个 messageListener
        return container;
    }

    /**
     * 消息监听器适配器
     */
    @Bean
    public MessageListenerAdapter channelAdapter() {
        return new MessageListenerAdapter(new ChannelListener());
    }

Next, let's try to go in this channel publishing a news!

    @Test
    public void publish() {
        redisTemplate.convertAndSend("channel", "Hello,World");
    }

Guess you like

Origin www.cnblogs.com/jmcui/p/11707970.html