redis

Redis

键值对数据库,基于内存

 <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
<!-- 
        	apache通用连接池
        	提供了对可复用的对象(如数据库连接,线程等)的池化管理,有助于提高资源的利用率和系统的				   	性能   
        	使用commons-pool2来管理与Redis数据库的连接池
         -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

RedisTemplate

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

RedisTemplate是Spring Data Redis提供的一个强大的Redis操作模板,用于在Spring应用程序中与Redis数据库进行交互。对redis底层开发包(Jedis,JRedis,RJC)进行了一个封装,定义了五种数据结构的操作方法,异常处理,序列化,发布订阅

opsForValue():操作字符串。
opsForList():操作列表。
opsForHash():操作哈希。
opsForSet():操作集合。
opsForZSet():操作有序集合。
————————————————

Redis序列化

这个就跟它的序列化有关了。就是根据RedisTemplate将数据写入到redis中的时候会经过一个序列化操作,序列化操作后就变成了以上数据格式,这个并不影响程序,因为set写入时会有序列化操作,get获取数据时也就有着这么一个序列话操作,但是对于我们来说时很不友好的

如果不设置默认为JdkSerializationRedisSerializer

配置Redis序列化

redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);则键值对都为一样的序列化

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
        //实例化RedisTemplate
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        //设置连接工厂
        redisTemplate.setConnectionFactory(connectionFactory);

        //指定k,v的序列化方式(json)
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //默认序列化为json格式 key和值都序列化为json格式
      //  redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
        //key设置为String类型
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //value设置为Json格式
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);


        return redisTemplate;
    }

将java对象先转化为json数据在传入redis序列化


@Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        //实例化RedisTemplate
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        //设置连接工厂
        redisTemplate.setConnectionFactory(factory);

        //指定k,v的序列化方式(json)
        Jackson2JsonRedisSerializer<Object> redisSerializer= new Jackson2JsonRedisSerializer<>(Object.class);

        //将对象变为json进行传递
        ObjectMapper mapper=new ObjectMapper();
        //设置序列化的域,ANY表示所有域都序列化.PropertyAccessor.ALL:表示要配置所有的属性访问器,包括字段、getter、setter等。
        // JsonAutoDetect.Visibility.ANY:表示所有的属性都是可见的,不论其修饰符是什么,都将被序列化或反序列化。
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        redisSerializer.setObjectMapper(mapper);

        //key设置为String类型
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //value设置为Json格式
        redisTemplate.setValueSerializer(redisSerializer);

        //设置hash
        //redisTemplate.afterPropertiesSet();:这一行用于确保所有的配置都已经完成。在 Spring 中,afterPropertiesSet
        // 方法通常在 bean 的所有属性被设置之后调用,以确保 bean 处于一个有效的状态。
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(redisSerializer);
        redisTemplate.afterPropertiesSet();


        return redisTemplate;
    }

注解@EnableCaching 用于方法级别的缓存当应用使用缓存时候帮助Spirng自动配置缓存和管理缓存

注解通常与 CacheManager 一起使用,以定义缓存的配置和规则。@EnableCaching 注解可以在应用程序上下文中寻找 CacheManager 类型的 bean,并将其用于缓存管理。如果没有明确指定 CacheManager,Spring 将尝试使用合适的默认实现。

工具类对RedisTemplate的封装

redisTemplate.expire(key, time, TimeUnit.SECONDS);
  • redisTemplate: 这是 Spring Data Redis 中的一个模板类,提供了对 Redis 数据存储进行操作的方法。通常,你需要在应用程序中注入一个 RedisTemplate 实例,以便与 Redis 进行交互。
  • expire: 这是 Redis 中的命令,用于设置指定键的过期时间。一旦设置了过期时间,键将在一定时间后被自动删除。在这里,expireRedisTemplate 类中的一个方法,它接受三个参数:
    • key: 要设置过期时间的键。
    • time: 过期时间的时长,以整数形式表示。在这里,它是一个时间单位的数量,将在下一个参数 TimeUnit.SECONDS 中定义的时间单位内过期。
    • TimeUnit.SECONDS: 过期时间的时间单位。在这里,设置为秒(Seconds),表示 time 参数表示的时间单位是秒。
 @SuppressWarnings("unchecked")
    public void del(String ... key){
        if(key!=null&&key.length>0){
            if(key.length==1){
                redisTemplate.delete(key[0]);
            }else {
                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
            }
        }
    }

String... key 是 Java 中的可变参数(Varargs)语法。它允许你在方法调用时传递任意数量的字符串参数。在方法内部,这些参数被视为一个字符串数组。具体来说,String... key 表示一个名为 key 的字符串数组,可以接受零个或多个字符串参数。这样的语法使得在调用方法时可以以更自然的方式传递多个参数,而不需要手动创建数组。例子如下

public class Example {
    public static void main(String[] args) {
        printKeys("key1", "key2", "key3");
        printKeys(); // 也可以不传递任何参数
    }

    public static void printKeys(String... keys) {
        System.out.println("Number of keys: " + keys.length);
        for (String key : keys) {
            System.out.println("Key: " + key);
        }
    }
}

注解:@SuppressWarnings(“unchecked”) 它用于告诉编译器忽略特定类型转换的警告信息。在这个具体的情境下,它用于抑制未经检查的转换(unchecked conversion)的警告。

举例:

普通redis存入数据:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

List集合存入会成一张表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Redist缓存+Mysql


    //配置全局的序列化和redis缓存时间 以便注解使用
    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(cacheConfiguration)
                .build();
    }

可以手动在service中进行缓冲操作例子:

@Override
    public DemoUser findUserById(int id) {
        String key = "user_" + id;
        ValueOperations<String,DemoUser> operations = redisTemplate.opsForValue();
        //判断redis中是否有键为key的缓存
        boolean haskey = redisTemplate.hasKey(key);
        if (haskey){
            DemoUser user = operations.get(key);
            System.out.println("从缓存中获取的数据:"+user.getUserName());
            System.out.println("----------------------------------");
            return user;
        }else {
            DemoUser user = demoUserMapper.findUserById(id);
            System.out.println("查询数据库中的数据"+ user.getUserName());
            System.out.println("--------------------写入数据------------------");
            //写入数据
            operations.set(key,user,5, TimeUnit.HOURS);
            return user;
        }
    }

注解的方式:

开起注解缓存

@EnableCaching
查询数据缓存@Cacheable

将返回的结果进行缓冲到指定缓冲器中,如果缓存中有数据如果相同的参数被传递,可以直接返回缓存中的结果,而不必再次执行方法体。

1.value(或 cacheNames): 指定缓存的名称,可以指定一个或多个名称。多个名称之间使用逗号分隔。缓存的名称在整个应用程序中必须是唯一的。

2.key: 指定缓存的键。可以使用SpEL表达式来构造键。默认情况下,会使用方法的参数值作为键

@Cacheable(value = "myCache", key = "#userId")
public User getUserById(Long userId) {
    // ...
}

3.condition: 指定在满足条件的情况下才进行缓存。条件使用SpEL表达式

@Cacheable(value = “myCache”, condition = “#result != null”)

4.unless:condition 相反,指定在满足条件的情况下不进行缓存。同样使用SpEL

清除缓存**@CacheEvict**

@CacheEvict 注解用于从缓存中移除一个或多个缓存条目。通常在执行一些更新或删除操作后,为了保持缓存与数据的一致性,可以使用 @CacheEvict 注解清除相应的缓

1.value (cacheNames): 指定要清除的缓存的名称,可以指定一个或多个名称

2.key: 指定要清除的缓存的键。可以使用SpEL表达式来构造键。默认情况下,会使用方法的参数值作为键。

3.allEntries: 如果设置为 true,则清除缓存中的所有条目,忽略指定的键。默认值为 false

4.beforeInvocation: 如果设置为 true,则在方法执行之前清除缓存,即使方法执行出现异常。如果设置为 false,则在方法执行成功后才清除缓存。默认值为 false

5.condition: 指定在满足条件的情况下才执行缓存清除操作。条件使用SpEL表达式。

缓存更新**@CachePut**

@CachePut 注解用于将方法的返回值存储到缓存中。与 @Cacheable 注解不同,@CachePut 注解不会检查缓存中是否已经存在相同的键,而是直接将方法的结果存储到缓存中。这在更新缓存中的数据时非常有用。以下是 @CachePut 注解的主要属性和用法:

1.value (cacheNames): 指定缓存的名称,可以指定一个或多个名称。多个名称之间使用逗号分隔。缓存的名称在整个应用程序中必须是唯一的。

2.key: 指定缓存的键。可以使用SpEL表达式来构造键。默认情况下,会使用方法的参数值作为键。

3.condition: 指定在满足条件的情况下才执行缓存更新操作。条件使用SpEL表达式。

4.unless: 指定在满足条件的情况下不进行缓存更新。同样使用SpEL表达式。

@Caching

用于组合多个缓存注解。可以在一个方法上同时使用多个缓存注解

@Caching(
    cacheable = @Cacheable(value = "myCache", key = "#userId"),
    evict = @CacheEvict(value = "otherCache", key = "#result.email")
)
public User getUserById(Long userId) {
    // ...
}
@CacheConfig

用于在类级别配置缓存的公共属性,这样在方法级别的注解中可以省略一些重复的配置。

@Service
@CacheConfig(cacheNames = "myCache", keyGenerator = "customKeyGenerator")
public class UserService {

    @Cacheable(key = "#userId")
    public User getUserById(Long userId) {
        // ...
    }
}

案例
package edcu.com.demo.service.impl;


import edcu.com.demo.dao.SmbmsUserDao;
import edcu.com.demo.entity.SmbmsUser;
import edcu.com.demo.service.SmbmsUserService;

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

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

/**
 * (SmbmsUser)表服务实现类
 *
 * @author makejava
 * @since 2023-12-15 18:16:36
 */
@Service
public class SmbmsUserServiceImpl implements SmbmsUserService {
    @Resource
    private SmbmsUserDao smbmsUserDao;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */

    @Override
    @Cacheable(value = "smbmsUserCache", key = "#id")
    public SmbmsUser queryById(Long id) {
        // 如果缓存中存在数据,方法不会执行,直接返回缓存的数据
        // 如果缓存中不存在数据,方法会执行,并将结果放入缓存
        System.out.println("从数据库中查询数据");
        return this.smbmsUserDao.queryById(id);
    }

    /**
     * 分页查询
     *
     * @param smbmsUser 筛选条件
     * @param pageRequest      分页对象
     * @return 查询结果
     */
    @Override
    //@Cacheable(value ="smbmsUserCachePage", key =" 'ALL_' + #pageRequest.pageNumber") page反序列问题无法解决
    public Page<SmbmsUser> queryByPage(SmbmsUser smbmsUser, PageRequest pageRequest) {
        long total = this.smbmsUserDao.count(smbmsUser);
        return new PageImpl<>(this.smbmsUserDao.queryAllByLimit(smbmsUser, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param smbmsUser 实例对象
     * @return 实例对象
     */
    @Override
    @CachePut(value = "smbmsUserCache", key = "#smbmsUser.id")
    public SmbmsUser insert(SmbmsUser smbmsUser) {
        this.smbmsUserDao.insert(smbmsUser);
        updatePageCache();// 删除分页查询的缓存
        return smbmsUser;
    }

    /**
     * 修改数据
     *
     * @param smbmsUser 实例对象
     * @return 实例对象
     */
    @Override
    @CachePut(value = "smbmsUserCache", key = "#smbmsUser.id")
    public SmbmsUser update(SmbmsUser smbmsUser) {
        this.smbmsUserDao.update(smbmsUser);
        this.updatePageCache();// 删除分页查询的缓存
        return this.queryById(smbmsUser.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    @CacheEvict(value = "smbmsUserCache", key = "#id")
    public boolean deleteById(Long id) {
       this.updatePageCache();// 删除分页查询的缓存
        return this.smbmsUserDao.deleteById(id) > 0;
    }



    // 手动更新分页查询的缓存
    @CacheEvict(value = "smbmsUserCachePage", allEntries = true)
    public void updatePageCache() {
        System.out.println("手动更新分页查询的缓存");
        // 这里可以不做任何实际操作,@CacheEvict 注解会清空缓存,下次查询时会重新加载缓存
    }
}

ey = “#id”)
public boolean deleteById(Long id) {
this.updatePageCache();// 删除分页查询的缓存
return this.smbmsUserDao.deleteById(id) > 0;
}

// 手动更新分页查询的缓存
@CacheEvict(value = "smbmsUserCachePage", allEntries = true)
public void updatePageCache() {
    System.out.println("手动更新分页查询的缓存");
    // 这里可以不做任何实际操作,@CacheEvict 注解会清空缓存,下次查询时会重新加载缓存
}

}


  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值