redis学习1
一、概念复习
关系型数据库和非关系型数据库的区别
关系型数据库:数据之间有关联关系,数据存储在硬盘上,以表的形式存储数据。
非关系型数据库:redis,数据之间没有关联关系,以键值对的形式存储,存储在内存中。
与数据库交互比较耗时,查询一些不经常发生变化的数据时可以把其缓存在redis中,加快访问速度。
redis支持存储的值数据类型:
字符串,list,map,set,有序set
redis持久化方式:
RDB方式,在一定的间隔时间中检测key的变化,然后持久化数据。
jedis客户端操作redis
二、用jedis操作redis
public class Test1 {
public static void main(String[] args) {
//获取连接
//Jedis jedis=new Jedis("localhost",6379);
Jedis jedis = getJedisClien();//使用jedis连接池来获取jedis
//设置字符串值
jedis.set("username","zhangsan");
//带过期时间设置值
jedis.setex("password",10,"123");
//获取字符串
System.out.println(jedis.get("username"));
//存储hash
jedis.hset("student","name","zhangsan");
jedis.hset("student","age","18");
//获取map中的某个值
System.out.println(jedis.hget("student","age"));
//获取整个map
Map<String, String> map = jedis.hgetAll("student");
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
//存储列表
// jedis.lpush("list","a");
// jedis.lpush("list","b");
// jedis.rpush("list","c");
//list范围获取
List<String> list = jedis.lrange("list", 0, -1);
System.out.println(list);
//list弹出
String ele = jedis.lpop("list");
System.out.println(ele);
String ele2 = jedis.rpop("list");
System.out.println(ele2);
//set集合类型数据
jedis.sadd("myset","java","php","c_sharp");
jedis.srem("myset","java");//移除set集合中的某个元素
Set<String> myset = jedis.smembers("myset");//获取set集合的全部元素
System.out.println(myset);
//有序set存储,根据给定的分数排序,分数越大越靠后
jedis.zadd("mysortSet",1,"a");
jedis.zadd("mysortSet",10,"c");
jedis.zadd("mysortSet",100,"b");
System.out.println(jedis.zrange("mysortSet",0,-1));
//指定某个key的过期时间
jedis.expire("student",15);
jedis.close();//使用连接池获取到的连接,调用close方法就是把连接归还连接池
}
/**
* 用jedis连接池来获取jedis对象
* @return
*/
public static Jedis getJedisClien(){
JedisPoolConfig config=new JedisPoolConfig();
config.setMaxTotal(10);
config.setMaxIdle(10);
JedisPool pool=new JedisPool(config,"localhost",6379);
return pool.getResource();
}
}
三、springboot整合redis
spring提供了一个RedisTemplate对象可以用来操作redis,在springboot中当然也可以使用redisTemplate
3.1 整合步骤
引入redis的起步依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
在配置文件中对redis和jedis的连接信息进行配置
spring:
redis:
host: localhost
port: 6379
jedis:
pool:
max-idle: 10
max-active: 8
max-wait: -1
min-idle: 0
在需要操作redis的地方注入redisTemplate的对象,就可以使用
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RedisStudyApplication.class)
public class Test1 {
@Autowired
private RedisTemplate redisTemplate;//这个对象的泛型是<Object,Object>
@Test
public void test1(){
//存储和获取字符串
redisTemplate.boundValueOps("username").set("zhangsan");
//使用泛型是<Object,Object>的模板对象,get方法返回的是Object
Object value = redisTemplate.boundValueOps("username").get();
System.out.println(value);
//存储和获取map
redisTemplate.boundHashOps("demoMap").put("key1","value1");
Object value2 = redisTemplate.boundHashOps("demoMap").get("key1");
System.out.println(value2);
}
}
3.2 自动注入的redistemplate对象详解
springboot提供了redis的自动配置类来创建redisTemplate对象,配置类如下:
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
可以看到其中提供了两个redisTemplate对象,一个泛型是RedisTemplate<Object, Object>,另一个的泛型是<String,String>。
使用这种方式注入的是泛型是<Object, Object>的redisTemplate对象
@Autowired
private RedisTemplate redisTemplate;
所以使用这个redisTemplate操作redis存储的key和value都是object类型的。
3.3 使用StringRedisTemplate
/**
* 测试 StringRedisTemplate来操作redis,序列化器使用的是 StringRedisSerializer
*/
@Test
public void test2(){
//1.存储和获取字符串
stringRedisTemplate.boundValueOps("accountName").set("lyy");
//使用指定泛型的模板对象来操作redis,get方法返回的对象就是指定的泛型类型的
String value = stringRedisTemplate.boundValueOps("accountName").get();
System.out.println(value);
//2.redis中存取hash类型的数据
stringRedisTemplate.boundHashOps("stringMap").put("key1","value1");
//通过redistemplate来获取hash类型的数据
Object value2 = stringRedisTemplate.boundHashOps("stringMap").get("key1");
System.out.println(value2);
}
3.4序列化器
将一个对象存储到redis中,需要把一个对象序列化即保存这个对象的状态,再把序列化的结果保存到redis中。
同样的,从redis中把一个对象读取到内存中需要反序列化这个对象。
spring提供了几个序列化器
Jackson2JsonRedisSerializer
JdkSerializationRedisSerializer
OxmSerializer
StringRedisSerializer
GenericToStringRedisSerializer
GenericJackson2JsonRedisSerializer
当我们自动注入泛型是<Object,Object>的redisTemplate对象时,默认使用的是jdk自己的序列化器,所以序列化后存储到redis的结果会和实际的内容有出入,不管是key还是value都多了一些特殊内容。
当使用StringRedisTemplate时,序列化使用的是StringRedisSerializer这个序列化器,部分源码如下
public class StringRedisTemplate extends RedisTemplate<String, String> {
/**
* Constructs a new <code>StringRedisTemplate</code> instance. {@link #setConnectionFactory(RedisConnectionFactory)}
* and {@link #afterPropertiesSet()} still need to be called.
*/
public StringRedisTemplate() {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
setKeySerializer(stringSerializer);
setValueSerializer(stringSerializer);
setHashKeySerializer(stringSerializer);
setHashValueSerializer(stringSerializer);
}
使用这个序列化器把字符串序列化后再存储到redis中,序列化的结果和实际的内容是一样的
3.5 自定义redisTemplate的泛型和序列化器
springboot自定配置的redisTemplate不满足使用要求时,可以自己在配置类中配置一个redisTemplate对象。
/**
* 自定义的redisTemplate对象
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> objectRedisTemplate(
RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
//设置template的序列化器
template.setKeySerializer(new StringRedisSerializer());//设置key的序列化器
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
//配置序列化器的属性
ObjectMapper mapper=new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//配置这个属性后从redis中再拿取到的就还是原来的对象,不配置这个属性存进去的是对象,获取到的会是一个map
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);//设置value的序列化器
template.setHashKeySerializer(serializer);
template.setHashValueSerializer(serializer);
template.setConnectionFactory(redisConnectionFactory);
return template;
}
使用自定义的redisTemplate
/**
* 使用自定义的redisTemplate,key的序列化器使用StringRedisSerializer,value的序列化器使用Jackson2JsonRedisSerializer
*/
@Test
public void test3(){
//1.存储和获取字符串
myRedisTemplate.boundValueOps("demo3").set("demo3-value");
Object demo3Value = myRedisTemplate.boundValueOps("demo3").get();
System.out.println(demo3Value);
//2.将一个map对象序列化成字符串然后存入redis中 redis中存储key-string类型
Map<String,String> map=new HashMap<>();
map.put("key1","value1");
map.put("key2","value2");
myRedisTemplate.boundValueOps("mapString").set(map);
Object map1 = myRedisTemplate.boundValueOps("mapString").get();
System.out.println(map1);
//2.把一个自定义对象序列化成字符串存入redis reids中存储 key-string类型
Student stu=new Student("1","zhangsan",18);
myRedisTemplate.boundValueOps("student").set(stu);
Object student = myRedisTemplate.boundValueOps("student").get();
System.out.println(student);
//3.给redis中存入hash类型的数据,hash中存储的是student对象(序列化成字符串),redis中存储的是key-hash类型
Student st1=new Student("2","st1",19);
Student st2=new Student("3","st2",19);
myRedisTemplate.boundHashOps("studentMap").put("st1",st1);
myRedisTemplate.boundHashOps("studentMap").put("st2",st2);
Object obj = myRedisTemplate.boundHashOps("studentMap").get("st1");
System.out.println(obj);
}
注意:
在配置value的序列化器时使用了
//配置序列化器的属性
ObjectMapper mapper=new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//配置这个属性后从redis中再拿取到的就还是原来的对象,不配置这个属性存进去的是对象,获取到的会是一个map
serializer.setObjectMapper(mapper);
是因为配置了这个后对象序列化成字符并存储到redis时字符串中会包含它的来源对象的信息,这样反序列时就可以重新反序列化成原来的对象。
此序列化器序列化对象的字符串的信息如下:
"[\"com.lyy.entity.Student\",{\"id\":\"1\",\"userName\":\"zhangsan\",\"age\":18}]"
这个字符串中包含了原始类Student的全类名,所以反序列化时就可以根据这个把其还原成原来的对象。
四、总结
redis中可以存储五种数据类型:String,List,hash,set,sortSet
springboot操作redis使用的核心对象是redisTemplate
springboot的redis自动配置类配置了两个redisTemplate<Object,Object>,和StringRedisTemplate<String,String>
存储一个对象到redis中需要把对象序列化,spring提供了多个序列化器。
可以自己配置指定泛型的redisTemplate,并指定序列化器。