[Series] how open source project based on Spring Cache multi-level cache (cache Ehcache while integrating local and distributed cache Redis)

A cache

When the amount of concurrent system up, and if we go frequently access the database, then the pressure will continue to increase the database, the database crashes can occur even at peak phenomenon. So in general we will use the cache to solve this problem concurrent access to the database, user access to come in, it will start with the query cache, if there is returned if there is no longer a query from the database, and finally added to the cache, and then returned to the user, of course, then you can use caching to provide a search function.

The cache, we generally can be divided into local caching and distributed cache.

Commonly used local cache has ehcache, guava cache, while we generally use ehcache, after all, he is pure Java, there is a problem we can solve the source code, and also own secondary development to extend the functionality.

Commonly distributed caching of course, is the Redis, Redis is a memory-based and single-threaded, the efficiency is very high.

二、Spring Cache

I believe if you want to integrate the cache to the project, we will use the Spring Cache, it not only integrates multiple caching framework (ehcache, jcache etc.), can also be based on the use of annotations, is quite convenient.

Integrated caching framework in spring-context-support in:
Here Insert Picture Description
Cache annotation in the spring-context:
Here Insert Picture Description
Of course, no Redis integration in the context of the Spring, but we can find the spring-data-redis in.
Here Insert Picture Description
But we all know, whether it is in the Spring or Spring Boot project, we can integrate all of the cache, the cache can not consolidate multiple simultaneously.

In Spring Boot, we usually use spring.cache.typeto specify which cache to use, and then fill in the relevant configuration information to complete the automatic configuration.
Here Insert Picture Description
CacheType source: we can see, Spring supports a large variety of caching framework.

package org.springframework.boot.autoconfigure.cache;

public enum CacheType {
    GENERIC,
    JCACHE,
    EHCACHE,
    HAZELCAST,
    INFINISPAN,
    COUCHBASE,
    REDIS,
    CAFFEINE,
    SIMPLE,
    NONE;

    private CacheType() {
    }
}

So if we just have such a need to integrate both caching framework: for example, a local cache Ehcache, a distributed cache Redis,

That whole can it?

You could be able to, but do not provide this Spring multi-level cache, but requires you yourself to the whole.

三、h2cache-spring-boot-starter

1. What is h2cache-spring-boot-starter?

In the micro-services, each service is stateless, need to go through RPC or HTTP to communicate between the service. And each service has its own corresponding database, so that if service A need to obtain data in a table service B, then you need a HTTP or RPC communication, and that if the peak of the need to call 100 times per second, it would mean that It requires 100 HTTP communication or RPC, the interface which is quite time consuming properties.

Then how to solve it?

That is certainly not the local cache, because different services are usually deployed in different machines above, so this time we need a distributed cache, such as Redis; however, high-traffic service of course still need a local cache . So finally, we need not only the local cache, but also distributed cache, but Spring Boot did not provide such a multi-level cache function, so it is necessary to integrate ourselves.

Do not worry, I already own a Spring Boot Starter whole, that is h2cache-spring-boot-starter, we only need to configure the corresponding information in the configuration file, you can enable the function of the multi-level cache.

2, started

Add dependence:

We introduced below normal can rely on, because I have posted this item to the Maven central repository of ~

<denpency>
    <groupId>com.github.howinfun</groupId>
    <artifactId>h2cache-spring-boot-starter</artifactId>
    <version>0.0.1</version>
</denpency>

Enabling Services in Spring Boot properties, and add the corresponding configuration:

Open multi-level cache service:

# Enable L2 cache or not
h2cache.enabled=true

Configuration Ehcache:

# Ehcache Config
## the path of ehcache.xml (We can put it directly under Resources) 
h2cache.ehcache.filePath=ehcache.xml
#Set whether the EhCache CacheManager should be shared (as a singleton at the ClassLoader level) or independent (typically local within the application).Default is "false", creating an independent local instance.
h2cache.ehcache.shared=true

Configuration Redis: including the default cache configuration and custom cache configuration

Point to note is: h2cache-spring-boot-starter while introducing Lettuceand Jedisclient, and the client Lettuce Spring Boot using the default, so if we need to use Jedis client, you need to rely Lettuce removed.

# Redis Config
## default Config (expire)
h2cache.redis.default-config.ttl=200
### Disable caching {@literal null} values.Default is "false"
h2cache.redis.default-config.disable-null-values=true
### Disable using cache key prefixes.Default is "true"
h2cache.redis.default-config.use-prefix=true

## Custom Config list
### cacheName -> @CacheConfig#cacheNames @Cacheable#cacheNames and other comments, etc   
h2cache.redis.config-list[0].cache-name=userCache
h2cache.redis.config-list[0].ttl=60
h2cache.redis.config-list[0].use-prefix=true
h2cache.redis.config-list[0].disable-null-values=true

h2cache.redis.config-list[1].cache-name=bookCache
h2cache.redis.config-list[1].ttl=60
h2cache.redis.config-list[1].use-prefix=true

#Redis
spring.redis.host=10.111.0.111
spring.redis.password=
spring.redis.port=6379
spring.redis.database=15
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=30

How to use the cache annotations

As long as we do before using Spring Cacheannotations can be.

for example:

The persistence layer code, I use is: the mybatis-PLUS .

package com.hyf.testDemo.redis;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Repository;

/**
 * @author Howinfun
 * @desc
 * @date 2020/3/25
 */
@Repository
// Global cache config,We usually set the cacheName               
@CacheConfig(cacheNames = {"userCache"})
public interface UserMapper extends BaseMapper<User> {

    /**
    * put the data to cache(Ehcache & Redis)
    * @param id
    * @return 
    */
    @Cacheable(key = "#id",unless = "#result == null")
    User selectById(Long id);

    /**
    * put the data to cache After method execution
    * @param user
    * @return 
    */
    @CachePut(key = "#user.id", condition = "#user.name != null and #user.name != ''")
    default User insert0(User user) {
        
        this.insert(user);
        return user;
    }

    /**
    * evict the data from cache
    * @param id
    * @return 
    */
    @CacheEvict(key = "#id")
    int deleteById(Long id);

    /**
    * Using cache annotations in combination
    * @param user
    * @return 
    */
    @Caching(
            evict = {@CacheEvict(key = "#user.id", beforeInvocation = true)},
            put = {@CachePut(key = "#user.id")}
    )
    default User updateUser0(User user){
        
        this.updateById(user);
        return user;
    }
}

have a test:

Query: We can see that in the database query results, will be added to the data Ehcacheand Rediscache; all will then inquire after the start Ehcacheor Redisin the query.

2020-04-03 09:55:09.691  INFO 5920 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-04-03 09:55:10.044  INFO 5920 --- [nio-8080-exec-7] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-04-03 09:55:10.051 DEBUG 5920 --- [nio-8080-exec-7] c.h.t.redis.BookMapper2.selectById       : ==>  Preparing: SELECT id,create_time,update_time,read_frequency,version,book_name FROM book WHERE id=? 
2020-04-03 09:55:10.068 DEBUG 5920 --- [nio-8080-exec-7] c.h.t.redis.BookMapper2.selectById       : ==> Parameters: 51(Long)
2020-04-03 09:55:10.107 DEBUG 5920 --- [nio-8080-exec-7] c.h.t.redis.BookMapper2.selectById       : <==      Total: 1
2020-04-03 09:55:10.113  INFO 5920 --- [nio-8080-exec-7] c.hyf.cache.cachetemplate.H2CacheCache   : insert into ehcache,key:51,value:Book2(id=51, bookName=微服务架构, readFrequency=1, createTime=2020-03-20T16:10:13, updateTime=2020-03-27T09:14:44, version=1)
2020-04-03 09:55:10.118  INFO 5920 --- [nio-8080-exec-7] c.hyf.cache.cachetemplate.H2CacheCache   : insert into redis,key:51,value:Book2(id=51, bookName=微服务架构, readFrequency=1, createTime=2020-03-20T16:10:13, updateTime=2020-03-27T09:14:44, version=1)

2020-04-03 09:55:31.864  INFO 5920 --- [nio-8080-exec-2] c.hyf.cache.cachetemplate.H2CacheCache   : select from ehcache,key:51

Delete: When you delete data in the database, it will be deleted Ehcacheand Redisthe corresponding cache data.

2020-04-03 10:05:18.704 DEBUG 5920 --- [nio-8080-exec-3] c.h.t.redis.BookMapper2.deleteById       : ==>  Preparing: DELETE FROM book WHERE id=? 
2020-04-03 10:05:18.704 DEBUG 5920 --- [nio-8080-exec-3] c.h.t.redis.BookMapper2.deleteById       : ==> Parameters: 51(Long)
2020-04-03 10:05:18.731 DEBUG 5920 --- [nio-8080-exec-3] c.h.t.redis.BookMapper2.deleteById       : <==    Updates: 1
2020-04-03 10:05:18.732  INFO 5920 --- [nio-8080-exec-3] c.hyf.cache.cachetemplate.H2CacheCache   : delete from ehcache,key:51
2020-04-03 10:05:18.844  INFO 5920 --- [nio-8080-exec-3] c.hyf.cache.cachetemplate.H2CacheCache   : delete from redis,key:51

Others do not demonstrate ...

Fourth, and finally

Of course, this starter is quite simple, if you're interested, you can go and see how the source code is based on Spring Cache multi-level cache ~

Guess you like

Origin www.cnblogs.com/Howinfun/p/12651576.html