1. Ehcache Introduction
EhCache is a pure Java in-process caching framework, which is fast and capable, and is the default Cacheprovider in Hibernate. Ehcache is a widely used, open source Java distributed cache. Primarily for general purpose caches, Java EE and lightweight containers. It features memory and disk storage, cache loaders, cache extensions, cache exception handlers, a gzip cache servlet filter, and support for rest and soap APIs.
Spring provides an abstraction of caching capabilities: that is, allowing different caching solutions to be bound (such as Ehcache), but does not natively provide the implementation of the caching functionality. It is very convenient to use the cache in annotation mode.
Ehcache Features: Fast and simple multiple cache policy cache data has two levels: memory and disk, so there is no need to worry about capacity issues cache data written to disk during virtual machine restart can be done through RMI, pluggable APIs, etc. distributed cache with cache and cache manager listening interface Support for multiple cache manager instances, as well as one instance of the cache implementation of hibernate for caching implementations
2.Redis introduction
Redis is an open source API that is written in ANSI C, supports the web, can be persisted in memory, key-value databases, and provides multiple languages. From March 15, 2010 onwards, the development work of Redis is hosted by VMware. Since May 2013, the development of Redis has been sponsored by pivotal.
Redis is a key-value storage system. It supports a large number of stored value types, including string (string), list (linked list), set (set), Zset (sorted set-ordered set), and hash (hash type). These data types support Push/pop, Add/remove, and intersection-set and difference sets, and richer operations, and these operations are atomic. Based on this, Redis supports sorting in a variety of different ways. Redis caches the data in memory. Redis periodically writes the updated data to disk or writes the modified operation to the appended record file, and Master-slave (Master-Slave) synchronization is implemented on this basis.
Features of Redis:
1. Fast speed
Redis is implemented in C, and all redis data is stored in memory. 2. Persistence
All redis data is stored in memory, and updates to the data are saved asynchronously to disk.
3. Support multiple data structures
Redis supports five types of data structures: String, List, Set, Hash, Zset 4, support for multiple programming languages
Java, PHP, Python, Ruby, Lua, node. js 5, Feature rich
In addition to supporting five types of data structures, it also supports functions such as transactions, pipelining, publish/subscribe, Message Queuing, and so on. 6. Simple source Code
Approximately 23000 lines of C language source code. 7, master-slave replication
The primary server (master) performs additions, modifications, deletions, and queries from the server. 8. Highly available and distributed
Redis-sentinel (v2.8) supports high availability. Redis-cluster (v3.0) supports distributed
3. Ehcache and Redis comparison
|
Ehcache |
Redis |
Access speed |
Ehcache cache directly in the JVM virtual machine, fast and efficient |
Redis is accessed through the socket to the cache service, which is less efficient than ecache |
Clustering and distributed |
Ehcache has the cache sharing scheme, but the broadcast cache notification update through RMI or Jgroup multicast, the cache sharing is complex, the maintenance is inconvenient; simple sharing can be, but it involves cache recovery, big data cache is not appropriate. |
Redis has a proven, distributed solution. Suitable for large-scale distributed cluster deployments. |
Complexity of operations |
The interface provided by Ehcache is simple and straightforward, and it only takes a few minutes of your time to build from Ehcache to use. In fact, many developers do not know that they use Ehcache,ehcache is widely used in other open source projects. For example: Hibernate |
At a minimum, you need to install the server and client to use. The operation is slightly more complicated than ehcache. |
|
|
|
4.SpringBoot and Ehcache integration solution
Configure Ehcache
@Configuration
@EnableCaching
public class EhCacheConfiguration implements CachingConfigurer {
@Bean (destroyMethod = "shutdown")
public net.sf.ehcache.CacheManager ehCacheManager () {
CacheConfiguration cacheConfiguration = new CacheConfiguration ();
cacheConfiguration.setName ("HelloWorldCache");
cacheConfiguration.setMemoryStoreEvictionPolicy ("LRU");
cacheConfiguration.setMaxEntriesLocalHeap (1000);
net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration ();
// Can create multiple cacheConfiguration, all added to Config
config.addCache (cacheConfiguration);
return net.sf.ehcache.CacheManager.newInstance (config);
}
@Bean
@Override
public CacheManager cacheManager () {
return new EhCacheCacheManager (ehCacheManager ());
}
@Bean
@Override
public KeyGenerator keyGenerator () {
return new SimpleKeyGenerator ();
}
@Override
public CacheResolver cacheResolver () {return null;}
@Override
public CacheErrorHandler errorHandler () {
return null;
}
}
Write a test service and its implementation class
public interface EhcacheService {
// Test failure, valid for 5 seconds
public String getTimestamp (String param);
}
@Service
public class EhcacheServiceImpl implements EhcacheService {
/ **
* @Cacheable indicates that the modified method can be cached: when this method is called for the first time, its result will be cached, within the effective time of the cache
* After accessing this method, the results of the cache will be returned directly, and the code segment in the method will no longer be executed.
* This annotation can use the condition attribute to set the condition. If the condition is not met, the cache capability is not used and the method is executed directly.
* You can use the key attribute to specify key generation rules.
*
* value: The name of the cache location, which cannot be empty. If EHCache is used, it is the name of the cache declared in ehcache.xml, which indicates in which cache the value is cached
*
* key: the cached key, which is empty by default, which means that the parameter type and parameter value of the method are used as the key, and SpEL is supported. If you want to refer to the parameter value, use a hash sign plus the parameter name, such as: #userId,
* In general, our update operation only needs to refresh a certain value in the cache, so the way to define the key value of the cache is very important, it is best to be unique, because this can accurately clear a specific cache, and will not Affect other cache values,
* In this example, the entity is combined with a colon and an ID to form a key name, such as "user: 1", "order: 223123", etc.
*
* condition: trigger condition, the cache will be added only when the condition is met, the default is empty, which means that all are added to the cache, support SpEL
* @param param
* @return
* /
@Cacheable (value = "HelloWorldCache", key = "# param")
@Override
public String getTimestamp (String param) {
Long timestamp = System.currentTimeMillis ();
return timestamp.toString ();
}
}
Write a unit test:
@RunWith (springrunner.class)
@SpringBootTest public
class Ehcacheservicetest {
@Autowired
Ehcacheservice Ehcacheservice;
/**
* Returns the first time the Gettimestamp method was called
* @throws interruptedexception */
@Test public
Void Testgettimestamp () throws Interruptedexception {
System.out.println ("First Call:" + Ehcacheservice.gettimestamp (" Param "));
Thread.Sleep (+);
System.out.println ("Call after 2 seconds:" + ehcacheservice.gettimestamp ("param"));
Thread.Sleep (4000);
System.out.println ("Call after 4 seconds:" + ehcacheservice.gettimestamp ("param"));}
}
You can see that the second two calls return the time of the first method call.
5. Springboot Integrated Redis Solution
Configure Redis
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate <String, Object> redisTemplate (RedisConnectionFactory factory) {
RedisTemplate <String, Object> redisTemplate = new RedisTemplate <String, Object> ();
redisTemplate.setConnectionFactory (factory);
// Key serialization method; (otherwise garbled characters will appear;), but if the method has Long and other non-String types, it will report a type conversion error;
// So when you do not define your own key generation strategy, the following code does not recommend this, you can not configure or implement ObjectRedisSerializer yourself
// Or JdkSerializationRedisSerializer serialization method;
RedisSerializer <String> keyRedisSerializer = new StringRedisSerializer ();
RedisSerializer <Object> valueRedisSerializer = new GenericJackson2JsonRedisSerializer ();
// Set the instantiated object of serialized Key
redisTemplate.setKeySerializer (keyRedisSerializer);
// Set the instantiated object of serialized Value
redisTemplate.setValueSerializer (valueRedisSerializer);
redisTemplate.setHashKeySerializer (keyRedisSerializer);
redisTemplate.setHashValueSerializer (valueRedisSerializer);
return redisTemplate;
}
}
Write a test service and its implementation class. There is no data in Redis that will be fished out of the database via DAO and then deposited into Redis
Public interface Cityservice {
/**
* Query City information based on City ID
*
* @param ID
* @return
*
* Findcitybyid (Long ID);
/**
* New city Information
*
* @param cities
* @return * *
/Long savecity;
/**
* Update city Information
*
* @param cities
* @return * *
/Long updatecity;
/**
* Delete City information based on City ID
*
* @param ID
* @return
*
/Long deletecity (long ID);
}
@Service public class Cityserviceimpl implements Cityservice {private static final Logger Logger = Loggerfactory.get
Logger (Cityserviceimpl.class);
private static final String City_redis_key_prefix = "City_";
@Autowired private Citydao Citydao;
@Autowired private Redistemplate redistemplate; /** * Get City Logic: * If the cache exists, get city information from the cache * If the cache does not exist, obtain city information from the DB, and then insert the cache */@Override public Cities FINDC
Itybyid (Long ID) {//Get city information from the cache String key = City_redis_key_prefix + ID;
Valueoperations<string, city> operations = Redistemplate.opsforvalue ();
The cache exists as a Boolean Haskey = Redistemplate.haskey (key);
if (Haskey) {City city = Operations.get (key);
Logger.info ("Cityserviceimpl.findcitybyid (): Get City >> from cache" + city.tostring ());
return city;
}//Get city information from DB urban = Citydao.findbyid (ID); Insert Cache Operations.set(Key, City, ten, timeunit.minutes);
Logger.info ("Cityserviceimpl.findcitybyid (): City Insert Cache >>" + city.tostring ());
return city;
}/** * Save city Information * @param cities * @return */@Override public Long savecity
Obtain city information from the DB, if it already exists, it is not in the save cities cityindb = Citydao.findbyid (City.getid ());
if (cityindb! = null) {return null;
} return Citydao.savecity (city); /** * Update City logic: * If the cache exists, delete * If the cache does not exist, do not operate */@Override public Long updatecity
{Long ret = citydao.updatecity (city);
Cache exists, delete cache String key = City_redis_key_prefix + City.getid ();
Boolean haskey = Redistemplate.haskey (key);
if (Haskey) {redistemplate.delete (key);
Logger.info ("cityserviceimpl.updatecity (): Remove City >> from cache" + city.tostring ());
} return ret; }/** * Delete City information * @param ID * @return */@Override public long deletecity (long id) {LONG ret = Citydao.deleteci
Ty (ID);
Cache exists, delete cache String key = City_redis_key_prefix + ID;
Boolean haskey = Redistemplate.haskey (key);
if (Haskey) {redistemplate.delete (key);
Logger.info ("cityserviceimpl.deletecity (): Remove the City ID >>" + ID from the cache);
} return ret; }
}
DAO class
Epublic interface Citydao {
/**
* Get a list of city information *
* @return *
/list<city> findallcity ();
/**
* For city information *
* @param ID * @return */city
FindByID (@Param ("id") Long ID);
/** *
Save city Information
* @param cities
* @return * *
/Long savecity;
/** *
Change city Information
* @param cities
* @return * *
/Long updatecity;
/** *
Delete city information
* @param ID
* @return
*
/Long deletecity (long id);
}
Write a test controller.
@RestController
public class CityRestController {
@Autowired
private CityService cityService;
@RequestMapping (value = "/ api / city / {id}", method = RequestMethod.GET)
public City findOneCity (@PathVariable ("id") Long id) {
return cityService.findCityById (id);
}
@RequestMapping (value = "/ api / city / create", method = RequestMethod.POST)
public void createCity (@RequestBody City city) {
cityService.saveCity (city);
}
@RequestMapping (value = "/ api / city", method = RequestMethod.PUT)
public void modifyCity (@RequestBody City city) {
cityService.updateCity (city);
}
@RequestMapping (value = "/ api / city / {id}", method = RequestMethod.DELETE)
public void modifyCity (@PathVariable ("id") Long id) {
cityService.deleteCity (id);
}
}