【Spring 】注解驱动的 Spring Cache

@Cacheable、@CachePut、@CacheEvict



①Spring配置文件

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

    <!--Test_Spring-->
    <bean id="helloWorld" class="com.cqh.Test_Spring.HelloWorld">
        <property name="name" value="Spring"/>
    </bean>

    <!--Cache_Spring-->
    <cache:annotation-driven />

    <bean id="accountServiceBean" class="com.cqh.Cache_Spring.AccountService"/>

    <!-- generic cache manager -->
    <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
        <property name="caches">
            <set>
                <bean
                        class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
                        p:name="default" />

                <bean
                        class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean"
                        p:name="accountCache" />
            </set>
        </property>
    </bean>

    </beans>

② 定义服务类

•	package com.cqh.Cache_Spring;

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

/**
 * Created by yl1794 on 2018/3/30.
 */
public class AccountService {

    // 当调用这个方法的时候,会从一个名叫accountCache的缓存中查询,如果有,返回缓存中的对象,不执行该方法了。
    // 如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中。
    @Cacheable(value="accountCache")
    public Account getAccountByName(String userName) {

        // 方法内部实现不考虑缓存逻辑,直接实现业务
        //TODO
        return getFromDB(userName);
    }

    // 基于SpEL表达式的condition定义,访问了参数 userName 对象的 length() 方法,条件表达式返回一个布尔值
    // 当条件为 true,则进行缓存操作,否则直接调用方法执行的返回结果。
    @Cacheable(value="accountCache", condition = "#userName.length()<=4")
    public Account getAccountByShortName(String userName) {

        // 方法内部实现不考虑缓存逻辑,直接实现业务
        //TODO
        return getFromDB(userName);
    }

    // 可以利用 SpEL 表达式对缓存 key 进行设计
    @Cacheable(value="accountCache",key="#userName.concat(#password)")
    public Account getAccountByNamePwd(String userName,String password,boolean sendLog) {

        // 方法内部实现不考虑缓存逻辑,直接实现业务
        //TODO
        return getFromDB(userName,password);
    }

    // CachePut可以确保方法被执行,同时方法的返回值也被记录到缓存中,主要用于数据新增和修改方法。
    @CachePut(value="accountCache",key="#account.getName()")//  更新 accountCache 缓存
    public Account updateAccount2(Account account) {
        return updateDB2(account);
    }

    @CacheEvict(value="accountCache",key="#account.getName()")// 清空 accountCache 缓存
    public void updateAccount(Account account) {
        updateDB(account);
    }

    @CacheEvict(value="accountCache",allEntries=true)// 清空 accountCache 缓存
    public void reload() {
    }

    // 从数据库查询
    private Account getFromDB(String acctName) {
        System.out.println("real querying db..."+acctName);
        Account account = new Account();
        account.setName(acctName);
        return account;
    }

    // 从数据库查询
    private Account getFromDB(String acctName, String password) {
        System.out.println("real querying db..."+acctName);
        Account account = new Account();
        account.setName(acctName);
        account.setPassword(password);
        return account;
    }

    // 更新数据库
    private void updateDB(Account account) {
        System.out.println("real update db..."+account.getName());
    }

    private Account updateDB2(Account account) {
        System.out.println("real updating db..."+account.getName());
        return account;
    }
}

③定义Account实体

package com.cqh.Cache_Spring;

/**
 * Created by yl1794 on 2018/3/30.
 */
public class Account {
    private int id;
    private String name;
    private String password;

    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;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

③  测试类

package com.cqh.Cache_Spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by yl1794 on 2018/3/30.
 */
public class Test_cache_spring {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "spring_config.xml");// 加载 spring 配置文件

        AccountService s = (AccountService) context.getBean("accountServiceBean");

        System.out.println("开始测试:缓存");
        // 第一次查询,应该走数据库
        System.out.println("first query:");
        s.getAccountByName("somebody");
        // 第二次查询,应该不查数据库,直接返回缓存的值
        System.out.println("second query:");
        s.getAccountByName("somebody");
        System.out.println();

        System.out.println("开始测试:清空缓存");
        //首先构造两个账号记录,然后记录到缓存中
        Account account1 = s.getAccountByName("somebody1");//走数据库
        Account account2 = s.getAccountByName("somebody2");//走数据库
        // 开始更新其中一个
        account1.setId(1212);
        s.updateAccount(account1);
        s.getAccountByName("somebody1");// 因为被更新了,所以走数据库
        s.getAccountByName("somebody2");// 没有更新过,应该走缓存
        s.getAccountByName("somebody1");// 再次查询,应该走缓存
        s.reload();                                // 更新所有缓存
        s.getAccountByName("somebody1");// 应该会查询数据库
        s.getAccountByName("somebody2");// 应该会查询数据库
        s.getAccountByName("somebody1");// 应该走缓存
        s.getAccountByName("somebody2");// 应该走缓存
        System.out.println();

        System.out.println("开始测试:按照条件操作缓存");
        s.getAccountByShortName("somebody3");// 长度大于 4,不会被缓存
        s.getAccountByShortName("sbd");      // 长度小于 4,会被缓存
        s.getAccountByShortName("somebody3");// 还是查询数据库
        s.getAccountByShortName("sbd");      // 会从缓存返回
        System.out.println();

        System.out.println("开始测试:如果有多个参数,如何进行 key 的组合");
        s.getAccountByNamePwd("somebody", "123456", true);// 应该查询数据库
        s.getAccountByNamePwd("somebody", "123456", true);// 应该走缓存
        s.getAccountByNamePwd("somebody", "123456", false);// 应该走缓存
        s.getAccountByNamePwd("somebody", "654321", true);// 应该查询数据库
        s.getAccountByNamePwd("somebody", "654321", true);// 应该走缓存
        System.out.println();

        System.out.println("开始测试:既要保证方法被调用,又希望结果被缓存");
        Account account = s.getAccountByName("someone");      // 应该查询数据库
        account.setPassword("123");
        s.updateAccount2(account);                                       // 更新数据库
        account.setPassword("321");
        s.updateAccount2(account);                                       // 更新数据库
        account = s.getAccountByName("someone");              // 应该走缓存
        System.out.println(account.getPassword());

    }
}

⑤ 结果












猜你喜欢

转载自blog.csdn.net/Mr_EvanChen/article/details/80283184