Spring Boot used in cache

You can use caching techniques to save money in the program to the database. Spring Boot cache provides good support, we almost do not have to do too much configuration can be achieved using a variety of cache. This introduces more personal touch weekdays Ehcache and Redis cache implementation.

 

Ready to work

According using Mybatis.html Spring-Boot in build a project Spring Boot, yml then configure the log output levels to observe the implementation of SQL:

logging:
level:
  com:
    springboot:
      mapper: debug

 

Wherein com.spring.mapper is a MyBatis Mapper interface path.

Then write the following test methods:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest {

  @Autowired
  private StudentService studentService;
   
  @Test
  public void test() throws Exception {
      Student student1 = this.studentService.queryStudentBySno("001");
      System.out.println("学号" + student1.getSno() + "的学生姓名为:" + student1.getName());
       
      Student student2 = this.studentService.queryStudentBySno("001");
      System.out.println("学号" + student2.getSno() + "的学生姓名为:" + student2.getName());
  }
}

 

Right-run as junit test:

2017-11-17 16:34:26.535 DEBUG 9932 --- [main] c.s.m.StudentMapper.queryStudentBySno    : ==>  Preparing: select * from student where sno=? 
2017-11-17 16:34:26.688 DEBUG 9932 --- [main] c.s.m.StudentMapper.queryStudentBySno   : ==> Parameters: 001(String)
2017-11-17 16:34:26.716 DEBUG 9932 --- [main] c.s.m.StudentMapper.queryStudentBySno   : <==     Total: 1
学号001的学生姓名为:KangKang
2017-11-17 16:34:26.720 DEBUG 9932 --- [main] c.s.m.StudentMapper.queryStudentBySno   : ==> Preparing: select * from student where sno=?
2017-11-17 16:34:26.720 DEBUG 9932 --- [main] c.s.m.StudentMapper.queryStudentBySno   : ==> Parameters: 001(String)
2017-11-17 16:34:26.721 DEBUG 9932 --- [main] c.s.m.StudentMapper.queryStudentBySno   : <==     Total: 1
Student Name Student ID 001 is: KangKang

 

It can be found in the second query though, and the first query exactly the same, but it is still the database query. Then the introduction of caching to improve this result.

Use Cached

To open Spring Boot cache function, you need to be introduced in pom in the Spring-the Boot-Starter-Cache :

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

 

Spring Boot followed by the inlet class @EnableCaching annotation caching enabled features:

@SpringBootApplication
@EnableCaching
public class Application {
  public static void main(String[] args) {
      SpringApplication.run(Application.class,args);
  }
}

 

Adding annotations StudentService cache interface:

@CacheConfig(cacheNames = "student")
@Repository
public interface StudentService {
  @CachePut(key = "#p0.sno")
  Student update(Student student);
   
  @CacheEvict(key = "#p0", allEntries = true)
  void deleteStudentBySno(String sno);
   
  @Cacheable(key = "#p0")
  Student queryStudentBySno(String sno);
}

 

We join in StudentService interface of @CacheConfig notes, queryStudentBySno method uses annotations @Cacheable (key = "# P0") , is about to id as key values in redis. When we update the data should be used @CachePut (key = "# p0.sno" ) to update cached data, otherwise the query to dirty data, because the annotations are saved in the return value of the method, so there should return Student .

Its implementation class:

@Repository("studentService")
public class StudentServiceImpl implements StudentService{
  @Autowired
  private StudentMapper studentMapper;
   
  @Override
  public Student update(Student student) {
      this.studentMapper.update(student);
      return this.studentMapper.queryStudentBySno(student.getSno());
  }
   
  @Override
  public void deleteStudentBySno(String sno) {
      this.studentMapper.deleteStudentBySno(sno);
  }
   
  @Override
  public Student queryStudentBySno(String sno) {
      return this.studentMapper.queryStudentBySno(sno);
  }
}

 

Spring Boot cache annotations that can be used are:

Cache comment

  1. @CacheConfig : mainly used for some common configurations will be used in such cache configuration. Here @CacheConfig (cacheNames = "student") : Configure the contents of the data access object returned will be stored in the cache object named student, we can not use this comment by direct @Cacheable configure the cache set their own name is defined;

  2. @Cacheable : Configure queryStudentBySno function return value is added to the cache. At the same time, it gets the start in the query cache, if there was further initiate access to the database. The notes there are several parameters of the following:

    • value , cacheNames : two identical parameters (cacheNames Spring 4 is added, as the value of an alias) for storing the specified cache set name. Since Spring 4 added a @CacheConfig , and therefore had to be some value property, it has become a non-essential item in 3 Spring;

    • key : the key value stored in the Map cache object set, the non-essential, all in accordance with the default parameter combinations as a function of a key value, when the need to use their allocation SpEL expression, such as: @Cacheable (key = "# P0") : using the first parameter as a function of cache key values, more detailed information about the expression SpEL refer https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache ;

    • for condition Condition : condition cached objects, non-essential, also need to use SpEL expression, only to meet the conditions of the content of the expression will be cached, such as: @Cacheable (Key = "# P0", for condition Condition = "# p0.length () <3 ") , it indicates the length only when the first parameter is less than 3 are cached;

    • The unless : another cache condition parameter, nonessential, use SpEL expression. Where it differs from it in that condition parameter determination timing, the determination conditions is done only after the function is called, it can judge the result;

    • keyGenerator : specifies the key generator, non-essential. If you specify a custom key generator, we need to realize org.springframework.cache.interceptor.KeyGenerator interface and uses the specified parameter;

    • CacheManager : Used to specify which cache manager, non-essential. Only when there is more need to use only;

    • cacheResolver : Used to specify that the Caching Resolver, non-essential. Required to realize its own cache by org.springframework.cache.interceptor.CacheResolver parser interface specified by the parameter and;

  3. @CachePut : disposed on the function, can be cached in accordance with the parameters defined conditions, the cache is the return value of the method, it @Cacheable is different, it is true every time the function is called, and it is mainly used for new data modify the operation. Its parameters @Cacheable Similarly, the specific function can refer to the face @Cacheable resolution parameters;

  4. @CacheEvict : disposed on the function, usually used in the deletion method for removing corresponding data from the cache. In addition to the same @Cacheable than the same parameters, it also has the following two parameters:

    • allEntries : non-essential, the default is false. When is true, it removes all data;

    • beforeInvocation : non-essential, the default is false, the data will be removed after calling method. When true, the data will be removed before calling the method.

Cache implementation

To use the Spring Boot cache function, but also need to provide a concrete implementation cached. Spring Boot according to the following order to detect the cache implementation:

  • Generic

  • JCache (JSR-107)

  • ehcache 2.x

  • Hazelcast

  • Infinispan

  • Redis

  • Guava

  • Simple

In addition to detecting the order, we can also be forced to specify the configuration properties spring.cache.type.

Next we focus on Redis and Ehcache cache implementation.

Redis

Download Redis is https://github.com/MicrosoftArchive/redis/releases , Redis supports 32-bit and 64-bit. This according to the actual circumstances of your system platform selection, here we Redis-x64-xxx.zip download archive to the C drive. CMD open a window, enter the following:

C:\Users\Administrator>cd c:\Redis-x64-3.2.100

c:\Redis-x64-3.2.100>redis-server.exe redis.windows.conf
              _._
          _.-``__ ''-._
    _.-``   `. `_. ''-._           Redis 3.2.100 (00000000/0) 64 bit
.-`` .-```. ```\/   _.,_ ''-._
(   '     ,       .-` | `,   )     Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
|   `-._   `._   /     _.-'   |     PID: 6404
`-._   `-._ `-./ _.-'   _.-'
|`-._`-._   `-.__.-'   _.-'_.-'|
|   `-._`-._       _.-'_.-'   |           http://redis.io
`-._   `-._`-.__.-'_.-'   _.-'
|`-._`-._   `-.__.-'   _.-'_.-'|
|   `-._`-._       _.-'_.-'   |
`-._   `-._`-.__.-'_.-'   _.-'
    `-._   `-.__.-'   _.-'
        `-._       _.-'
            `-.__.-'

[6404] 25 Dec 09:47:58.890 # Server started, Redis version 3.2.100
[6404] 25 Dec 09:47:58.898 * DB loaded from disk: 0.007 seconds
[6404] 25 Dec 09:47:58.898 * The server is now ready to accept connections on port 6379

 

Then open another terminal CMD, type:

C:\Users\Administrator>cd c:\Redis-x64-3.2.100

c:\Redis-x64-3.2.100>redis-cli.exe -p 6379
127.0.0.1:6379>

 

After the preparatory work done, then began to introduce Redis project in the Spring Boot:

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

 

Redis configuration in application.yml in:

Spring: 
Redis:
  # the Redis database indexes (default 0)
  Database: 0
  # the Redis server address
  Host: localhost
  # the Redis server port
  Port: 6379
  the pool:
    # connection pool maximum number of connections (negative values no limit)
    max-Active : 8
    # latency connection pool maximum blocking (negative values no limit)
    max the wait-: -1
    # connection pool maximum idle connection
    max-idle: 8
    minimum idle connection pool connection #
    min-iDLE: 0
  # connection time (ms)
  timeout: 0

 

More on Spring Boot Redis configuration, see: https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html# Redis

Then create a Redis configuration class:

@Configuration
public class RedisConfig extends CachingConfigurerSupport {

  // 自定义缓存key生成策略
  @Bean
  public KeyGenerator keyGenerator() {
      return new KeyGenerator() {
          @Override
          public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
              StringBuffer sb = new StringBuffer();
              sb.append(target.getClass().getName());
              sb.append(method.getName());
              for (Object obj : params) {
                  sb.append(obj.toString());
              }
              return sb.toString();
          }
      };
  }

  // cache manager
  @Bean
  public CacheManager the CacheManager (@SuppressWarnings ( "rawtypes") RedisTemplate redisTemplate) {
      RedisCacheManager CacheManager = new new RedisCacheManager (redisTemplate);
      // set the cache expiration time (in seconds)
      cacheManager.setDefaultExpiration (3600);
      return CacheManager ;
  }   @Bean   public redisTemplate <String, String> redisTemplate (RedisConnectionFactory Factory) {       StringRedisTemplate Template = new new StringRedisTemplate (Factory);       setSerializer (Template); // set the serial tool       template.afterPropertiesSet ();       return Template;   }









  private void setSerializer(StringRedisTemplate template) {
      @SuppressWarnings({ "rawtypes", "unchecked" })
      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);
  }
}

 

Test run, the console output:

18 2017-11-17: 17: 06.995 DEBUG 8836 --- [main] csmStudentMapper.queryStudentBySno: ==> the Preparing: the SELECT * Student from the WHERE SnO =? 
2017-11-17 18: 17: 07.128 DEBUG 8836 --- [main] csmStudentMapper.queryStudentBySno: ==> the Parameters: 001 (String)
2017-11-17 18: 17: 07.152 DEBUG 8836 --- [main] csmStudentMapper.queryStudentBySno: <== Total: 1
student number 001 students name is: KangKang
school student names No. 001 was: KangKang

 

The second query does not access the database, but retrieved from the cache to see if the value in the redis:

127.0.0.1:6379>   keys *
1) "student~keys"
2) "001"
127.0.0.1:6379> get 001
"[\"com.springboot.bean.Student\",{\"sno\":\"001\",\"name\":\"KangKang\",\"sex\":\"M \"}]"

 

In the test method Test Update:

@Test 
public void Test () throws Exception {
  Student student1 = this.studentService.queryStudentBySno ( "001");
  System.out.println ( "student number" + student1.getSno () + "student name is:" + student1 .getName ());   student1.setName ( "Kang Kang");   this.studentService.update (student1);   Student STUDENT2 = this.studentService.queryStudentBySno ( "001");   System.out.println ( "study" + student2.getSno () + "student's name is:" + student2.getName ()); }
   


   


 

Console output:

学号001的学生姓名为:KangKang
2017-11-17 19:30:05.813 INFO 11244 --- [main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
2017-11-17 19:30:05.823 DEBUG 11244 --- [main] c.s.mapper.StudentMapper.update         : ==> Preparing: update student set sname=?,ssex=? where sno=?
2017-11-17 19:30:05.941 DEBUG 11244 --- [main] c.s.mapper.StudentMapper.update         : ==> Parameters: 康康(String), M (String), 001(String)
2017-11-17 19:30:05.953 DEBUG 11244 --- [main] c.s.mapper.StudentMapper.update         : <==   Updates: 1
2017-11-17 19:30:05.957 DEBUG 11244 --- [main] c.s.m.StudentMapper.queryStudentBySno   : ==> Preparing: select * from student where sno=?
. 19 2017-11-17: 30: 05.959 11244 --- the DEBUG [main] csmStudentMapper.queryStudentBySno: ==> the Parameters: 001 (String)
2017-11-17. 19: 30: 05.976 11244 --- the DEBUG [main] csmStudentMapper .queryStudentBySno: <== Total: 1
student number 001 names of the students is: Kankan

 

Check in redis in:

127.0.0.1:6379> get 001
"[\"com.springboot.bean.Student\",{\"sno\":\"001\",\"name\":\"\xe5\xba\xb7\xe5\xba\xb7\",\"sex\":\"M \"}]"

 

Visible to update the database at the same time, the cache has been updated.

Source link: https://github.com/wuyouzhuguli/Spring-Boot-Demos/tree/master/09.Spring-Boot-Redis-Cache

ehcache

Ehcache dependent on the introduction of:

<!-- ehcache -->
<dependency>
  <groupId>net.sf.ehcache</groupId>
  <artifactId>ehcache</artifactId>
</dependency>

 

New ehcache.xml in src / main / resources directory:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="ehcache.xsd">
  <defaultCache
      maxElementsInMemory="10000"
      eternal="false"
      timeToIdleSeconds="3600"
      timeToLiveSeconds="0"
      overflowToDisk="false"
      diskPersistent="false"
      diskExpiryThreadIntervalSeconds="120" />

  <cache
      name="student"
      maxEntriesLocalHeap="2000"
      eternal="false"
      timeToIdleSeconds="3600"
      timeToLiveSeconds="0"
      overflowToDisk="false"
      statistics="true"/>
</ehcache>

 

Some instructions on Ehcahe of:

  • name: the name of the cache.

  • maxElementsInMemory: The maximum number of cache

  • maxElementsOnDisk: The maximum number of hard disk cache.

  • eternal: object is permanent, but a set, timeout will not work.

  • overflowToDisk: whether to save to disk.

  • timeToIdleSeconds: Set target idle time allowed before failure (unit: seconds). Only when eternal = false objects is not a permanent use, optional attributes, the default value is 0, that is, the idle time may be infinity.

  • timeToLiveSeconds: Set object allows survival time before failure (unit: seconds). The maximum time between failure time and time of creation. Only when eternal = false when the object is not permanent and effective use, the default is 0, that is, the survival time of the object to infinity.

  • diskPersistent: whether to cache the virtual machine restart of the data, the default value is false.

  • diskSpoolBufferSizeMB: This parameter sets the size of the buffer DiskStore (disk cache) of. The default is 30MB. Each Cache should have a buffer of its own.

  • diskExpiryThreadIntervalSeconds: disk fails thread run intervals, the default is 120 seconds.

  • memoryStoreEvictionPolicy: When reached maxElementsInMemory limit, Ehcache will go to clean up the memory according to the specified policy. The default policy is LRU (least recently used). You can set FIFO (First In First Out) or LFU (rarely used).

  • clearOnFlush: whether to remove the maximum amount of memory.

  • memoryStoreEvictionPolicy: Ehcache emptied three strategies: the FIFO , First in First OUT, this is our most familiar, FIFO. LFU , Less Frequently Used, is the strategy used in the above example, bluntly say that has been least used. As above, say, the element has a cache hit attribute, the cache hit value will be cleared minimal. The LRU , Least Recently Logs in Used, the least recently used cache element has a time stamp, when the cache capacity is full, but need to make room for the new cache element, then the existing cache element in the timestamp from the current time farthest element will be cleared cache.

Next ehcache arranged in the path specified in application.yml:

spring:
cache:
  ehcache:
    config: 'classpath:ehcache.xml'

 

So you can start using ehcache, and run the test class, watch the console:

09 2017-11-18: 10: 40.201 DEBUG 3364 --- [main] csmStudentMapper.queryStudentBySno: ==> the Preparing:? The SELECT * Student from the WHERE SnO = 
2017-11-18 09: 10: 40.343 DEBUG 3364 --- [main] csmStudentMapper.queryStudentBySno: ==> the Parameters: 001 (String)
2017-11-18 09: 10: 40.364 DEBUG 3364 --- [main] csmStudentMapper.queryStudentBySno: <== Total: 1
student number 001 students name is: KangKang
school student names No. 001 was: KangKang

 

The second can be seen is obtained from the cache.

Test update:

2017-11-18 09:18:04.230 DEBUG 11556 --- [main] c.s.m.StudentMapper.queryStudentBySno    : ==>  Preparing: select * from student where sno=? 
2017-11-18 09:18:04.397 DEBUG 11556 --- [main] c.s.m.StudentMapper.queryStudentBySno   : ==> Parameters: 001(String)
2017-11-18 09:18:04.427 DEBUG 11556 --- [main] c.s.m.StudentMapper.queryStudentBySno   : <==     Total: 1
学号001的学生姓名为:KangKang
2017-11-18 09:18:04.433 DEBUG 11556 --- [main] c.s.mapper.StudentMapper.update         : ==> Preparing: update student set sname=?,ssex=? where sno=?
2017-11-18 09:18:04.438 DEBUG 11556 --- [main] c.s.mapper.StudentMapper.update         : ==> Parameters: 康康(String), M (String), 001(String)
2017-11-18 09:18:04.440 DEBUG 11556 --- [main] c.s.mapper.StudentMapper.update         : <==   Updates: 1
2017-11-18 09:18:04.440 DEBUG 11556 --- [main] c.s.m.StudentMapper.queryStudentBySno   : ==> Preparing: select * from student where sno=?
2017-11-18 09:18:04.441 DEBUG 11556 --- [main] c.s.m.StudentMapper.queryStudentBySno   : ==> Parameters: 001(String)
2017-11-18 09:18:04.442 DEBUG 11556 --- [main] c.s.m.StudentMapper.queryStudentBySno   : <==     Total: 1
学号001的学生姓名为:康康

 

Visible, even if the update method added @CachePut notes, the second query because the Student object is updated, and it is to obtain data from the database, so for Ehcache, the update method plus without @CachePut notes, the results are the same.

Guess you like

Origin www.cnblogs.com/7788IT/p/11626845.html