大家都知道springboot项目都是微服务部署,A服务和B服务分开部署,那么它们如何更新或者获取共有模块的缓存数据,或者给A服务做分布式集群负载,如何确保A服务的所有集群都能同步公共模块的缓存数据,这些都涉及到分布式系统缓存的实现。

前面其实我已经介绍了springboot+mybatis+ehcache实现缓存数据,但是ehcache的设计并不适合做分布式缓存,所以今天用redis来实现分布式缓存。

原理什么的,我就不多说了,直接上代码。

pom依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency> <dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

表创建sql语句

CREATE TABLE `t_user` (
`id` varchar(50) NOT NULL,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

application.properties配置文件

server.port=8860

# redis
spring.redis.database=1
spring.redis.host=127.0.0.1
spring.redis.password=test123
spring.redis.pool.max-active=8
spring.redis.pool.max-idle=8
spring.redis.pool.max-wait=-1
spring.redis.pool.min-idle=0
spring.redis.port=6379
#spring.redis.sentinel.master= # Name of Redis server.
#spring.redis.sentinel.nodes= # Comma-separated list of host:port pairs.
spring.redis.timeout=5000 # cache
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=600000 # datasource
spring.datasource.name=ehcahcetest
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3312/ehcahcetest
spring.datasource.username=root
spring.datasource.password=123456 # mybatis
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.config-location=classpath:mybatis/mybatis-config.xml
#mybatis.type-aliases-package=

springboot启动类

package com.rediscache;

import java.lang.reflect.Method;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper; @SpringBootApplication
@ComponentScan(basePackages="com.rediscache")//扫描组件
@ServletComponentScan(basePackages="rediscache")//扫描拦截器,过滤器
@EnableCaching
public class RedisCacheTestApplication { /**
* 设置缓存对象的序列化方式,不设置会报错
* 另外对于json序列化,对象要提供默认空构造器
* @param redisTemplate
* @return
*/
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) { Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
cacheManager.setDefaultExpiration(300);
return cacheManager;
} /**
* 自定义key的生成策略
* @return
*/
@Bean
public KeyGenerator myKeyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
} public static void main(String[] args) {
SpringApplication.run(RedisCacheTestApplication.class, args);
} }

接口测试类

package com.rediscache.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import com.rediscache.entity.User;
import com.rediscache.factory.UserFactory;
import com.rediscache.service.UserService;
import com.google.gson.Gson; @RestController
@RequestMapping("/o")
public class OperationController { @Autowired
private StringRedisTemplate redisTemplate; @Autowired
private UserService userService; Gson gson = new Gson(); @RequestMapping(value = "/insert", method = RequestMethod.GET)
public String insert(){ // 保存一个新用户
String uid = userService.save(UserFactory.createUser()); return uid;
} @RequestMapping(value = "/query", method = RequestMethod.GET)
public String query(String uid){ // 查询该用户
System.out.println(gson.toJson(userService.getUserById(uid), User.class));
System.out.println(); return "success";
} @RequestMapping(value = "/update", method = RequestMethod.GET)
public String update(String uid, String username){ User user = new User();
user.setUid(uid);
user.setUsername(username); // 更新该用户
userService.update(user); return "success";
} @RequestMapping(value = "/del", method = RequestMethod.GET)
public String del(String uid){ // 删除该用户
userService.del(uid);
System.out.println(); return "success";
} }

service缓存类

package com.rediscache.service;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import com.rediscache.dao.UserDao;
import com.rediscache.entity.User; @Service
public class UserService { @Autowired
private UserDao userDao; @CacheEvict(key="'user_'+#uid", value="userCache")
public void del(String uid) {
// TODO Auto-generated method stub
userDao.del(uid);
} @CachePut(key="'user_'+#user.uid", value="userCache")
public void update(User user) {
userDao.update(user);
} @Cacheable(key="'user_'+#uid",value="userCache")
public User getUserById(String uid){
System.err.println("缓存里没有"+uid+",所以这边没有走缓存,从数据库拿数据");
return userDao.findById(uid); } @CacheEvict(key="'user'",value="userCache")
public String save(User user) {
// TODO Auto-generated method stub
return userDao.save(user);
} }

其它的dao类和mybatis的mapper就不贴了。

复制上面写好的项目,把新项目的端口改为8862,现在分别启动8860和8862两个项目,模拟服务的集群部署。

开始测试

1、浏览器里输入http://localhost:8860/o/insert

可以看到数据库里保存进一条数据

2、输入http://localhost:8860/o/query?uid=ff4c5723-3ffc-438d-9d8c-8a2a7025b33e 查询刚刚的这条数据

可以看到sql语句打印了,提示也表示这一次没有走缓存

看看redis

说明缓存数据已经进来了。

3、再次http://localhost:8860/o/query?uid=ff4c5723-3ffc-438d-9d8c-8a2a7025b33e 查询

可以看到这次没有从数据库查,而是从缓存里获取的数据

说明单服务里的缓存已经奏效了,下面看看集群服务有没有效果

4、http://localhost:8862/o/query?uid=ff4c5723-3ffc-438d-9d8c-8a2a7025b33e 在8862服务里查询

这个是8862的控制台打印的结果,说明分布式缓存奏效了。

项目结构截图

注意点

缓存设置了时效的,也就是redis的时效

springboot+mybatis+redis实现分布式缓存的更多相关文章

  1. Redis-基本概念、java操作redis、springboot整合redis,分布式缓存,分布式session管理等

    NoSQL的引言 Redis数据库相关指令 Redis持久化相关机制 SpringBoot操作Redis Redis分布式缓存实现 Resis中主从复制架构和哨兵机制 Redis集群搭建 Redis实 ...

  2. Springboot Mybatis Redis 实现二级缓存

    前言 什么是mybatis二级缓存? 二级缓存是多个sqlsession共享的,其作用域是mapper的同一个namespace. 即,在不同的sqlsession中,相同的namespace下,相同 ...

  3. WEB 应用缓存解析以及使用 Redis 实现分布式缓存

    什么是缓存? 缓存就是数据交换的缓冲区,用于临时存储数据(使用频繁的数据).当用户请求数据时,首先在缓存中寻找,如果找到了则直接返回.如果找不到,则去数据库中查找.缓存的本质就是用空间换时间,牺牲数据 ...

  4. Redis实现分布式缓存

    Redis 分布式缓存实现(一) 1. 什么是缓存(Cache) 定义:就是计算机内存中的一段数据: 2. 内存中数据特点 a. 读写快    b. 断电立即丢失 3. 缓存解决了什么问题? a. 提 ...

  5. 在AspNetCore 中 使用Redis实现分布式缓存

    AspNetCore 使用Redis实现分布式缓存 上一篇讲到了,Core的内置缓存:IMemoryCache,以及缓存的基础概念.本篇会进行一些概念上的补充. 本篇我们记录的内容是怎么在Core中使 ...

  6. 【转载】在AspNetCore 中 使用Redis实现分布式缓存

    原文地址:https://www.cnblogs.com/szlblog/p/9045209.html AspNetCore 使用Redis实现分布式缓存 上一篇讲到了,Core的内置缓存:IMemo ...

  7. ASP.NET Core 使用 Redis 实现分布式缓存:Docker、IDistributedCache、StackExchangeRedis

    ASP.NET Core 使用 Redis 实现分布式缓存:Docker.IDistributedCache.StackExchangeRedis 前提:一台 Linux 服务器.已安装 Docker ...

  8. SpringBoot集成Redis 一 分布式锁 与 缓存

    1.添加依赖及配置(application.yml) <!-- 引入redis依赖 --> <dependency> <groupId>org.springfram ...

  9. redis+keeplived分布式缓存

    redis(三)redis+Keepalived主从热备秒级切换 博客分类: 分布式缓存Redis redis高可用Keepalived  一 简介 安装使用centos 5.10 Master 19 ...

随机推荐

  1. 《java第一季之入门篇》的想法

    学习java也有一段时间了,但是考虑到自己现在上课.复习.考试等耗费很多时间,感觉没有静下心来的时间去写一个长期的博客.计划今年7月1号开始写一套关于java的入门篇博客文章,入门篇计划这样--涵盖j ...

  2. PDA开发数据由DB下载至PDA本地

    public string DownFile = "\\下载.txt";//下载路径 public string LoadFile = "\\上传.txt";/ ...

  3. 如何取得ChipmunkConstraint实例对象的私有属性

    在 如何用代码禁用SpriteBuilder中创建的关节 一篇中提到了要想禁用一个关节就需要将其无效化. 然后我们在重新创建新关节时,可以参考该关节的原始参数. 但是代码中只能直接访问到bodyA和b ...

  4. didLoadFromCCB方法的调用顺序

    该方法运行顺序和其(包含)继承体系顺序的逆序相同. 这意味着孩子的didLoadFromCCB将总是在其父的didLoadFromCCB之前调用. 比如GameScene.ccb中含有GameMenu ...

  5. Android开发技巧——实现可复用的ActionSheet菜单

    在上一篇<Android开发技巧--使用Dialog实现仿QQ的ActionSheet菜单>中,讲了这种菜单的实现过程,接下来将把它改成一个可复用的控件库. 本文原创,转载请注明出处: h ...

  6. SharePoint 2007 图片库视图不可用、页面标题不显示

    描述: 问题1:SharePoint新建图片库,想选择"视图"-"所有图片",选择"详细信息.幻灯片.缩略图"等视图,均没有反应.如图1. ...

  7. masm中list文件和宏的一些常用编译调试查看方法

    我们知道使用用 ml /Fl a.asm 可以生成lst文件,但是如果不加调整,masm默认生成的lst文件是非常大的,因为它包含了很大的windows必须用到的头文件内容,为了减小lst文件大小,便 ...

  8. 恶补web之三:http学习

    http是超文本传输协议的简称,该协议设计目的是保证客户机与服务器之间的通信.http的工作方式为客户机与服务器之间的请求-应答协议. 一般来说web浏览器是客户端,计算机上的网络应用程序可能作为服务 ...

  9. db2字段修改

    db2表字段修改 1:删除字段非空属性alter table XXX alter column XXX drop not null 2:添加字段非空属性alter table XXX alter co ...

  10. java程序的内存分配(二)

    前言 您是否是动态分配的 C/C++ 对象忠实且幸运的用户?您是否在模块间的往返通信中频繁地使用了"自动化"?您的程序是否因堆分配而运行起来很慢?不仅仅您遇到这样的问题.几乎所有项 ...