spring boot 整合 redis,使用@Cacheable,@CacheEvict,@CachePut,jedisPool操作redis数据库

好久没写文章了,最近换了个公司,入职差不多一个半月了,接触了不少没玩过的新东西,这里放个
spring boot 整合 redis的demo吧。
先看一下demo目录:
这里写图片描述
如何创建spring boot项目我就不说了很简单,不会百度一大把。
先看一下pom需要哪些包:

<dependencies>
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.0.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.29</version>
        </dependency>
    </dependencies>

这些包都很见名知意我就不说每个干嘛用的了。
先看一下配置文件吧,主要就3个东西,redis,mysql,jpa:

#redis相关配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8  
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1  
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8  
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0  
# 连接超时时间(毫秒)
spring.redis.timeout=6000 

#mysql相关配置
#mysql服务器地址
spring.datasource.url =jdbc:mysql://localhost:3306/redis_test
#mysql服务器连接用户名
spring.datasource.username = root
#mysql服务器连接密码
spring.datasource.password = root
#mysql服务器连接驱动
spring.datasource.driverClassName =com.mysql.jdbc.Driver
# 连接池最大连接数
spring.datasource.max-active=20
# 连接池中的最大空闲连接
spring.datasource.max-idle=8
# 连接池中的最小空闲连接
spring.datasource.min-idle=8

spring.datasource.initial-size=10


# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sqlquery
spring.jpa.show-sql = true
# Hibernate ddl auto (create,create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy =org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them tothe entity manager)
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

既然用到redis,需要先写一个RedisUtils类来继承CachingConfigurerSupport,需要我们手动实现一些方法:

@Configuration
@EnableCaching //启用缓存,这个注解很重要;
public class RedisUtils extends CachingConfigurerSupport {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.timeout}")
    private int timeout;

    @Value("${spring.redis.pool.max-idle}")
    private int maxIdle;

    @Value("${spring.redis.pool.max-wait}")
    private long maxWaitMillis;

//    @Value("${spring.redis.password}")
//    private String password;

    @Bean
    public JedisPool redisPoolFactory() {
        System.out.println("JedisPool注入成功!!");
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        //本地redis未设置密码,所以第五个参数password不传
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout);
        return jedisPool;
    }

    /**
     * 缓存管理器.
     * @param redisTemplate
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) {
        CacheManager cacheManager = new RedisCacheManager(redisTemplate);
        return cacheManager;
    }

    /**
     * redis模板操作类,类似于jdbcTemplate的一个类;
     * 虽然CacheManager也能获取到Cache对象,但是操作起来没有那么灵活;
     * 这里在扩展下:RedisTemplate这个类不见得很好操作,我们可以在进行扩展一个我们
     * 自己的缓存类,比如:RedisStorage类;
     * @param redisConnectionFactory : 通过Spring进行注入,参数在application.properties进行配置;
     * @return
     */
    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory);
        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);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

    /**
     * 自定义key生成策略
     * 类名+方法名+参数(适用于分布式缓存),默认key生成策略分布式下有可能重复被覆盖
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return (o, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(o.getClass().getName());
            sb.append("." + method.getName() + "(");
            for (Object obj : objects) {
                sb.append(obj.toString());
            }
            sb.append(")");
            return sb.toString();
        };
    }
}

看一下controller,方法都见名知意我就不写注释了,这里介绍一下controller用到的3个注解作用:
@Cacheable:主要用作查询,如果根据key从redis中没查到就去mysql查并且把返回结果插入redis,下次直接从redis取;
@CachePut:主要用作更新,如果根据key从redis中没查到就去mysql查并且把返回结果插入redis,如果从redis查到那么也去mysql查一遍,所以不管redis中有没有都去查mysql,所以主要用作更新
@CacheEvict:主要用作删除,根据key从redis中删除数据

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/findById/{id}")
//    @Cacheable(value = "user",keyGenerator = "keyGenerator")
    @Cacheable(value = "zh",key = "'user_' + #id")
    public User findById(@PathVariable Integer id) {
        System.err.println("UserController.findById()=========从数据库中进行获取的....id = " + id);
        return userService.findById(id);
    }

    @GetMapping("/deleteById/{id}")
    @CacheEvict(value = "zh",key = "'user_' + #id")
    public void deleteById(@PathVariable Integer id){
        System.out.println("UserController.deleteById().从数据库中删除.");
        userService.deleteById(id);
    }

    @PostMapping("/save")
    @CachePut(value = "zh",key = "'user_' + #user.id")
    public User save(User user){
        return userService.save(user);
    }

    @PostMapping("/updateNameById")
    public void updateNameById(User user){
        userService.updateNameById(user);
    }

}

看下service和serviceImpl,前三个方法是加了注解操作redis,第四个方法是使用jedisPool操作数据库:

public interface UserService {
    User findById(Integer id);

    void deleteById(Integer id);

    User save(User user);

    void updateNameById(User user);
}
@Service
public class UserServicrImpl implements UserService {
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private JedisPool jedisPool;
    @Autowired
    private UserDao userDao;

    @Override
    public User findById(Integer id) {
        return userDao.findOne(id);
    }

    @Override
    public void deleteById(Integer id) {
        userDao.delete(id);
    }

    @Override
    public User save(User user) {
        return userDao.save(user);
    }

    @Override
    public void updateNameById(User user) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("连接不上redis");
        }
        JSONObject jsonUser= (JSONObject) JSONObject.toJSON(user);
        jedis.set("user_" + user.getId(),jsonUser.toJSONString());
        jedis.close();
    }
}

dao继承一下jpa的类就行了,提供了基本的增删改查,User实体类我就不贴了:

public interface UserDao extends CrudRepository<User, Integer> {
}

总结一下:我在写demo的时候思考为什么注解很方便的操作redis,还要用jedisPool操作数据库呢?
其实原因很简单,因为实际业务逻辑会有很复杂的情况,注解只适用与简单的操作。因为jedisPool连接池可能连不上redis所以要加try/catch捕获

猜你喜欢

转载自blog.csdn.net/eumenides_/article/details/78298088
今日推荐