Java阶段四Day10

news2024/12/28 22:22:54

Java阶段四Day10

文章目录

  • Java阶段四Day10
    • 关于Redis
      • Redis的数据类型
      • Redis中的list类型
      • Redis的常用命令
      • 关于Key的格式
      • Redis编程
      • 使用Redis时的数据一致性问题
    • 关于ApplicationRunner
      • LoadCacheRunner
      • ContentCategoryServiceImpl
    • 计划任务
      • ScheduleConfiguration
      • CategoryCacheSchedule

关于Redis

Redis是一种基于内存的,使用K-V结构存储数据的NoSQL非关系型数据库。

提示:Redis也会占用磁盘空间,并且,会自动将内存中的数据同步到硬盘上,所以,存入到Redis中的数据,即使重启电脑,再次开机时Redis会自动将硬盘上的数据重新加载到内存,但是,正常读写Redis仍是在内存中处理的!

Redis的主要作用是缓存数据,通常,会将关系型数据库(例如MySQL)中的数据读取出来,并写入到Redis中,后续,当需要获取数据时,直接从Redis中读取即可,不必再从关系型数据库中读取数据,从而提高获取数据的效率!

由于Redis是基于内存的,读写效率远高于基于磁盘(例如硬盘)的关系型数据库,使得单次查询耗时变得非常短,则整个系统处理数据的效率会明显提升,并且,由于减少了对关系型数据库的访问频率,可以起到“保护”关系型数据库的作用!

Redis的数据类型

Redis中的经典数据类型有5种:string / hash / list / set / z-set

  • 在Java语言中的简单数据类型,在Redis中对应的都是string

另外,还有:bitmap / hyperloglog / GEO / 流

Redis中的list类型

在Redis中,list类型的数据是一个先进后出、后进先出的栈结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v0vjkUcc-1688223041706)(E:/TeduWork/jsd2303-tea-front-server-teacher/doc/assets/image-20230701091848423.png)]

在学习Redis时,你需要将以上图例旋转了90度!

可以选择从左侧压栈来存入数据,例如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-19NwUIkz-1688223041707)(E:/TeduWork/jsd2303-tea-front-server-teacher/doc/assets/image-20230701092424201.png)]

可以选择从右侧压栈来存入数据,例如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lGJPVhBM-1688223041708)(E:/TeduWork/jsd2303-tea-front-server-teacher/doc/assets/image-20230701092501128.png)]

从Redis中读取list数据时,始终是从左至右读取的,通常,为了更加符合使用列表的习惯,大多情况下采取“从XX压入数据”的做法。

**注意:**在Redis中的list数据,每个元素都同时拥有2个下标,一个是从左至右、从0开始递增编号的,另一个是从右至左、从-1开始递减编号的!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Lm1GOOP-1688223041708)(E:/TeduWork/jsd2303-tea-front-server-teacher/doc/assets/image-20230701094904029.png)]

**注意:**在读取List中的区间时,end表示的元素不可以是相对start更靠左的元素!

提示:-1始终是最后一个元素的下标,所以,当你需要读取整个列表的数据时,start0end-1

Redis的常用命令

当登录Redis的客户端后(命令提示符变成127.0.0.1:6379>状态后),可以:

  • set KEY VALUE:存入数据,例如:set username root,如果反复使用同一个KEY执行此命令,后续存入的VALUE会覆盖前序存入的VALUE,相当于“修改数据”,如果使用的是此前从未使用过的KEY,则会新增数据
  • get KEY:取出数据,例如:get username,如果KEY存在,则取出对应的数据,如果KEY不存在,则返回(nil),相当于Java中的null
  • keys PATTERN:根据模式(PATTERN)获取KEY,例如:keys username,如果KEY存在,则返回,如果不存在,则返回(empty list or set),在PATTERN处可以使用星号(*)作为通配符,例如:keys username*可以返回当前Redis中所有以username作为前缀的KEY,返回的多个KEY在显示时是无序的,甚至,还可以使用keys *查询当前Redis中所有KEY
    • **注意:**在生产环境中,禁止使用此命令
  • del KEY [KEY ...] :删除指定KEY对应的数据,例如:del username,将返回删除了多少条数据
  • flushdb:清空当前数据库

更多命令可参考:Redis命令手册

关于Key的格式

Redis本身并没有要求Key应该如何定义,但是,由于Redis被设计为可以存放特别多数据,并且,各种各样的数据都可以放在Redis中,所以,在实际应用中,应该使用有规律的Key,否则,后续读写数据时会很麻烦!

例如:当存放“用户”相关数据时,应该使用user字样作为Key的一部分,存放“文章”相关数据时,应该使用article字样作为Key的一部分。

示例:假设有20个用户数据,ID分别是从1到20,使用Redis中的string类型分别存储这20个用户数据时,各数据对应的Key可以是:user-1user-2、……、user-20,后续,只要知道被获取数据的ID,就可以知道Key,并基于这个Key来读取数据。

在定义Key时,各部分之间应该使用某个符号进行分隔,例如user-1就是在user前缀和ID之间使用了减号进行分隔!

在绝大部分Redis可视化工具(例如:Another Redis Desktop Manager)中,默认情况下,会自动处理Key中的冒号(:),并多个前缀相同的Key放在相同的“文件夹”中,例如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1EhQmiDg-1688223041709)(E:/TeduWork/jsd2303-tea-front-server-teacher/doc/assets/image-20230701103237470.png)]

以上冒号只是建议使用的分隔符号,并不是必须使用冒号,也可以改为其它符号,例如减号等,大多软件也可以设置根据什么符号来分隔出“文件夹”。

提示:无论使用什么分隔符,只要Key不冲突,对使用是没有影响的,所以,并不一定需要分隔符,只是强烈建议在Key中使用分隔符。

在开发实践中,Key的定义应该是多层级的,并且,应该保证同类数据一定具有相同的组成部分,例如:

  • 用户详情数据:user:item:1user:item:2
  • 用户列表数据:user:list
  • 文章详情数据:article:item:1article:item:2
  • 文章列表数据:article:list

Redis编程

在Spring Boot中,实现Redis编程需要添加依赖:

<!-- Spring Boot支持Redis编程的依赖项 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

当需要读写Redis中的数据时,需要使用RedisTemplate的工具类,通常,会使用配置类中的@Bean方法来配置此类的对象,以便于后续可以随时通过自动装配来获取此类的对象!

/**
 * Redis的配置类
 *
 */
@Slf4j
@Configuration
public class RedisConfiguration {

    public RedisConfiguration() {
        log.debug("创建配置类对象:RedisConfiguration");
    }

    @Bean
    public RedisTemplate<String, Serializable> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setValueSerializer(RedisSerializer.json());
        return redisTemplate;
    }
}

使用Redis时的数据一致性问题

在开发实践中,数据最终肯定是保存在关系型数据库(例如MySQL等)中的,同时,为了提高查询效率、保护关系型数据库,通常会将某些数据从关系型数据库中读出来,并写入到Redis中,后续,将优先从Redis中读取数据!

由于在关系型数据库和Redis中都存储了数据,如果某个数据需要修改,最终修改的肯定是关系型数据库中的数据,但是,如果Redis中的数据没有及时更新,却仍从Redis中读取数据,则读取到的数据就是“不准确的”!

所以,当同一个数据在多个不同的位置存储了多份,就可能出现以上问题,通常称之为“数据一致性”的问题,即2个或多个不同的存储位置,本应该“相同”的数据其实“并不相同”!

关于数据一致性问题:

  • 并不一定有必要及时更新数据,例如:MySQL中的数据发生了变化,但是Redis中却不更新,此时,数据并不一致,但是,对于软件的使用可能没有严重影响
    • 例如:某个热门视频的播放次数
    • 例如:购买火车票时,列表页面中显示的的各车次的余票数量
  • 某些数据的更新频率可能非常低,这类数据基本上没有数据一致性问题
    • 例如:全国省市区数据
  • 并不是所有数据都适合在Redis中也存一份,对于访问频率非常低的数据,或数据量特别大的数据,可以不使用Redis
    • 例如:用户3年前的历史订单

解决数据一致性问题的做法主要有:

  • 即时更新:当关系型数据库的数据发生变化,马上更新Redis中的数据
    • 保证数据的实时一致性
  • 周期性更新:当关系型数据库的数据发生变化,不会马上更新Redis中的数据,而是每间隔一段时间,或到了某个指定的时间时,执行1次同步数据的操作
    • 保证数据的最终一致性
  • 手动更新:当关系型数据库的数据发生变化,不会马上更新Redis中的数据,而是由管理人员(或运营人员)明确执行更新操作,才会同步数据
    • 保证数据的最终一致性

关于ApplicationRunner

在Spring Boot中,可以自定义组件类,实现ApplicationRunner接口,重写其中的run()抽象方法,后续,当启动项目后,会在启动成功后的第一时间自动调用此run()方法!

LoadCacheRunner

@Slf4j
@Component
public class LoadCacheRunner implements ApplicationRunner {

    @Autowired
    private ContentCategoryService categoryService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.debug("开始执行【加载缓存数据】");
        categoryService.rebuildListCache();
    }
}

ContentCategoryServiceImpl

@Service
@Slf4j
public class ContentCategoryServiceImpl implements ContentCategoryService {

    @Autowired
    private CategoryCacheRepository categoryCacheRepository;
    @Autowired
    private ContentCategoryRepository categoryRepository;

    public ContentCategoryServiceImpl() {
        log.info("创建业务对象:CategoryServiceImpl");
    }


    @Override
    public List<ContentCategoryListItemVO> list() {
        log.debug("开始处理【查询类别数据列表】的业务,参数:无");
        return categoryCacheRepository.list();
    }

    @Override
    public void rebuildListCache() {
        log.debug("开始处理【重建缓存中的类别列表】的业务,参数:无");
        categoryCacheRepository.deleteList();
        List<ContentCategoryListItemVO> list = categoryRepository.list();
        categoryCacheRepository.save(list);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q6GaUqUE-1688225115329)(../../../AppData/Roaming/Typora/typora-user-images/image-20230701230053968.png)]

利用以上机制,可以实现“缓存预热”(项目启动时就将数据加载到缓存中)。

但其实用价值不太高,需要结合手动更新一起使用,因为只会在项目启动的那一刻执行,当数据发生改变仍需要手动更新,适合类别地址、省市区管理等,适用于数据变化频率不规则,而如何使用周期性更新就需要用到计划任务

计划任务

在Spring Boot中,默认禁止了所有的计划任务,需要在配置类上添加@EnableScheduling注解,以启用当前项目中所有计划任务。

在项目中,自定义组件类,并在组件类中自定义方法,使用框架调用,无返回值无参数列表。在方法上添加@Scheduled注解,则此方法就是一个计划任务方法,可以周期性的执行。

ScheduleConfiguration

@Slf4j
@Configuration
@EnableScheduling
public class ScheduleConfiguration {

    public ScheduleConfiguration() {
        log.debug("创建配置类对象:ScheduleConfiguration");
    }
}

CategoryCacheSchedule

/**
* 处理类别缓存的计划任务
*/
@Slf4j
@Component
public class CategoryCacheSchedule {

    @Autowired
    private ContentCategoryService categoryService;

    public CategoryCacheSchedule() {
        log.debug("创建计划任务组件对象:CategoryCacheSchedule");
    }

    // fixedRate:执行频率,根据上一次执行的开始时间来计算下一次的执行时间,取值以毫秒为单位
    // fixedDelay:执行间隔,根据上一次执行的结束时间来计算下一次的执行时间,取值以毫秒为单位
    // cron:使用cron表达式来配置执行时间
    // -- cron表达式的本质是一个字符串,此字符串中包括6~7个域,每个域的值之间使用空格分隔
    // -- cron表达式中的域从左至右依次是:秒 分 时 日 月 周 [年]
    // -- 各域的值可以使用通配符:
    // -- 使用星号(*)表示任意值
    // -- 使用问号(?)表示不关心此值,此通配符只能用于“日”和“周”所在的域
    // -- 在各个域中,可以使用减号表示连接的区间,例如在“月”所在的域使用 5-7 表示“从5至7”
    // -- 在各个域中,可以使用英文的逗号分隔多个值,表示满足列举的任意值均可,例如在“月”所在的域使用 1,3,5,7,9 表示1月或3月或5月或7月或9月均匹配
    // -- 在各个域中,数字值可以写成“x/y”的格式,表示此域的值为x时执行,且每间隔y再次执行,直至其它域的值不满足匹配
    // -- 更多内容可参考:https://zhuanlan.zhihu.com/p/573018560
    @Scheduled(fixedRate = 2 * 60 * 1000)
    public void rebuildListCache() {
        log.debug("开始执行【重建缓存中的类别列表】的计划任务");
        categoryService.rebuildListCache();
    }
    
}




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/708395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

已烧写过的镜像重新烧镜像教程

本教程是已经烧录过镜像的SD卡&#xff0c;无法被电脑识别盘符导致无法重新烧录镜像的教程。一般是win7系统无法识别烧录过的Ubuntu系统盘符。win10可以使用SDformat软件格式化。 1.确定读卡器是否识别到SD卡。 点击计算机右键选择“管理”&#xff0c;选择磁盘管理&#xff0…

Vue3中Vuex的基本使用

src/store/uuidState.js const uuidState {namespaced: true,state: {uuid: "",state_tag: "",},// 要想改变state中的数据必须使用mutations的方法mutations: {changeUuid(state, value) {state.uuid value;},changeTag(state, value) {state.state_ta…

如何通过空号检测,验证电话号码数据的准确性

引言 空号检测 API 接口通常与电话号码数据库或相关的电话服务提供商进行交互&#xff0c;使用验证算法和查询技术来确定电话号码的状态。通过该接口&#xff0c;开发者可以通过编程方式对电话号码进行验证&#xff0c;帮助验证号码的有效性&#xff0c;确保数据的准确性和可靠…

HJ76 尼科彻斯定理

描述 验证尼科彻斯定理&#xff0c;即&#xff1a;任何一个整数m的立方都可以写成m个连续奇数之和。 例如&#xff1a; 1^31 2^335 3^37911 4^313151719 输入一个正整数m&#xff08;m≤100&#xff09;&#xff0c;将m的立方写成m个连续奇数之和的形式输出。 数…

vmware17安装群辉6.2懒人包

懒人包下载 链接&#xff1a;https://pan.baidu.com/s/1onGpM3BLIKUuxs10lLM83A?pwdcmdr 提取码&#xff1a;cmdr --来自百度网盘超级会员V5的分享 解压安装 如果已经安装了vmware软件的话&#xff0c;直接双击打开即可 上图说明安装成功 点击搜索 &#xff0c; 会出现服务…

0-1BFS 双端队列 广度优先搜索

一. BFS及0-1BFS的简单介绍 深度优先搜索DFS和广度优先搜索BFS是经常使用的搜索算法&#xff0c;在各类题目中都有广泛的应用。 深度优先搜索算法&#xff08;英语&#xff1a;Depth-First-Search&#xff0c;DFS&#xff09;是一种用于遍历或搜索树或图的算法。其过程简要来说…

pwn学习day3——函数调用约定

文章目录 x32 cdecl调用约定x64 System V AMD64 ABI调用约定 规定函数调用时如何传递参数&#xff0c;如何返回值&#xff0c;如何进行栈管理 x32 cdecl调用约定 参数从右往左依次压入栈中&#xff0c;返回值存入eax寄存器中,由调用者清理栈上的参数。 测试程序&#xff1a; …

转载-【AI思维空间】Chat2DB 一款开源数据库客户单工具

卸载 Navicat&#xff0c; xxx 又开源了一款数据库神器&#xff0c;太炸了 Chat2DB 是一款有开源免费的多数据库客户端工具&#xff0c;支持windows、mac本地安装&#xff0c;也支持服务器端部署&#xff0c;web网页访问。和传统的数据库客户端软件Navicat、DBeaver 相比Chat2D…

基于JSP+Servlet+Mysql的智能化停车场管理系统(含论文)

TOC 一、系统介绍 项目类型&#xff1a;Java web项目 项目名称&#xff1a;基于JSPServlet的智能智能停车场管理系统 源码作者&#xff1a;未知 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语言 前端技术&#xff1a;HTML、CSS、JS等技术 后端技术&#xff…

中国国债发行数据集(2002-2023)

国债是由国家发行的债券&#xff0c;由于国债的发行主体是国家&#xff0c;所以它具有最高的信用度&#xff0c;被公认为是最安全的投资工具。国债按照交易市场的不同分为三类&#xff0c;即银行间市场国债、交易所市场国债和柜台市场国债&#xff1b;按照交易方式的不同分为三…

PCB绘制封装

绘制封装 常见的电阻封装如下&#xff1a; 绘制封装的一般步骤&#xff1a; 丝印不重要&#xff0c;关键是焊盘。 第一步是确认中心(对称中心)&#xff1b;第二步&#xff0c;围绕着对称中心&#xff0c;放置焊盘。直插式的焊盘要放大孔径&#xff0c;贴片式的焊盘要加长&am…

springboot-配置优先级

配置文件 类型 1.properties(三者同时存在&#xff0c;优先级最高) 2.yml 3.yaml&#xff08;最低&#xff09; 除此之外&#xff0c;可以在启动配置处修改 //java系统属性配置, -Dserver.port8080&#xff0c;优先级高于以上三种 //命令行参数 --server.port10010&#xff0…

【SQL应知应会】行列转换(一)• MySQL版

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习&#xff0c;有基础也有进阶&#xff0c;有MySQL也有Oracle 行列转换 • Mysql版 一、MySQL行列转换1.准备操作…

kafka入门,数据去重(九)

数据传递语义 至少一次&#xff1a;ACK级别设置为-1分区副本大于等于2ISR里应答的最小副本数量大于等于2 最多一次&#xff1a;ACK级别设置为0 总结&#xff1a; At Least Once&#xff1a;可以保证数据不丢失&#xff0c;但是不能保证数据不重复 At Most Once&#xff1a;可以…

智慧园区运营管理平台解决方案

智慧园区运营管理平台是当今现代城市发展中的一项重要工具。随着城市人口不断增长&#xff0c;对城市基础设施和服务的需求也不断增加。为了有效管理和优化园区内的各项运营活动&#xff0c;智慧园区运营管理平台应运而生。 智慧园区运营管理平台是基于现代信息技术和互联网技术…

10W+前端面试题面试资料八股文

点击下方链接获取全部内容文档题目及其答案: 10W前端面试题&面试资料&八股文题目及其答案 https://m.tb.cn/h.5a7v237?tkQeVPdsoKwr4 CZ3457 部分题目如下&#xff1a; 1. call丶apply丶bind区别及源码实现&#xff08;手写&#xff09; 不同点&#xff1a; call…

HTML 编辑器的介绍及推荐

HTML 编辑器 HTML 编辑器是用于编写 HTML 的工具&#xff0c;使用 HTML 编辑器时以编辑主题&#xff0c;索引&#xff0c;自定义窗口&#xff0c;选择添加搜索页。 使用 Notepad 或 TextEdit 来编写 HTML 下列是三种专门用于编辑 HTML 的 HTML 编辑器&#xff1a; Adobe Dream…

ChatGPT实战:高考志愿填报

近期&#xff0c;随着各地陆续发布高考成绩&#xff0c;高考志愿填报市场随之升温&#xff0c;“高报师”再次成为“香饽饽”。填报志愿对中学生来说太难&#xff0c;在一个懵懂的年纪做这样一个决策&#xff0c;份量是比较重的。当普通人没很多的信息做参考的时候&#xff0c;…

【测试效率提升技巧】xmind测试用例转换为excel工具使用手册

【测试效率提升技巧】xmind测试用例转换为excel工具使用手册 一、前置环境配置二、执行Xmind2testcase的转换方法1.在控制台输入xmind2testcase [path/xmind文件路径] [-csv] [-xml] [-json]&#xff0c;例&#xff1a;xmind2testcase /root/homin/XX测试点.xmind -csv ##在当前…

HBase(14):HBase架构

1 系统架构 1.1 Client 客户端,例如:发出HBase操作的请求。例如:之前我们编写的Java API代码、以及HBase shell,都是CLient 1.2 Master Server 在HBase的Web UI中,可以查看到Master的位置。 监控RegionServer处理RegionServer故障转移处理元数据的变更处理region的分配或…