springboot+mybatis+redis实现分布式缓存详解编程语言

 

 

 

大家都知道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

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

springboot+mybatis+redis实现分布式缓存详解编程语言

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

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

springboot+mybatis+redis实现分布式缓存详解编程语言

看看redis

 springboot+mybatis+redis实现分布式缓存详解编程语言

springboot+mybatis+redis实现分布式缓存详解编程语言

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

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

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

springboot+mybatis+redis实现分布式缓存详解编程语言

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

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

 springboot+mybatis+redis实现分布式缓存详解编程语言

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

项目结构截图

springboot+mybatis+redis实现分布式缓存详解编程语言

 

注意点

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

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/15695.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论