springboot17-Cache的使用和原理

Cache使用和Redis的使用:

一、准备工作:

新建一个springboot的project,然后配置好mybatisdruid的数据库、数据源。

二、准备初试Cache缓存的作用:

1、新建一个bean.User实体类:

public class User {
    private String username;
    private String passwd;
    private String phone;
    private String address;
    private String youbian;

    public User() {
    }

    public User(String username, String passwd, String phone, String address, String youbian) {
        this.username = username;
        this.passwd = passwd;
        this.phone = phone;
        this.address = address;
        this.youbian = youbian;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getYoubian() {
        return youbian;
    }

    public void setYoubian(String youbian) {
        this.youbian = youbian;
    }
}

2、新建一个UserService服务:

@Service
public class UserService {

    @Autowired
    UserMapper userMapper;

    /**
     * 将方法的运行结果进行缓存,以后再要相同的数据,直接从缓存中取出数据
     * 1、cacheNames/value  指定缓存的名字;
     * 2、key: 缓存数据使用的key;可以用它来指定,默认就是使用方法参数的值: 1-方法的返回值
     *       我们也可以使用SpEL: #username; 参数id的值 #a0 #po #root.args[0]
     * 3、keyGenerator: key的生成器: 我们也可以使用自己自定key的生成器的组件username
     * 4、key/keyGenerator 选一个使用
     * 5、cacheMange 缓存管理器:我们可以指定缓存管理器
     * 6、condition:指定符合条件的情况下才缓存;
     * 7、unless:当unless指定的条件为true,方法的返回值就不会被缓存;unless可以获取到结果进行判断:#result代表方法的返回值
     * 8、sync:是否使用异步模式
     *
     * @param username
     * @return
     */
    //我们可以用 #root.args[0] 也代表使用username
    @Cacheable(cacheNames = "user_emp",key = "#root.args[0]")
    public User getUserName(String username){
        System.out.println("查询 --"+username+"-- 用户");
        return userMapper.getUserUsername(username);
    }

    public int insertUser(User user){
        System.out.println("插入 --"+user.getUsername()+"-- 用户");
        return userMapper.insertUser(user);
    }
}

@Cacheable注解作用:将方法的运行结果进行缓存,以后再要相同的数据,直接从缓存中取出数据。
1、cacheNames/value 指定缓存的名字;
2、key: 缓存数据使用的key;可以用它来指定,默认就是使用方法参数的值: 1-方法的返回值
我们也可以使用SpEL: #username; 参数id的值 #a0 #po #root.args[0]
3、keyGenerator: key的生成器: 我们也可以使用自己自定key的生成器的组件username
4、key/keyGenerator 选一个使用
5、cacheMange 缓存管理器:我们可以指定缓存管理器
6、condition:指定符合条件的情况下才缓存;
7、unless:当unless指定的条件为true,方法的返回值就不会被缓存;unless可以获取到结果进行判断:#result代表方法的返回值
8、sync:是否使用异步模式。

3、新建一个Controller:

@RestController
public class UserController {

    @Autowired
    UserService userService;

    @GetMapping("/user/{username}")
    public User getUser(@PathVariable("username") String username){
        return userService.getUserName(username);
    }

    @GetMapping("/user")
    public User insertUser(User user){
        int insertUser_id = userService.insertUser(user);
        return user;
    }
}

4、运行:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WmDO0Ozo-1584289740357)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200315230940974.png)]

我们首次查询的时候:控制台会打印出sql语句。

在这里插入图片描述

但是我们第二次 第三次查询这个数据的时候,控制台不会再打印sql语句,这时我们已经把该数据放入到了缓存中,可以直接从缓存中获取数据。
在这里插入图片描述

三、Cache缓存的原理:

1、自动配置类:CacheAutoConfiguration

2、缓存的配置类:

static class CacheConfigurationImportSelector implements ImportSelector {

		@Override
		public String[] selectImports(AnnotationMetadata importingClassMetadata) {
			CacheType[] types = CacheType.values();
			String[] imports = new String[types.length];
			for (int i = 0; i < types.length; i++) {
				imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
			}
			return imports;
		}

	}

CacheAutoConfiguration这个配置类中可以找到这个函数,我们可以用断点来看看导入了哪些配置类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KvBeziqt-1584289740361)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200315231644136.png)]

导入了以下的这些包:

0 = "org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration"
1 = "org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration"
2 = "org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration"
3 = "org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration"
4 = "org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration"
5 = "org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration"
6 = "org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration"
7 = "org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration"
8 = "org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration"
9 = "org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration"

3、哪个配置类默认生效呢?

我们可以直接在yml配置文件下添加debug=true打印自动配置报告。我们就可以看到有哪些生效了的配置类。

我们可以找到只生效了:SimpleCacheConfiguration

SimpleCacheConfiguration作用:给容器中注册了一个CacheManager:ConcurrentMapCacheManager

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class SimpleCacheConfiguration {

	@Bean
	ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,
			CacheManagerCustomizers cacheManagerCustomizers) {
        //注册了一个CacheManager
		ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
		List<String> cacheNames = cacheProperties.getCacheNames();
		if (!cacheNames.isEmpty()) {
			cacheManager.setCacheNames(cacheNames);
		}
		return cacheManagerCustomizers.customize(cacheManager);
	}

}

实现CacheManager后就可以有getCache方法了。

我们来看一下这个函数:

@Override
	@Nullable
	public Cache getCache(String name) {
		Cache cache = this.cacheMap.get(name);
		if (cache == null && this.dynamic) {
			synchronized (this.cacheMap) {
				cache = this.cacheMap.get(name);
				if (cache == null) {
					cache = createConcurrentMapCache(name);
					this.cacheMap.put(name, cache);
				}
			}
		}
		return cache;
	}

createConcurrentMapCache:

protected Cache createConcurrentMapCache(String name) {
		SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
		return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256),
				isAllowNullValues(), actualSerialization);

	}

我们可以看到,这里创建了一个Cache对象,并返回该对象。

4、所以这个SimpleCacheConfiguration所起作用就可以获取创建ConcurrentMapCache类型的缓存组件

我们来看一下new的这个ConcurrentMapCache类:

其中有一个lookup函数:

protected Object lookup(Object key) {
		return this.store.get(key);
	}

返回一个key的值。我们来看一下store是一个什么结构:

private final ConcurrentMap<Object, Object> store;

store是一个Map键值对,根据传入的key来获取value值。

5、由以上分析,我们可以得到ConcurrentMapCache类型的缓存组件的作用:将数据保存在ConcurrentMap中,然后根据传入的key来返回存入的value值

//查询函数
@Override
@Nullable
protected Object lookup(Object key) {
    return this.store.get(key);
}
//保存函数
@Override
public void put(Object key, @Nullable Object value) {
    this.store.put(key, toStoreValue(value));
}

6、运行流程:

  • 一、查询缓存是否存在我们所请的数据,按照cacheName指定的名字获取,如果第一次获取缓存如果没有Cache组件会自动创建;

  • 二、去Cache中查找缓存的内容,使用一个key,默认方法的参数,key是按照某种策略生成的,默认是使用keyGenerator 生成的,默认使用SimpleKeyGenerator生成key。
    SimpleKeyGenerator生成key的默认策略

    • 如果没有参数,key=new SimpleKey();
    • 如果有一个参数,key=参数值;
    • 如果有多个参数,key=new SimpleKey(params);
  • 三、不存在的情况下,会调取对应的Service函数,然后调用Dao层,并返回数据;

  • 四、拿到数据库的数据后,会put到缓存中,如果设置了cacheNames,那么就是以cacheNames会缓存名字,value就是请求的对象数据;

  • 五、然后返回数据到前端页面;

  • 六、如果再次请求该数据,那么就会在ConcurrentMap中查找到以传入数据的值为key的缓存,然后就从ConcurrentMap中取出数据并返回给前端页面,不会执行Service函数,也不会访问数据库。

总体来说:

  • 方法执行之前先来检查缓存中有没有数据,默认按照参数的值作为key去查询缓存,如果没有就运行方法,并将结果放入缓存,以后再来调用就可以直接使用缓存中的数据。

@CachePut注解的使用:

  • CachePut的使用:在对数据库进行更新后,会随着更新缓存中的数据,以保持数据的一致性,对于update的方法,如果添加了缓存机制,那么最好要添加@CachePut注解,在更新的过程中也更新缓存;

  • CachePut运行时机:先调用目标方法,然后把结果返回到缓存中,更新缓存;

  • /**
         * @CachePut:运行时机:先调用目标方法,然后再把结果返回到缓存中,更新缓存
         *
         * @param user
         * @return
         */
        @CachePut(value = "user_emp",key = "#result.id")
        public User updateUser(User user){
            System.out.println("更新--"+user.getUsername()+"--用户");
            userMapper.updateUser(user);
            return user;
        }
    

    这里设置key设置为**#result.id**,把返回回来的**id(id也是主键属性)**设置为缓存的key值,以更新缓存中的数据。

  • 我们来看一下@CachePut的使用:

    首先我们查询一下,把id为1的用户放入缓存:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VUxK3uNF-1584521712275)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316111750528.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cMMffqfE-1584521712278)(C:\Users\ouguangji\Desktop\markdown\专业知识学习\image-20200316111822392.png)]

    然后我们更新一下id为1的用户,然后我们再查询一下id=1的用户,看是否更新缓存:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CpzKX4gU-1584521712280)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316113306247.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K3SfOwRp-1584521712284)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316113322830.png)]

    再查询:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wfs193Xw-1584521712286)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316113339423.png)]

    我们看看后台有没有打印访问数据库:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2hcuxlto-1584521712287)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316113405381.png)]

    可以看到,并没去数据库找该数据,所以可以得知:缓存更新成功,并且查询直接从缓存中拿出了该数据。


@Caching注解的使用:复杂注解的使用

/**
     * 添加@CachePut后会先执行方法,再更新缓存,无论什么情况都会执行方法,然后把缓存中的队友value值更新
     *
     * @param username
     * @return
     */
    @Caching(
            cacheable = {
                    @Cacheable(value = "user_emp",key = "#username")
            },
            put = {
                    @CachePut(value = "user_emp",key = "#result.id"),
                    @CachePut(value = "user_emp",key = "#result.phone")
            }
    )
    public User getUserByName(String username){
        System.out.println("使用名称查询:"+username+" 用户");
        return userMapper.getUserUsername(username);
    }

添加@CachePut注解后,会无论什么情况都会先执行方法,然后再更新缓存,只要对应好value值的情况下,就可以更新其他属性的缓存信息。


@CacheConfig:

public @interface CacheConfig {

	/**
	 * Names of the default caches to consider for caching operations defined
	 * in the annotated class.
	 * <p>If none is set at the operation level, these are used instead of the default.
	 * <p>May be used to determine the target cache (or caches), matching the
	 * qualifier value or the bean names of a specific bean definition.
	 */
	String[] cacheNames() default {};

	/**
	 * The bean name of the default {@link org.springframework.cache.interceptor.KeyGenerator} to
	 * use for the class.
	 * <p>If none is set at the operation level, this one is used instead of the default.
	 * <p>The key generator is mutually exclusive with the use of a custom key. When such key is
	 * defined for the operation, the value of this key generator is ignored.
	 */
	String keyGenerator() default "";

	/**
	 * The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
	 * create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
	 * is set already.
	 * <p>If no resolver and no cache manager are set at the operation level, and no cache
	 * resolver is set via {@link #cacheResolver}, this one is used instead of the default.
	 * @see org.springframework.cache.interceptor.SimpleCacheResolver
	 */
	String cacheManager() default "";

	/**
	 * The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
	 * <p>If no resolver and no cache manager are set at the operation level, this one is used
	 * instead of the default.
	 */
	String cacheResolver() default "";

}

在这个配置中可以设置一些公共的属性,比如cacheNames等属性,不需要每次在方法前添加cacheNames。


Redis的使用和配置:

一、Redis的简历:

Redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。

Redis与其他key-value缓存产品的特点有:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list、set、zset、hash等数据结构存储
  • Redis支持数据的备份,即master-slave模式的数据备份。

二、Redis的优势:

  • 性能极高:Redis能读的速度是110000次/s,写的速度是81000次/s。
  • 丰富的数据类型:Redis支持二进制案例的Strings,Lists,Hashes,Sets及Ordered Sets数据类型操作。
  • 原子性:Redis的所有操作都是原子性的,意思就是要么全部成功,么失败则全部不执行。单个操作是原子性的。多个操作也是支持事物的,即原子性:通过MULTI和EXEC只能包括起来。
  • 丰富的特征:Redis还支持publish/subscribe,通知,key过期等特性。

三、Redis与其他key-value存储有什么不同呢?

  • Redis有着更为复杂的数据结构并且提供了对他们的原子性操作,这是一个不同于其他数据库的进化路径,Redis的数据类型都是基于基本数据结构的同时对程序猿透明,不再需要其他额外的抽象。
  • Redis运行在内存中,但是可以持久化到硬盘上,所以在对不同数据集进行高速读写的时候需要权衡内存,因为数据量是不能大于硬件内存的。
  • 相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情,同时在磁盘格式方面他们是以紧凑的、以追加的方式产生的,不需要进行随机访问,这样能提高访问的速度。

四、在Windows下安装Redis

https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NhGADiQW-1584521712289)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316164049567.png)]

然后打开cmd,进入解压后的文件中:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ycVHlFY-1584521712290)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316164125980.png)]

redis-server.exe redis.windows.conf

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JMyLbxzA-1584521712291)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316164256088.png)]

启动成功,然后再开启一个cmd:

//windows进入方法
redis-cli.exe -h 127.0.0.1 -p 6379
//linux进入方法
redis-cli

然后设置键值对:

set myKey abc

取出键值对:

get myKey

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UnmGbs2T-1584521712293)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316164439801.png)]

安装完毕!


Redis数据类型

Redis支持五种数据类型:

  • String:字符串
  • hash:哈希
  • list:列表
  • set:集合
  • zeset(sorted set):有序集合

一、String字符串:

String字符串是redis最基本的类型,可以理解成语Memcached一模一样的类型,一个key对应一个value值。String类型是二进制安全的:redis的string可以包含任何数据,包含汉字、图片、或者序列化对象。String类型是Redis最基本的数据类型,最大能存储512MB。

set ruuoob "小狗"

我在docker中实验redis,因为在windows下,对于使用汉字的时候,会出现乱码的情况:

在linux下只需要设置 --raw 就可以显示中文汉字了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9y8cCnsB-1584521712294)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316172936564.png)]

二、Hash哈希:

Redis hash是一个键值对(key=>value)集合。

Redis hash是一个String类型的field和value的映射表,hash特别适合用于存储对象。

删除之前的key
DEL runoob
设置hash
HMSET runoob field1 "hello1" field2 "hello2"
得到hash值
HGET runoob field1

每个hash中可以存储2的32次方-1个键值对。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g0sKeVs1-1584521712295)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316173058660.png)]

三、List列表:

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

lpush runoob redis
lpush runoob mongodb
lpush runoob rabitmq
获取值:从第x到第y个值
lrange runoob x y 

列表最多存储2的32次方-1个元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-21Wk4TLB-1584521712296)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316173600020.png)]

三、Set集合:

Redis的Set集合是string类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找都是O(1)。

sadd命令:添加一个string元素到key对应的set集合中,成功返回1,如果元素已经存在在集合中返回0

sadd key member
取出元素:
smembers key

集合最多存储2的32次方-1个元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UYt9COT7-1584521712297)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316175355961.png)]

四、zset(Sorted set:有序集合)

Redis zset 和set 一样也是String类型元素的集合,且不允许重复的成员。

不同的是:每个元素都会关联一个double类型的分数,redis通过这个分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的。但是分数score是可以重复的。

zadd命令:添加元素到集合中,元素在集合中存在则更新对应的score

zadd key score member

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DQRPWfbM-1584521712298)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200316175949968.png)]


Redis和springboot的整合:

一、Redis的测试环境:

1)、搭建Redis环境;

2)、在springboot中加入redis依赖:

<!--redis加载-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>jcl-over-slf4j</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>io.lettuce</groupId>
        <artifactId>lettuce-core</artifactId>
    </dependency>

3)、配置文件配置ip和port:

spring:
    redis:
    host: 47.97.192.241
    port: 6379

4)、在test中测试Redis:

@SpringBootTest
class DemoMybatisApplicationTests {


    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    RedisTemplate redisTemplate;
    @Test
    void contextLoads() {
//        String msg = stringRedisTemplate.opsForValue().get("msg");
//        System.out.println("111");
//        System.out.println(msg);
        stringRedisTemplate.opsForList().leftPush("myList","1");
        stringRedisTemplate.opsForList().leftPush("myList","2");
        stringRedisTemplate.opsForList().leftPush("myList","3");
        stringRedisTemplate.opsForList().rightPush("myList","4");
    }

}

成功的情况下输出为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mdzKbJwl-1584521712299)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200317205410962.png)]

二、redis的实际使用:

1)、配置mybatis环境;

2)、配置redis环境;

3)、添加Service:

@Cacheable(cacheNames = "user_emp",key = "#root.args[0]")
public User getUserById(Integer id){
    System.out.println("查询 --id= "+id+"-- 用户");
    return userMappers.getUserById(id);
}

注意:User实体类,一定要添加序列化接口。

但是如果这样进行缓存,缓存下来的只能是序列化后的数据,如果我们想缓存json数据到Redis中,那么就必须自定义配置redisconfig。

4)、配置自定义MyRedisConfig

@Configuration
public class MyRedisConfig {

    /**
     * 自定义序列化器
     * @param redisConnectionFactory
     * @return
     * @throws
     */
    @Bean
    public RedisTemplate<Object, Object> User_redisTemplate(RedisConnectionFactory redisConnectionFactory)
    {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer<Object> jsonRedisSerializer
                = new Jackson2JsonRedisSerializer<Object>(Object.class);
        template.setDefaultSerializer(jsonRedisSerializer);

        return template;
    }


    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory){
        //初始化一个RedisCacheWriter输出流
        RedisCacheWriter redisCacheWriter=RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
        //自定义序列化机制
        Jackson2JsonRedisSerializer<Object> serializer=new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper mapper=new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);
        RedisSerializationContext.SerializationPair pair=
                RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(serializer);
        //创建CacheConfig
        RedisCacheConfiguration redisCacheConfiguration=RedisCacheConfiguration
                .defaultCacheConfig()
                .serializeValuesWith(pair);
        return new RedisCacheManager(redisCacheWriter,redisCacheConfiguration);
    }
    
}
第一个函数自定义的是RedisTemplate的配置。
RedisTemplate<Object,Object> User_redisTemplate;

RedisTemplate的用法:在Controller中:

@Autowired
RedisTemplate<Object,Object> User_redisTemplate;
@ResponseBody
@GetMapping("/add2")
public Object add2(){
    User user=new User();
    user.setUsername("ogj");
    user.setPasswd("123456");
    user.setAddress("重庆市");
    User_redisTemplate.opsForValue().set("user",user);
    return User_redisTemplate.opsForValue().get("user");
}    
第二个函数自定义的是Cacheable注解所自定义的CacheManager:
@Cacheable(cacheNames = "user_emp",key = "#root.args[0]")
public User getUserById(Integer id){
    System.out.println("查询 --id= "+id+"-- 用户");
    return userMappers.getUserById(id);
}

使用方法和之前Cache的使用方法相同,因为之前使用的是SimpleCacheConfiguration,在加入RedisCache后,自动配置将自动转为redis的配置,所以使用方法完全一致:

  • @Cacheable进行缓存
  • @CachePut进行缓存更新
  • @CacheEvict进行删除
  • @Caching进行复杂化操作

5)、运行项目:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Vey37Ig-1584521712300)(C:\Users\ouguangji\AppData\Roaming\Typora\typora-user-images\image-20200318164837997.png)]

在这里插入图片描述

json格式存储成功!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值