SpringBoot数据访问-------------数据缓存

Posted 没昵称可用

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot数据访问-------------数据缓存相关的知识,希望对你有一定的参考价值。

Spring缓存支持

  Spring开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术。Spring Cache的核心就是对某个方法进行缓存,其实质就是缓存该方法的返回结果,并把方法参数和结果用键值对的方式存放到缓存中,当再次调用该方法使用相应的参数时,就会直接从缓存里面取出指定的结果进行返回。所以在使用Cache的时候我们要保证我们缓存的方法对于相同的参数要有相同的返回结果。

  自定义缓存

  定义实体类

public class Account {
    private int id;
    private String name;
    public Account(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

  定义一个缓存管理器

import com.google.common.collect.Maps;
import java.util.Map;
public class CacheContext<T> {
    private Map<String, T> cache = Maps.newConcurrentMap();

    public T get(String key){
        return  cache.get(key);
    }
    public void addOrUpdateCache(String key,T value) {
        cache.put(key, value);
    }
    // 依据 key 来删除缓存中的一条记录
    public void evictCache(String key) {
        if(cache.containsKey(key)) {
            cache.remove(key);
        }
    }
    // 清空缓存中的全部记录
    public void evictCache() {
        cache.clear();
    }
}

  定义服务类

import com.google.common.base.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
@Service
public class AccountService1 {

    private final Logger logger = LoggerFactory.getLogger(AccountService1.class);

    @Resource
    private CacheContext<Account> accountCacheContext;

    public Account getAccountByName(String accountName) {
        Account result = accountCacheContext.get(accountName);
        if (result != null) {
            logger.info("get from cache... {}", accountName);
            return result;
        }

        Optional<Account> accountOptional = getFromDB(accountName);
        if (!accountOptional.isPresent()) {
            throw new IllegalStateException(String.format("can not find account by account name : [%s]", accountName));
        }

        Account account = accountOptional.get();
        accountCacheContext.addOrUpdateCache(accountName, account);
        return account;
    }

    public void reload() {
        accountCacheContext.evictCache();
    }

    private Optional<Account> getFromDB(String accountName) {
        logger.info("real querying db... {}", accountName);
        //Todo query data from database
        return Optional.fromNullable(new Account(accountName));
    }

}

Spring Cache

  注解                                  描述   

  @Cacheable                   在方法执行前Spring先查看缓存中是否有数据,如果有数据则直接返回缓存数据。反之调用方法并将方法返回值放入缓存填充。

  @CachePut                    无论缓存是否有数据,都会将方法的返回值放入缓存。 

  @CacheEvict                  将一条或多条数据从缓存中删除。

  @Caching                     组合多个注解策略在一个方法上。

  Spring Cache实例

package com.kingdee.service;

import java.util.Optional;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.kingdee.domains.Account;

@Service
public class AccountService {

	@Cacheable(value="accountCache")
	public Account getAccountByName(String accountName) {
		System.out.println("real querying account... "+accountName);
        // 方法内部实现不考虑缓存逻辑,直接实现业务
        Account accountOptional = getFromDB(accountName);
        return accountOptional;
    }
	@CacheEvict(value="accountCache",key="#account.getName()")
    public void updateAccount(Account account) {
        updateDB(account);
    }
	@CachePut(value="accountCache",key="#account.getName()")
	public Account updateAccount2(Account account){
		account.setName("bcd");
		System.out.println("========="+account.getName());
        return account;
	}
	private void updateDB(Account account) {
        System.out.println("real update db..."+account.getName());
    }
	private Account getFromDB(String accountName) {
        System.out.println("real querying db... "+accountName);
        Account account = new Account(accountName);
        return account;
    }
}

  Spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans
 xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:util="http://www.springframework.org/schema/util"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:task="http://www.springframework.org/schema/task"
 xmlns:rabbit="http://www.springframework.org/schema/rabbit"
 xmlns:cache="http://www.springframework.org/schema/cache"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                    http://www.springframework.org/schema/context
                    http://www.springframework.org/schema/context/spring-context-3.0.xsd
                    http://www.springframework.org/schema/mvc
                    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
                    http://www.springframework.org/schema/util
                    http://www.springframework.org/schema/util/spring-util-3.0.xsd
                    http://www.springframework.org/schema/task
                    http://www.springframework.org/schema/task/spring-task-3.0.xsd
                    http://www.springframework.org/schema/rabbit
                    http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd
                    http://www.springframework.org/schema/cache
           			http://www.springframework.org/schema/cache/spring-cache.xsd">

<context:component-scan base-package="com.kingdee"></context:component-scan>
<context:annotation-config/>
<cache:annotation-driven/>
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <set>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                    <property name="name" value="default"/>
                </bean>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                    <property name="name" value="accountCache"/>
                </bean>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
                    <property name="name" value="myCache"/>
                </bean>
            </set>
        </property>
    </bean>

</beans>

  测试

package com.kingdee;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.kingdee.domains.Account;
import com.kingdee.domains.User;
import com.kingdee.service.AccountService;
import com.kingdee.service.UserService;

public class CacheTest {

	public static void main(String[] args){
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application-beans.xml");
        AccountService accountService = context.getBean("accountService", AccountService.class);
        Account account = accountService.getAccountByName("abc");
        Account account2 = accountService.getAccountByName("abc");
        UserService userService = context.getBean("userService", UserService.class);
        User user = userService.findName("abc");
        System.out.println("==========="+user.getName());
        User user2 = userService.findName("abc");
        System.out.println("==========="+user2.getName());
	}
}

  注解详解

  缓存@Cacheable

  @Cacheable注解会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存。

@Cacheable(value = "emp" ,key = "targetClass + methodName +#p0")
    public List<NewJob> queryAll(User uid) {
        return newJobDao.findAllByUid(uid);
    }

  此处的value是必需的,它指定了你的缓存存放在哪块命名空间。

  此处的key是使用的spEL表达式,参考上章。这里有一个小坑,如果你把methodName换成method运行会报错,观察它们的返回类型,原因在于methodNameStringmethohMethod

  源码分析

String[] cacheNames() default {}; //和value注解差不多,二选一
String keyGenerator() default ""; //key的生成器。key/keyGenerator二选一使用
String cacheManager() default ""; //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器
String condition() default ""; //条件符合则缓存
String unless() default ""; //条件符合则不缓存
boolean sync() default false; //是否使用异步模式

  配置@CacheConfig

  当我们需要缓存的地方越来越多,你可以使用@CacheConfig(cacheNames = {"myCache"})注解来统一指定value的值,这时可省略value,如果你在你的方法依旧写上了value,那么依然以方法的value值为准。

@CacheConfig(cacheNames = {"myCache"})
public class BotRelationServiceImpl implements BotRelationService {
    @Override
    @Cacheable(key = "targetClass + methodName +#p0")//此处没写value
    public List<BotRelation> findAllLimit(int num) {
        return botRelationRepository.findAllLimit(num);
    }
    .....
}

  源码分析

String keyGenerator() default "";  //key的生成器。key/keyGenerator二选一使用
String cacheManager() default "";  //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器

  更新@CachePut

  @CachePut注解的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用 。简单来说就是用户更新缓存数据。但需要注意的是该注解的value 和 key 必须与要更新的缓存相同,也就是与@Cacheable 相同。示例:

@CachePut(value = "emp", key = "targetClass + #p0")
    public NewJob updata(NewJob job) {
        NewJob newJob = newJobDao.findAllById(job.getId());
        newJob.updata(job);
        return job;
    }

  源码分析

String[] cacheNames() default {}; //与value二选一
String keyGenerator() default "";  //key的生成器。key/keyGenerator二选一使用
String cacheManager() default "";  //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器
String condition() default ""; //条件符合则缓存
String unless() default ""; //条件符合则不缓存

  清除@CacheEvict

  @CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空 。

@CacheEvict(value="emp",key="#id")
    public void delect(int id) {
        newJobDao.deleteAllById(id);
    }

  源码分析

String[] cacheNames() default {}; //与value二选一
String keyGenerator() default "";  //key的生成器。key/keyGenerator二选一使用
String cacheManager() default "";  //指定缓存管理器
String cacheResolver() default ""; //或者指定获取解析器
String condition() default ""; //条件符合则清空

SpringBoot实例

  在Springboot运行时开启缓存支持

package com.kingdee;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@EnableCaching
public class App {

	public static void main(String[] args){
		SpringApplication.run(App.class);
	}
}

以上是关于SpringBoot数据访问-------------数据缓存的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot数据访问

SpringBoot数据访问

SpringBoot:Mybatis + Druid 数据访问

SpringBoot数据访问 SpringBoot整合JPA

SpringBoot与数据访问

SpringBoot1.x之数据访问