本文介绍: 对于使用@Cacheable标注方法,Spring在每次执行前都会检查Cache是否存在相同key缓存元素,如果存在就不再执行方法,而是直接缓存获取结果进行返回,否则才会执行并将返回结果存入指定缓存中。@Caching注解作用是将多个缓存注解组合在一起,作为一个缓存操作配置信息。MyBatis的一级缓存是指在同一个SqlSession中,多次执行同一个查询语句,第一次执行后查询结果会被缓存内存中,后续执行同一个查询语句时,会直接缓存获取结果,而不会再次向数据库发送查询请求

1. 作用

相关知识点 — 关于mybatis的一级缓存

MyBatis的一级缓存是指在同一个SqlSession中,多次执行同一个查询语句,第一次执行后查询结果会被缓存内存中,后续执行同一个查询语句时,会直接从缓存中获取结果,而不会再次向数据库发送查询请求。

一级缓存是MyBatis默认开启的,它的实现方式是将缓存存储在SqlSession对象中。当SqlSession执行查询操作时,查询结果会被存储一个HashMap对象中,该HashMap对象作用域当前SqlSession对象

一级缓存的生命周期与SqlSession对象生命周期一样长,当SqlSession对象被关闭提交事务时,一级缓存也会被清空

一级缓存是针对同一个SqlSession对象的,不同的SqlSession对象之间的缓存是互相独立的。

如果需要禁用一级缓存,可以在SqlSession执行查询操作调用SqlSessionclearCache()方法清空缓存

2. 集成

2.1 导入需要的包

包括jedisspringdataredis以及jackson(在将对象序列化保存redis需要

2.2 redis属性配置文件

redis属性配置文件放在resources目录

#访问地址
redis.host=192.168.62.147
#访问端口
redis.port=6379
#注意,如果没有password,此处不设置值,但这一项要保留
#redis.password=

#最大空闲数,数据库连接最大空闲时间。超过空闲时间数据库连接将被标记不可用,然后被释放。设为0表示限制redis.maxIdle=300
#连接池最大数据库连接数。设为0表示无限制
redis.maxTotal=600
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制redis.maxWaitMillis=1000
#在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的;
redis.testOnBorrow=true

2.3 springredis集成配置

2.3.1 xml方式

xml配置文件放在resources目录下,已applicationContextredis.xml命名

<?xml version="1.0" encoding="UTF-8"?&gt;
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
       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/cache http://www.springframework.org/schema/cache/spring-cache.xsd"&gt;

    <!-- 连接池基本参数配置,类似数据库连接池 --&gt;
    <context:property-placeholder location="classpath:redis.properties"
                                  ignore-unresolvable="true" />

    <!-- redis连接池 -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.maxTotal}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>

    <!-- 连接配置,类似数据库连接池 -->
    <bean id="jedisConnectionFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.host}"></property>
        <property name="port" value="${redis.port}"></property>
        <!-- <property name="password" value="${redis.pass}"></property> -->
        <property name="poolConfig" ref="poolConfig"></property>
    </bean>

    <!--redis操作模版,使用该对象可以操作redis  -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
        <property name="connectionFactory" ref="jedisConnectionFactory" />
        <!--如果不配置Serializer,那么存储时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!!  -->
        <property name="keySerializer" >
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer" >
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
        </property>
        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
        </property>
        <!--开启事务  -->
        <property name="enableTransactionSupport" value="true"></property>
    </bean >

    <!-- 启用缓存 -->
    <cache:annotation-driven cache-manager="cacheManager"/>

    <!-- 声明reids缓存管理器 -->
    <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
        <constructor-arg index="0" ref="redisTemplate"></constructor-arg>
        <!-- 用于指明过期时间 -->
        <!--<property name="expires">
            <map>
                <entry key="students" value="#{60*2}"/>
            </map>
        </property>-->

    </bean>
    
    <bean id="customKeyGenerator" 
class="com.zking.mybatisdemo.config.CustomKeyGenerator"/>

</beans>

2.3.2 程序方式配置

源码中,可以新建一个config的包,用于放置配置相关的java文件

@Configuration
@EnableCaching
public class CacheConfig {


    private static final Logger log = LoggerFactory.getLogger(CacheConfig.class);


    @Bean
    public JedisConnectionFactory redisConnectionFactory() throws IOException {

        ClassPathResource resource = new ClassPathResource("/redis.properties");
        InputStream in = resource.getInputStream();
        Properties prop = new Properties();
        prop.load(in);

        String host = prop.getProperty("redis.host");
        Integer port = Integer.valueOf(prop.getProperty("redis.port"));
        Integer maxIdle = Integer.valueOf(prop.getProperty("redis.maxIdle"));
        Integer maxTotal = Integer.valueOf(prop.getProperty("redis.maxTotal"));
        Integer maxWaitMillis = Integer.valueOf(prop.getProperty("redis.maxWaitMillis"));
        boolean testOnBorrow =  Boolean.valueOf(prop.getProperty("redis.testOnBorrow"));

        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(maxIdle);
        poolConfig.setMaxTotal(maxTotal);
        poolConfig.setMaxWaitMillis(maxWaitMillis);
        poolConfig.setTestOnBorrow(testOnBorrow);

        JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
        redisConnectionFactory.setHostName(host);
        redisConnectionFactory.setPort(port);
        redisConnectionFactory.setPoolConfig(poolConfig);

        return redisConnectionFactory;
    }


    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory cf) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(cf);

        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        return redisTemplate;
    }


    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(factory);
        return stringRedisTemplate;
    }


    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        //这里可以设置一个默认过期时间
        cacheManager.setDefaultExpiration(300);
        return cacheManager;
    }

    @Bean
    public KeyGenerator customKeyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(o.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

}

3. 使用示例

常用注解

3.1 @Cacheable

3.1.1 通过指定key,将查询结果缓存到redis中

@Service
public class StudentService implements IStudentService {

    @Resource
    private StudentMapper studentMapper;

    @Cacheable(value = "students",key = "#student.toString()")
    @Override
    public List<Student> list(Student student) {
        return studentMapper.list(student);
    }

}
属性 描述 示例
methodName 当前方法名 #root.methodName
method 当前方法 #root.method.name
target 当前调用的对象 #root.target
targetClass 当前调用的对象的class #root.targetClass
args 当前方法参数组成的数组 #root.args[0]
result 获取方法的返回值 #result.id 表示获取返回值中的id属性的值

3.1.2 配置key生成策略

1) xml配置文件方式

编写自定义key生成器

public class CustomKeyGenerator implements KeyGenerator {

    @Override
    public Object generate(Object target, Method method, Object... params) {
        StringBuilder sb = new StringBuilder();
        sb.append(target.getClass().getName());
        sb.append(method.getName());
        for (Object obj : params) {
            sb.append(obj.toString());
        }
        return sb.toString();
    }
}
    <!-- 启用注解式缓存 -->
    <cache:annotation-driven cache-manager="cacheManager" key-generator="customKeyGenerator"/>
    
    <!--自定义key生成器-->
    <bean id="customKeyGenerator" class="com.zking.mybatisdemo.config.CustomKeyGenerator"/>

2) java配置方式

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    private static final Logger log = LoggerFactory.getLogger(CacheConfig.class);

    ......

    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        //这里可以设置一个默认过期时间
        cacheManager.setDefaultExpiration(300);
        return cacheManager;
    }

    @Bean(name="customKeyGenerator")
    public KeyGenerator customKeyGenerator() {
        return new CustomKeyGenerator();
    }

    //配置自定义key生成器
    @Override
    public KeyGenerator keyGenerator() {
        return new CustomKeyGenerator();
    }

}

注意: 该类必须继承CachingConfigurerSupport类,并重写其中的keyGenerator方法。

配置默认生成策略后,如果没有指定key,则使用默认的生成策略, 如:

    @Cacheable(value = "students")
    @Override
    public List<Student> list(Student student) {
        return studentMapper.list(student);
    }

3) 除默认key生成策略外,还可以指定key,或指定生成策略,如果一下示例:

    @Cacheable(value = "students", key = "'sname:' + #student.sname")
    @Override
    public List<Student> list(Student student) {
        return studentMapper.list(student);
    }

    @Override
    @Cacheable(value="student",keyGenerator = "customKeyGenerator")
    public Student load(String sid) {
        return studentMapper.load(Integer.valueOf(sid));
    }

3.1.3 condition

只对学生名称以“李”字开发的的查询执行缓存,否则不进行缓存, 代码如下

    @Cacheable(value = "students", key = "'sname:' + #student.sname", condition = "#student.sname.equals('李')")
    @Override
    public List<Student> list(Student student) {
        return studentMapper.list(student);
    }

可以使用unless参数否决向缓存添加值。

3.2 @CacheEvict

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

示例:

    @Override
    @Cacheable(value="student", key="#sid.toString()")
    public Student load(Integer sid) {
        return studentMapper.load(sid);
    }


    @CacheEvict(value="student", key="T(Integer).toString(#student.sid)")
    //@CacheEvict(value="student", key="#student.sid + ''")
    @Override
    public void update(Student student) {
        studentMapper.update(student);
    }

测试代码

    @Test
    public void load() {
        Student student = studentService.load(197);
        System.out.println(student);
    }

    @Test
    public void update() {
        Student student = new Student();
        student.setSid(197);
        student.setSname("曹雪学");
        student.setAge(56);
        student.setRemark("测试");
        studentService.update(student);
    }

运行load测试, 会将sid为197的学生信息缓存,然后再运行update,会将sid为197的学习信息从缓存中删除

使用allEntries属性从缓存中退出所有条目。如下示例:

    @CacheEvict(cacheNames="books", allEntries=true)
    @Override
    public void update(Student student) {
        studentMapper.update(student);
    }

清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素
示例:

@CacheEvict(value="users", beforeInvocation=true)

3.3 @CachePut

对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

示例:

    @Override
    //@Cacheable(value="student", key="#sid.toString()")
    @CachePut(value = "student", key="#sid.toString()")
    public Student load(Integer sid) {
        return studentMapper.load(sid);
    }

注意: @CachePut 与 @Cacheable 之间的差别,@CachePut不会去检查缓存中是否有值, 每次都会通过获取获取数据填充到缓存中去。

3.4 @Caching

@Caching注解可以作为一个容器注解用于组合多个缓存注解实现多个缓存操作在一个方法中的统一配置

@Caching注解作用是将多个缓存注解组合在一起,作为一个缓存操作的配置信息。例如,一个方法需要在缓存中查询一个对象,如果找到了就返回,否则从数据库中查询并将结果存储到缓存中。这个操作可以通过@Caching注解实现如下所示
示例代码如下


@Caching(
    cacheable = {
        @Cacheable(value = "myCache", key = "#id")
    },
    put = {
        @CachePut(value = "myCache", key = "#id"),
        @CachePut(value = "myOtherCache", key = "#result.name")
    }
)
public MyObject findMyObjectById(String id) {
    // ...
}

在上面的示例中,@Caching注解包含两个缓存操作:@Cacheable和@CachePut。@Cacheable注解用于从缓存中查询MyObject对象,@CachePut注解用于将MyObject对象存储到缓存中。同时,@CachePut注解还配置了将MyObject对象的name属性作为key存储到另一个缓存中(myOtherCache)

3.5 @CacheConfig

缓存提供了许多的注解选项,但是有一些公用的操作,我们可以使用@CacheConfig在类上进行全局设置。

@CacheConfig(keyGenerator = "customKeyGenerator")
public class StudentService implements IStudentService {
    
    @Cacheable(value = "students")
    @Override
    public List<Student> list(Student student) {
        return studentMapper.list(student);
    }
    ....
 }

原文地址:https://blog.csdn.net/qq_73126462/article/details/134784406

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_38700.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注