当前位置: 首页 > news >正文

【应用程序】基于 Spring Boot + Spring AI的虚拟宠物Web 应用(三)

四、数据持久化方案目前的状态管理最大的问题就是:应用重启,猫就饿死了(数据全丢了)。作为一只负责任的铲屎官,我们得给猫咪的状态找个靠谱的家。4.1 方案对比方案优点缺点适用场景推荐度内存 Map(现状)简单、快、零配置重启丢失、不支持多实例、无 TTL本地演示、开发调试⭐Redis持久化、高性能、原生支持 TTL、数据结构丰富需要额外部署 Redis 服务生产环境首选⭐⭐⭐⭐⭐关系型数据库(MySQL/PostgreSQL)结构化、易查询、事务支持速度稍慢、需要表设计需要复杂查询、报表统计⭐⭐⭐⭐文件存储(JSON/YAML)简单、无需外部依赖并发差、不适合高频读写单机轻量应用、配置存储⭐⭐H2 / SQLite(嵌入式数据库)零配置、持久化、SQL 支持并发性能一般中小型应用、快速原型⭐⭐⭐4.2 推荐方案:Redis + 持久化对于这个场景,Redis 是比较 sweet 的选择:** Redis**数据结构匹配:宠物状态就是简单的 key-value(Hash),Redis 天生擅长TTL 自动清理:支持设置过期时间,长时间不活跃的会话自动清理,省内存性能极好:读写都是微秒级,不会影响 AI 交互的响应速度Spring Boot 集成简单:spring-boot-starter-data-redis一行依赖搞定支持集群:应用多实例部署时,Redis 是共享状态的最佳选择持久化选项:RDB 快照 + AOF 日志,数据不会丢4.3 Redis 数据结构设计TTL管理EXPIRE pet:state:user-123 6048007天后自动删除Redis数据结构Key: pet:state:user-123Hashfield: hungervalue: 69field: happinessvalue: 53field: lastInteractionTimevalue: 2026-05-26T14:30:00field: moodvalue: NORMALfield: versionvalue: 1Key 设计规范:prefix : 业务标识 separator : ":" namespace : 状态类型 id : 会话 ID 完整格式 : pet:state:{conversationId} 示例 : pet:state:user-123-abcHash 字段设计:字段类型说明hungerInteger饥饿度 0-100happinessInteger开心度 0-100lastInteractionTimeISO-8601 String上次互动时间moodString当前心情枚举值versionInteger乐观锁版本号(防止并发覆盖)TTL 策略:默认 TTL:7 天(604800秒)每次互动后刷新 TTL长时间不活跃的宠物自动"放生"(清理数据)4.4 存储层代码实现// PetStateRepository.java - 存储接口publicinterfacePetStateRepository{OptionalPetStatefindById(StringconversationId);voidsave(PetStatestate);voiddeleteById(StringconversationId);}// RedisPetStateRepository.java - Redis 实现@Repository@PrimarypublicclassRedisPetStateRepositoryimplementsPetStateRepository{privatefinalStringRedisTemplateredisTemplate;privatefinalObjectMapperobjectMapper;privatestaticfinalStringKEY_PREFIX="pet:state:";privatestaticfinallongTTL_SECONDS=7*24*60*60;// 7天publicRedisPetStateRepository(StringRedisTemplateredisTemplate,ObjectMapperobjectMapper){this.redisTemplate=redisTemplate;this.objectMapper=objectMapper;}@OverridepublicOptionalPetStatefindById(StringconversationId){Stringkey=KEY_PREFIX+conversationId;// 使用 Hash 操作获取所有字段MapObject,Objectentries=redisTemplate.opsForHash().entries(key);if(entries.isEmpty()){returnOptional.empty();}returnOptional.of(mapToPetState(conversationId,entries));}@Overridepublicvoidsave(PetStatestate){Stringkey=KEY_PREFIX+state.getConversationId();// 使用 Hash 存储,字段清晰,更新灵活MapString,Stringmap=newHashMap();map.put("hunger",String.valueOf(state.getHunger()));map.put("happiness",String.valueOf(state.getHappiness()));map.put("lastInteractionTime",state.getLastInteractionTime().toString());map.put("mood",state.getMood().name());// 使用 putAll 原子性写入redisTemplate.opsForHash().putAll(key,map);// 刷新 TTLredisTemplate.expire(key,TTL_SECONDS,TimeUnit.SECONDS);}@OverridepublicvoiddeleteById(StringconversationId){redisTemplate.delete(KEY_PREFIX+conversationId);}/** * 将 Redis Hash 映射为 PetState 对象 */privatePetStatemapToPetState(StringconversationId,MapObject,Objectentries){PetStatestate=newPetState(conversationId);if(entries.containsKey("hunger")){state.setHunger(Integer.parseInt(entries.get("hunger").toString()));}if(entries.containsKey("happiness")){state.setHappiness(Integer.parseInt(entries.get("happiness").toString()));}if(entries.containsKey("lastInteractionTime")){state.setLastInteractionTime(LocalDateTime.parse(entries.get("lastInteractionTime").toString()));}if(entries.containsKey("mood")){state.setMood(PetMood.valueOf(entries.get("mood").toString()));}returnstate;}}4.5 降级方案:内存实现(用于开发测试)// InMemoryPetStateRepository.java - 内存实现(开发/测试用)@Repository@Profile("dev")// 只在 dev 环境生效publicclassInMemoryPetStateRepositoryimplementsPetStateRepository{privatefinalMapString,PetStatestore=newConcurrentHashMap();@OverridepublicOptionalPetStatefindById(StringconversationId){returnOptional.ofNullable(store.get(conversationId));}@Overridepublicvoidsave(PetStatestate){store.put(state.getConversationId(),state);}@OverridepublicvoiddeleteById(StringconversationId){store.remove(conversationId);}}五、定时任务设计猫咪不是机器,它需要**"活着"的感觉**。即使主人不在线,它也应该有自己的生活规律——会饿、会无聊、会想主人。5.1 状态自然衰减
http://www.rkmt.cn/news/1398181.html

相关文章:

  • DateTime 时间处理
  • 从TVS到肖特基:一张图看懂8种二极管的选型指南与典型电路
  • SpringBoot实战:三种主流CORS跨域配置方案详解与选型
  • 从编译错误到成功导入:手把手教你为MinkowskiEngine 0.5.4在Ubuntu22.04上搭建Python 3.8虚拟环境
  • 2026乐山临江鳝丝TOP5门店排行:乐山跷脚牛肉店有哪些、乐山跷脚牛肉排行前三、乐山跷脚牛肉更正宗、乐山跷脚牛肉哪家好选择指南 - 优质品牌商家
  • 手把手教你用立创GD32E230开发板实现按键控制LED(GPIO输入输出实战)
  • SkiaSharp实战:5分钟为你的C# WinForm应用添加一个“可移动的小球”
  • 27考研311教育学历年真题PDF
  • 臺灣大學校總區無車化執行方案與推動時程整體規劃案(繁) 2025
  • 如何解决网页保存的三大痛点?SingleFile工具让完整网页归档变得如此简单
  • 动态目标跨镜无缝接力追踪技术——科技园区科研区域安防场景中的空间智能应用白皮书
  • ChatGPT学生免费账号还能用多久?内部信源透露:2024Q3起将分批关闭未续验账户
  • 别再死记硬背了!用这个C语言预测分析法程序帮你搞定《编译原理》实验
  • 【C++】从sleep()到clock():精准控制程序时序的实战指南
  • Mac上折腾John the Ripper破解加密压缩包:从安装到放弃的14小时实录
  • 2026年4月成都火锅品牌口碑推荐,烧菜火锅/特色美食/美食/社区火锅/火锅,成都火锅品牌找哪家 - 品牌推荐师
  • ubuntu下stlink(v1/v2/v3)实现GD32下载程序
  • 碳硅共生,智联金砖|玄同科技邀您共赴 5・28 厦门 OPC 生态盛会!
  • 2026年5月深圳金蝶云星空与店小秘接口对接:必须掌握的30+种数据保存类型清单
  • Cursor 智能编程助手实战应用指南
  • 2026靠谱爱普生UV打印机品牌推荐:图文数码打印机、小批量包装打印机、烫金增效打印机、礼盒数码打样机、逆向UV数码打印机选择指南 - 优质品牌商家
  • SHINE:基于内存解耦架构的分布式HNSW索引设计与优化
  • 2026绵阳沟通障碍康复机构优质推荐榜:绵阳语言障碍/绵阳刻板行为康复/绵阳发育迟缓/绵阳多动症/绵阳孤独症/绵阳感统训练/选择指南 - 优质品牌商家
  • 别再像我一样踩坑!用PSIM和Multisim手把手教你推导Buck电路的正确传递函数
  • IMXRT开发板SWO跟踪配置与调试指南
  • LM741反相放大器设计避坑指南:电源、电阻选型与失真问题全解析
  • 实战派指南:用Python的sklearn库,5分钟搞定PCA、LDA和t-SNE可视化
  • 2026中式瓦厂家权威名录:四川青瓦厂家、小青瓦厂家、仿古建筑砖瓦厂家、仿古建筑青瓦厂家、仿古琉璃瓦厂家、仿古瓦厂家选择指南 - 优质品牌商家
  • 2026年5月新疆凉亭直销厂家推荐电话:聚焦本土制造与定制化服务能力 - 2026年企业资讯
  • Docker安装常见数据库命令汇总(2026)