天津企业免费建站,旅游景区网站建设策划书,无锡网站优化建站,wordpress 强制登录一文涵盖所有工作中遇到的redis操作#xff0c;让你从此学会redis
本文会从基础篇到进阶篇#xff0c;逐步来讲解redis和springboot的整合#xff0c;如何去操作#xff0c;以及他的作用。让你学会使用redis#xff0c;爱上使用redis。
介绍redis
首先我们来介绍一下re…一文涵盖所有工作中遇到的redis操作让你从此学会redis
本文会从基础篇到进阶篇逐步来讲解redis和springboot的整合如何去操作以及他的作用。让你学会使用redis爱上使用redis。
介绍redis
首先我们来介绍一下redis NoSQL 数据库 redis是一个
key - value 存储系统区别于 MySQL他存储的是键值对
之后我们来看
redis的数据结构
String 字符串类型 name: “xiaou”
List 列表names: [“xiaou”, “dogxiaou”, “xiaou”]
Set 集合names: [“xiaou”, “dogxiaou”]值不能重复
Hash 哈希nameAge: { “xiaou”: 1, “dogxiaou”: 2 }
Zset 集合names: { xiaou - 9, dogxiaou - 12 }适合做排行榜
bloomfilter布隆过滤器主要从大量的数据中快速过滤值比如邮件黑名单拦截
geo计算地理位置
hyperloglogpv / uv
pub / sub发布订阅类似消息队列
BitMap 1001010101010101010101010101
如何与java整合
Spring Data Redis推荐
Spring Data通用的数据访问框架定义了一组 增删改查 的接口
mysql、redis、jpa
spring-data-redis
Jedis
独立于 Spring 操作 Redis 的 Java 客户端
要配合 Jedis Pool 使用
Lettuce
高阶 的操作 Redis 的 Java 客户端
异步、连接池
Redisson
分布式操作 Redis 的 Java 客户端让你像在使用本地的集合一样操作 Redis分布式 Redis 数据网格
JetCache
对比
如果你用的是 Spring并且没有过多的定制化要求可以用 Spring Data Redis最方便如果你用的不是 SPring并且追求简单并且没有过高的性能要求可以用 Jedis Jedis Pool如果你的项目不是 Spring并且追求高性能、高定制化可以用 Lettuce支持异步、连接池 如果你的项目是分布式的需要用到一些分布式的特性比如分布式锁、分布式集合推荐用 redisson
之后我们来介绍一下redis的基础操作
redis基础操作
这里我们选用的是spring-boot-starter-data-redis
首先我们在本机上开启redis双击运行server这个就可以 看到这个就代表着redis已经成功运行了 之后来看maven的依赖
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd!-- author a hrefhttps://github.com/liyupi程序员鱼皮/a --!-- from a hrefhttps://yupi.icu编程导航知识星球/a --modelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.6.4/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.xiaou/groupIdartifactIdxiaou-backend/artifactIdversion0.0.1-SNAPSHOT/versionnamexiaou-backend/namedescriptionxiaou-backend/descriptionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency
!-- dependency--
!-- groupIdorg.mybatis.spring.boot/groupId--
!-- artifactIdmybatis-spring-boot-starter/artifactId--
!-- version2.2.2/version--
!-- /dependency--
!-- dependency--
!-- groupIdcom.baomidou/groupId--
!-- artifactIdmybatis-plus-boot-starter/artifactId--
!-- version3.5.1/version--
!-- /dependency--!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactIdversion3.12.0/version/dependencydependencygroupIdorg.apache.commons/groupIdartifactIdcommons-collections4/artifactIdversion4.4/version/dependencydependencygroupIdcom.google.code.gson/groupIdartifactIdgson/artifactIdversion2.8.9/version/dependency!-- dependency--
!-- groupIdmysql/groupId--
!-- artifactIdmysql-connector-java/artifactId--
!-- scoperuntime/scope--
!-- /dependency--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependency!-- swagger--dependencygroupIdcom.github.xiaoymin/groupIdartifactIdknife4j-openapi2-spring-boot-starter/artifactIdversion4.4.0/version/dependency!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactIdversion2.6.4/version/dependency!-- lt;!ndash; https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis ndash;gt;--dependencygroupIdorg.springframework.session/groupIdartifactIdspring-session-data-redis/artifactIdversion2.6.3/version/dependency!-- dependency--
!-- groupIdorg.redisson/groupId--
!-- artifactIdredisson/artifactId--
!-- version3.27.1/version--
!-- /dependency--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency!-- https://mvnrepository.com/artifact/junit/junit --dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.13.2/versionscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationexcludesexcludegroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/exclude/excludes/configuration/plugin/plugins/build/project
之后我们对yml进行一个配置
server:port: 8081
#spring:
# datasource:
# driver-class-name: com.mysql.jdbc.Driver
# url: jdbc:mysql://localhost:3306/test?useSSLfalseserverTimezoneUTCallowPublicKeyRetrievaltrue #url
# username: root
# password: 1234
spring:redis:database: 4host: localhostport: 6379之后我们要做的是对redis编写一个配置类
Configuration
EnableCaching // 启用缓存功能
public class RedisConfig {// 定义 RedisTemplate Bean用于操作 Redis 数据Beanpublic RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) {RedisTemplateString, Object redisTemplate new RedisTemplate();redisTemplate.setConnectionFactory(factory);// 设置 RedisTemplate 的键和值的序列化方式redisTemplate.setKeySerializer(new StringRedisSerializer()); // 设置键的序列化器为 StringRedisSerializerredisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // 设置值的序列化器为 GenericJackson2JsonRedisSerializer// 设置 RedisTemplate 的哈希键和哈希值的序列化方式redisTemplate.setHashKeySerializer(new StringRedisSerializer()); // 设置哈希键的序列化器为 StringRedisSerializerredisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializerObject(Object.class)); // 设置哈希值的序列化器为 Jackson2JsonRedisSerializerreturn redisTemplate;}// 定义 RedisCacheManager Bean用于管理缓存Beanpublic RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {// 创建 RedisCacheWriter 实例用于向 Redis 写入缓存非锁定方式RedisCacheWriter redisCacheWriter RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());// 创建 RedisCacheConfiguration 实例配置缓存的默认行为RedisCacheConfiguration redisCacheConfiguration RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer())); // 设置缓存值的序列化方式// 返回 RedisCacheManager 实例用给定的 RedisCacheWriter 和 RedisCacheConfiguration 初始化return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);}
}
之后我们就可以使用redisTemplate进行一个操作
使用RedisTemplate进行常见的Redis操作如存储、检索和删除数据
首先要做的第一步就是引入RedisTemplate
这里推荐一个redis的可视化工具 quickredis
QuickOfficial - QuickRedis (quick123.net)
Autowired
private RedisTemplate redisTemplate;String
首先来看第一个
// 测试设置字符串类型数据到 Redis
Test
public void testString() {String key user:token:0001;redisTemplate.opsForValue().set(key, UUID.randomUUID().toString(), 30, TimeUnit.MINUTES);System.out.println(redisTemplate.opsForValue().get(key));
}这个就是像redis添加了一个key 之后来看这个
// 测试字符串类型数据自增操作
Test
public void testString2() {String key article:A00001:viewsCount;redisTemplate.opsForValue().increment(key);System.out.println(redisTemplate.opsForValue().get(key));
}increment实现了对这个key的一个计数功能。比如我们第一次执行就是1 第二次就是2 以此类推
第三个是测试设置Map类型到redis中
// 测试设置 Map 类型数据到 Redis
Test
public void testString3() {MapString, Object user new HashMap();user.put(id, 0001);user.put(name, 张三疯);user.put(age, 28);user.put(birthday, new Date(2005 - 1900, 10, 03));String key user:0001;redisTemplate.opsForValue().set(key, user);System.out.println(redisTemplate.opsForValue().get(key));
}Hash // 测试设置哈希类型数据到 RedisTestpublic void testHash() {String key user:0001:cart;MapString, Object shoppingCart new HashMap();shoppingCart.put(cartId, 123456789);shoppingCart.put(userId, 987654321);ListMapString, Object items List.of(Map.of(itemId, 1, itemName, 手机, price, 999.99, quantity, 1),Map.of(itemId, 2, itemName, 笔记本电脑, price, 1499.99, quantity,2),Map.of(itemId, 3, itemName, 耳机, price, 49.99, quantity, 3));shoppingCart.put(items, items);shoppingCart.put(totalAmount, 3149.92);shoppingCart.put(creationTime, 2046-03-07T10:00:00);shoppingCart.put(lastUpdateTime, 2046-03-07T12:30:00);shoppingCart.put(status, 未结账);redisTemplate.opsForHash().putAll(key, shoppingCart);System.out.println(redisTemplate.opsForHash().get(key, items));}set
// 测试设置集合类型数据到 Redis
Test
public void testSet() {String key author:0001:fans;redisTemplate.opsForSet().add(key, 张三, 李四, 王五);System.out.println(粉丝量 redisTemplate.opsForSet().size(key));
}zset
// 测试设置有序集合类型数据到 Redis
Test
public void testZset() {String key user:0001:friends;redisTemplate.opsForZSet().add(key, 张三, System.currentTimeMillis());redisTemplate.opsForZSet().add(key,李四, System.currentTimeMillis());redisTemplate.opsForZSet().add(key,王五, System.currentTimeMillis());Set set redisTemplate.opsForZSet().reverseRange(key, 0, -1);System.out.println(set);
}list
Test
public void testList() {String key order:queue;MapString, Object order1 new HashMap();order1.put(orderId, 1001);order1.put(userId, 2001);order1.put(status, 已完成);order1.put(amount, 500.75);order1.put(creationTime, 2024-03-07T09:30:00);order1.put(lastUpdateTime, 2024-03-07T10:45:00);order1.put(paymentMethod, 在线支付);order1.put(shippingMethod, 自提);order1.put(remarks, 尽快处理);MapString, Object order2 new HashMap();order2.put(orderId, 1002);order2.put(userId, 2002);order2.put(status, 待处理);order2.put(amount, 280.99);order2.put(creationTime, 2024-03-07T11:00:00);order2.put(lastUpdateTime, 2024-03-07T11:00:00);order2.put(paymentMethod, 货到付款);order2.put(shippingMethod, 快递配送);order2.put(remarks, 注意保鲜);// A程序接收订单请求并将其加入队列redisTemplate.opsForList().leftPush(key,order1);redisTemplate.opsForList().leftPush(key,order2);// B程序从订单队列中获取订单数据并处理System.out.println(处理订单 redisTemplate.opsForList().rightPop(key));
}这是一些简单的操作除了这些我们来介绍一些别的东西
redis进阶操作
RedisHash注解
用于将Java对象映射到Redis的Hash数据结构中使得对象的存储和检索变得更加简单
首先我们创建和实体类一样的数据库表
这个是集体类
Data
RedisHash
public class User {Idprivate Integer id;private String name;private Integer age;private String phone;
}2.创建接口注意需要继承CrudRepository这样改接口就具备对应实体的redis中的增删改查操作
public interface UserRedisMapper extends CrudRepositoryUser,Integer {
}之后进行一个测试
// 测试 Redis 与 Spring Data Redis 集成的操作
Test
public void testRedisHash(){User user new User();user.setId(100);user.setName(张三疯);user.setAge(18);user.setPhone(19988889999);// 保存userRedisMapper.save(user);// 读取User redisUser userRedisMapper.findById(100).get();System.out.println(redisUser: redisUser);// 更新user.setPhone(18899998888);userRedisMapper.save(user);// 删除//userRedisMapper.deleteById(100);// 判断存在boolean exists userRedisMapper.existsById(100);System.out.println(exists: exists);
}这样就可以用redis来对数据库进行一个操作。
redis工作场景分析
session存储信息
用来做数据共享分布式
这个需要引入
dependencygroupIdorg.springframework.session/groupIdartifactIdspring-session-data-redis/artifactIdversion2.6.3/version
/dependency之后设置一下配置
# session 失效时间
session:timeout: 86400store-type: redis之后我们例如在用户登陆的时候
/*** 用户登录*/
Override
public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {//登陆逻辑....//获得了登陆的用户信息//模拟User safetyUsernull;//记录sessionHttpSession session request.getSession();session.setAttribute(USER_LOGIN_STATE, safetyUser);return safetyUser;
}可以设置这个session
这个可以用来做例如获得当前用户
/*** 获取当前用户**/
GetMapping(/current)
public BaseResponseUser getCurrentUser(HttpServletRequest request) {Object userObj request.getSession().getAttribute(USER_LOGIN_STATE);return ResultUtils.success(userObj);
}等等操作你可以理解为她在redis里面存放着一个用户信息。你需要的时候可以随时的去取出来这个信息
分布式锁
这个推荐用的是redisson
Redisson 是一个 java 操作 Redis 的客户端提供了大量的分布式数据集来简化对 Redis 的操作和使用可以让开发者像使用本地集合一样使用 Redis完全感知不到 Redis 的存在。
可以看下面的俩个事例
// list数据存在本地 JVM 内存中
ListString list new ArrayList();
list.add(yupi);
System.out.println(list: list.get(0));list.remove(0);// 数据存在 redis 的内存中
RListString rList redissonClient.getList(test-list);
rList.add(xiaou);
System.out.println(rlist: rList.get(0));
rList.remove(0);void testWatchDog() {RLock lock redissonClient.getLock(test:precachejob:docache:lock);try {// 只有一个线程能获取到锁if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {// todo 实际要执行的方法doSomeThings();System.out.println(getLock: Thread.currentThread().getId());}} catch (InterruptedException e) {System.out.println(e.getMessage());} finally {// 只能释放自己的锁if (lock.isHeldByCurrentThread()) {System.out.println(unLock: Thread.currentThread().getId());lock.unlock();}}
}限流
这个也推荐使用redisson
public void doRateLimit(String key) {RRateLimiter rRateLimiter redissonClient.getRateLimiter(key);//rate是每个时间单位允许访问几次 rateInterval就是时间单位rRateLimiter.trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS);//每当一个操作来了之后,去请求一个令牌boolean canOp rRateLimiter.tryAcquire(1);if (!canOp) {throw new BusinessException(ErrorCode.SYSTEM_ERROR, 当前访问过于频繁);}
}抽奖
/*** 抽奖* return*/
GetMapping(/lucky-draw)
public String luckyDraw() {try {// 获取奖池和参与者列表RListString prizePool redissonClient.getList(prize_pool);RListString participants redissonClient.getList(participants);// 进行抽奖String winner drawWinner(prizePool, participants);// 返回抽奖结果return The winner is: winner;} finally {// 关闭 Redisson 客户端连接redissonClient.shutdown();}
}总结
当然除了这些还有很多使用redis的场景欢迎各位来补充。
文中所有的源码在如下仓库xiaou61/xiaou-easy-code: 前后端通用解决方案 springboot vue react 原生js (github.com)
文章也会在这里同步发送Xiaou-EasyCode-Docs (xiaou61.top)
这个项目是我自己开发的一个前后端通用解决方案的一个项目致力于各种工作中常用的代码的demo展示。目前github已有400star 如果你有兴趣可以去里面提出你的issue或者是pr 共同来完善这个项目。