Redis-03Redis数据结构--字符串String

版权声明:【show me the code ,change the world】 https://blog.csdn.net/yangshangwei/article/details/82251931

概述

字符串是 Redis 最基本的数据结构 ,它将以一个键和一个值存储于 Redis 内部,很像Java 的 Map 结构 ,让 Redis 通过键去找到值。

Redis 会通过 key 去找到对应的字符串 ,比如通过 keyl 找到 valuel。假设产品的编号为 0001 , 只要设置 key 为 product_0001 , 就可以通过 product_0001去保存该产品到 Redis 中,也可以通过 product_0001 从 redis 中找到产品信息。


字符串的一些基本命令

官网 : https://redis.io/commands#string

中文网站: http://www.redis.cn/commands.html#string

这里仅仅列出常用的一些,其他详见上述官网

命令 说明 备注
set key value 设置键值对 最常用的写入命令
get key 通过键获取值 最常用的读取命
del key 通过 key ,删除键值对 删除命令,返刨删除数,注意,它是一个通用的命令,换句话说在其他数据纺构中,也可以使用它
strlen key 求 key 指向字符串的氏度 返回长度
getset key value 修改原来 key 的对应值,并将旧值返回 如果原来值为空,则返回为空,并设置新值
getrange key start end 获取子串 记字符串的长度为 len,把字符串看作一个数组,而Redis 是以 0 开始计数的,所以 s tart 和l end 的取值范为 0 到 len-1
append key value 将新的字符串value加入到原来 key指向的字符串末 返回 key 指向新字符净的长度

客户端操作

我这里的redis server设置了密码,密码为artisan ,所以有

 auth artisan

[redis@artisan bin]$ pwd
/home/redis/redis/redis-4.0.11/bin
[redis@artisan bin]$ ./redis-cli 
127.0.0.1:6379> auth artisan
OK
127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> set key2 value2
OK
127.0.0.1:6379> get key1
"value1"
127.0.0.1:6379> del key1
(integer) 1
127.0.0.1:6379> strlen key2
(integer) 6
127.0.0.1:6379> getset key2 new_value2
"value2"
127.0.0.1:6379> get key2
"new_value2"
127.0.0.1:6379> getrange key2 0 3 
"new_"
127.0.0.1:6379> append key2 _app
(integer) 14
127.0.0.1:6379> get key2
"new_value2_app"
127.0.0.1:6379>

Spring中操作redis的字符串

spring-redis-string.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:p="http://www.springframework.org/schema/p"
	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">

    <context:property-placeholder location="classpath:redis/redis.properties" />

    <!--2,注意新版本2.3以后,JedisPoolConfig的property name,不是maxActive而是maxTotal,而且没有maxWait属性,建议看一下Jedis源码或百度。 -->
    <!-- redis连接池配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!--最大空闲数 -->
        <property name="maxIdle" value="${redis.maxIdle}" />
        <!--连接池的最大数据库连接数 -->
        <property name="maxTotal" value="${redis.maxTotal}" />
        <!--最大建立连接等待时间 -->
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟) -->
        <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />
        <!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 -->
        <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />
        <!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 -->
        <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />
   		<property name="testOnBorrow" value="true"></property>
		<property name="testOnReturn" value="true"></property>
		<property name="testWhileIdle" value="true"></property>
    </bean>
	
	<!--redis连接工厂 -->
    <bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
        destroy-method="destroy">
        <property name="poolConfig" ref="jedisPoolConfig"></property>
        <!--IP地址 -->
        <property name="hostName" value="${redis.host.ip}"></property>
        <!--端口号 -->
        <property name="port" value="${redis.port}"></property>
        <!--如果Redis设置有密码 -->
        <property name="password" value="${redis.password}" /> 
        <!--客户端超时时间单位是毫秒 -->
        <property name="timeout" value="${redis.timeout}"></property>
        <property name="usePool" value="true" />
        <!--<property name="database" value="0" /> -->
    </bean>
	
	<!-- 键值序列化器设置为String 类型 -->
	<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>

	<!-- redis template definition -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		p:connection-factory-ref="jedisConnectionFactory"
		p:keySerializer-ref="stringRedisSerializer"
		p:valueSerializer-ref="stringRedisSerializer">
	</bean>

</beans>





SpringRedisStringsDemo

package com.artisan.redis.baseStructure.strings;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;

public class SpringRedisStringsDemo {

	public static void main(String[] args) {
		
		ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring/spring-redis-string.xml");
		
		// 在 Spring 中,
		// redisTemplate.opsForValue()所返回的对象可以操作简单的键值对,可以是字符串,也可以是对象,具体依据你所配置的序列化方案
		// 这里在spring-redis-string.xml中key和value都是指定的 stringRedisSerializer
		RedisTemplate<String,String> redisTemplate = (RedisTemplate<String, String>) ctx.getBean("redisTemplate");

		// 设置值
		//127.0.0.1:6379> set key1 value1
		//OK
		//127.0.0.1:6379> set key2 value2
		//OK
		redisTemplate.opsForValue().set("key1", "value1");
		redisTemplate.opsForValue().set("key2", "value2");
		
		// 通过 key 获取值
		//127.0.0.1:6379> get key1
		//"value1"
		String key1 = redisTemplate.opsForValue().get("key1");
		System.out.println("key1:" + key1);
		
		// 通过 key 删除值
		//127.0.0.1:6379> del key1
		//(integer) 1
		Boolean success = redisTemplate.delete("key1");
		System.out.println("删除key1是否成功:" + success);
		
		
		// 求长度
		//127.0.0.1:6379> strlen key2
		//(integer) 6
		Long size = redisTemplate.opsForValue().size("key2");
		System.out.println("key2长度:" + size);
		
		// 设值新值并返回旧值
		//127.0.0.1:6379> getset key2 new_value2
		//"value2"
		String oldValue = redisTemplate.opsForValue().getAndSet("key2", "new_value2");
		System.out.println("key2旧值:" + oldValue);

		
		// 127.0.0.1:6379> get key2
		// "new_value2"
		String newValue = redisTemplate.opsForValue().get("key2");
		System.out.println("key2新值:" + newValue);

		// 获取子串
		// 127.0.0.1:6379> getrange key2 0 3
		// "new_"
		String subString = redisTemplate.opsForValue().get("key2", 0, 3);
		System.out.println("subString:" + subString);

		// 将新的字符串value加入到原来 key指向的字符串末
		// 127.0.0.1:6379> append key2 _app
		// (integer) 14
		Integer value = redisTemplate.opsForValue().append("key2", "_app");
		System.out.println("value:" + value);

		// 127.0.0.1:6379> get key2
		// "new_value2_app"
		String newValue2 = redisTemplate.opsForValue().get("key2");
		System.out.println("key2:" + newValue2);
	}
}

首先在客户端中flushdb,确保数据干净。

输出
在这里插入图片描述

redis中的数据

在这里插入图片描述


Redis中对整数和浮点型数字的支持

上面介绍了字符串最常用的命令 , 但是 Redis 除了这些之外还提供了对整数和浮点型数字的功能,如果字符串是数字(整数或者浮点数〉,那么 Redis 还能支持简单的运算。但是它的运算能力比较弱 , 目前版本只能支持简单的加减法运算。

命令 说明 备注
incr key 在原字段上加 1 只能对整数操作
incrby key increment 在原字段上加上整数( increment ) 只能对整数操作
deer key 在原字段上减 1 只能对整数操作
decrby key decrement 在原字段上减去整数( decrement ) 只能对整数操作
incrbyfloat keyincrement 在原字段上加上浮点数( increment) 可以操作浮点数或者整

客户端操作

[redis@artisan bin]$ ./redis-cli 
127.0.0.1:6379> auth artisan
OK
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set number 8
OK
127.0.0.1:6379> GET number
"8"
127.0.0.1:6379> INCR number
(integer) 9
127.0.0.1:6379> INCRBY number 5
(integer) 14
127.0.0.1:6379> DECR number
(integer) 13
127.0.0.1:6379> DECRBY number 10
(integer) 3
127.0.0.1:6379> INCRBYFLOAT number 8.88
"11.88"
127.0.0.1:6379> get number
"11.88"
127.0.0.1:6379> 


如果开始把val 设置为浮点数,那么 incr、 deer、 incrby 、 deerby 的命令都会失败。 Redis 并不支持减法 、 乘法、除法操作,功能十分有限,需要注意。


Spring中操作redis的字符串的加减运算


package com.artisan.redis.baseStructure.strings;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;

public class SpringRedisStringAdd_Subtraction {

	public static void main(String[] args) {

		ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring/spring-redis-string.xml");

		RedisTemplate redisTemplate = (RedisTemplate) ctx.getBean("redisTemplate");

		// 127.0.0.1:6379> set number 8
		// OK
		redisTemplate.opsForValue().set("number", String.valueOf(8));

		// 127.0.0.1:6379> GET number
		// "8"
		System.out.println(redisTemplate.opsForValue().get("number"));

		// 127.0.0.1:6379> INCR number
		// (integer) 9
		System.out.println(redisTemplate.opsForValue().increment("number", 1));

		// 127.0.0.1:6379> INCRBY number 5
		// (integer) 14
		System.out.println(redisTemplate.opsForValue().increment("number", 5));

		// 127.0.0.1:6379> DECR number
		// (integer) 13
		Long number = redisTemplate.getConnectionFactory().getConnection().decr(redisTemplate.getKeySerializer().serialize("number"));
		System.out.println(number);
		// 127.0.0.1:6379> DECRBY number 10
		// (integer) 3
		Long number2 = redisTemplate.getConnectionFactory().getConnection().decrBy(redisTemplate.getKeySerializer().serialize("number"), 10);
		System.out.println(number2);

		// 127.0.0.1:6379> INCRBYFLOAT number 8.88
		// "11.88"
		System.out.println(redisTemplate.opsForValue().increment("number", 8.88));
		// 127.0.0.1:6379> get number
		// "11.88"
		System.out.println(redisTemplate.opsForValue().get("number"));

	}

}

在配置文件中使用的是字符串序列化器,所以 Redis 保存的还是字符串 ,如果采用其他的序列化器,比如 JDK 序列化器,那么 Redis 保存的将不会是数字而是产生异常。

Spring 己经优化了代码,所increment 方法可 以支持long和double的加法,如下
在这里插入图片描述

对于减法, RedisTemplate 并没有进行支持。 所以用下面的代码去代替它

redisTemplate . getConnectionFactory() .getConnection() . decrBy(redisTemplate.getKeySerializer() . serialize ("number") , 10) ;

通过获得连接工厂再获得连接从而得到底层的 Redis 连接对象。为了和 RedisTemplate的配置保持一致 ,所以先获取了其 keySerializer 属性 ,对键进行了序列化,如果获取结果也可以进行同样的转换。

当然 getConnection()只是获取一个 spring data redis 项目中封装的底层对象 RedisConnection , 甚至可以获取原始的链接对象Jedis 对象。

Jedis jedis =(Jedis)redisTemplate.getConnectionFactory() .getConnection() .getNativeConnection() ;

关于减法的方法,原有值都必须是整数,否则就会引发异常.

// 如果进行减法运算原有值都必须是整数,否则就会引发异常,比如下面的,编译通过,但运行会抛出异常
redisTemplate.opsForValue().set("number", "1.1");
redisTemplate.getConnectionFactory().getConnection().decr(redisTemplate.getKeySerializer().serialize("number"));
Exception in thread "main" org.springframework.dao.InvalidDataAccessApiUsageException: ERR value is not an integer or out of range; nested exception is redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range
	at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:64)
	at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:41)
	at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
	at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
	at org.springframework.data.redis.connection.jedis.JedisConnection.convertJedisAccessException(JedisConnection.java:181)
	at org.springframework.data.redis.connection.jedis.JedisStringCommands.convertJedisAccessException(JedisStringCommands.java:757)
	at org.springframework.data.redis.connection.jedis.JedisStringCommands.decr(JedisStringCommands.java:469)
	at org.springframework.data.redis.connection.DefaultedRedisConnection.decr(DefaultedRedisConnection.java:301)
	at com.artisan.redis.baseStructure.strings.SpringRedisStringAdd_Subtraction.main(SpringRedisStringAdd_Subtraction.java:49)
Caused by: redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range
	at redis.clients.jedis.Protocol.processError(Protocol.java:127)
	at redis.clients.jedis.Protocol.process(Protocol.java:161)
	at redis.clients.jedis.Protocol.read(Protocol.java:215)
	at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:340)
	at redis.clients.jedis.Connection.getIntegerReply(Connection.java:265)
	at redis.clients.jedis.BinaryJedis.decr(BinaryJedis.java:708)
	at org.springframework.data.redis.connection.jedis.JedisStringCommands.decr(JedisStringCommands.java:467)
	... 2 more



注意

使用 Spring 提供的 RedisTemplate 去展示多个命令可以学习到如何使用 RedisTemplate 操作 Redis 。 实际工作中并不是那么用的,因为每一 个操作会尝试从连接池里获取 一 个新的 Redis 连接,多个命令应该使用SessionCallback 接口进行操作 。


代码

代码托管到了 https://github.com/yangshangwei/redis_learn

猜你喜欢

转载自blog.csdn.net/yangshangwei/article/details/82251931