1. 程式人生 > >spring boot 整合 redis,使用@Cacheable,@CacheEvict,@CachePut,jedisPool操作redis資料庫

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捕獲