Redis学习——Redisson 分布式锁集成及其简单使用
文章目录
- 引言
- 1. Redisson概述
- 1.1 Redisson的基本概念
- 1.2 Redisson的主要功能
- 1.3 Redisson的优点
- 2. 开发环境
- 3. Redisson的安装与配置
- 3.1 添加依赖
- 3.2 配置Redisson
- 4. 使用Redisson
- 4.1 可重入锁
- 4.1.1 可重入锁的概念
- 4.1.2 可重入锁的实现原理
- 4.1.3 简单使用
- 锁的获取和释放
- 4.2 公平锁
- 4.2.1 公平锁的概念
- 4.2.2 公平锁的实现原理
- 4.2.3 简单使用
- 4.3 读写锁
- 4.3.1 读写锁的概念
- 4.3.2 读写锁的实现原理
- 4.3.3 简单使用
- 4.4 联锁
- 4.4.1 联锁的概念
- 4.4.2 联锁的实现原理
- 4.4.3 简单使用
- 5. WatchDog机制
- 6. 总结

引言
在分布式系统中,经常需要对共享资源进行并发访问控制,以确保数据的一致性和完整性。分布式锁是一种用于在分布式环境中控制对共享资源访问的机制,它可以保证在同一时刻只有一个客户端能够访问某些特定资源。
1. Redisson概述
1.1 Redisson的基本概念
Redisson是一个基于Redis的Java客户端,它不仅提供了对Redis的基础操作支持,还封装了许多高级功能,如分布式锁、分布式集合、分布式队列等。Redisson的设计目标是简化分布式系统的开发,提高开发效率和系统的可维护性。
1.2 Redisson的主要功能
- 分布式锁:支持可重入锁、公平锁、读写锁、红锁等多种分布式锁机制,保证分布式环境下的资源访问控制。比如:在电商系统中,防止超卖现象;在订单系统中,防止同一订单被多次处理。
- 分布式集合:提供分布式Set、List、Map等集合类型,支持高并发环境下的数据操作。
- 分布式队列:支持分布式阻塞队列、延迟队列等,适用于任务调度和消息传递场景。
- 分布式对象:提供分布式AtomicLong、AtomicDouble、CountDownLatch、Semaphore等对象,简化分布式系统的开发。
- 分布式服务:支持分布式执行器、分布式调度器等服务,增强分布式系统的功能。
1.3 Redisson的优点
Redisson是一个基于Redis的Java客户端,提供了许多高级特性和分布式数据结构。相比其他Redis客户端,Redisson的优势在于:
- 简洁易用:提供了丰富的API,简化了分布式编程的复杂性。
- 高可用性:支持多种Redis部署模式,包括单节点、主从复制和集群模式。
- 分布式对象:提供了分布式锁、分布式集合、分布式队列等高级数据结构,便于在分布式环境中使用。
- 自动续期:Redisson的Watchdog机制可以自动续期分布式锁,避免锁超时问题。
2. 开发环境
- JDK版本:JDK 17
- Spring Boot版本:Spring Boot 3.2.2
- Redis版本:5.0.14.1
- 构建工具:Maven
3. Redisson的安装与配置
3.1 添加依赖
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.24.3</version>
</dependency>
3.2 配置Redisson
配置参考文档:2. Configuration · redisson/redisson Wiki (github.com)
添加配置类RedissonConfig
:
/*** Redisson配置类,用于配置Redisson客户端。*/
@Configuration
public class RedissonConfig {/*** 创建并配置RedissonClient Bean。* * @return 配置好的RedissonClient实例*/@Beanpublic RedissonClient redissonClient() {// 创建Redisson配置对象Config config = new Config();// 配置单节点模式config.useSingleServer()// 设置Redis服务器地址.setAddress("redis://127.0.0.1:6379")// 设置Redis服务器密码.setPassword("123321")// 设置连接池大小.setConnectionPoolSize(64)// 设置最小空闲连接数.setConnectionMinimumIdleSize(24)// 设置空闲连接超时时间(毫秒).setIdleConnectionTimeout(10000)// 设置连接超时时间(毫秒).setConnectTimeout(10000)// 设置命令等待超时时间(毫秒).setTimeout(3000)// 设置命令重试次数.setRetryAttempts(3)// 设置命令重试间隔时间(毫秒).setRetryInterval(1500);// 创建并返回RedissonClient实例return Redisson.create(config);}
}
4. 使用Redisson
官方wiki文档:8. Distributed locks and synchronizers · redisson/redisson Wiki (github.com)
中文版wiki文档(已经有5年没有更新了,不建议看):8. 分布式锁和同步器 · redisson/redisson Wiki (github.com)
4.1 可重入锁
4.1.1 可重入锁的概念
可重入锁(Reentrant Lock)是一种允许同一个线程多次获取同一把锁的锁机制。也就是说,当一个线程已经持有某个锁时,它可以再次获取该锁而不会被阻塞。这种锁机制能够避免死锁问题,并简化锁的使用。
可重入锁的主要特点是:
- 同一线程可多次获取:同一个线程可以多次获取同一把锁,而不会被阻塞。
- 计数器维护:可重入锁内部维护一个计数器,每次获取锁时计数器加1,每次释放锁时计数器减1,当计数器为0时,锁才真正被释放。
4.1.2 可重入锁的实现原理
可重入锁的实现通常依赖于一个计数器和一个持有锁的线程标识。当一个线程第一次获取锁时,计数器加1,并记录持有锁的线程标识。当同一个线程再次获取锁时,只需将计数器加1,而不会阻塞线程。当线程释放锁时,计数器减1,当计数器为0时,锁才真正被释放,并允许其他线程获取锁。
在Redisson中,可重入锁的实现基于Redis的原子操作和Lua脚本。Redisson通过维护一个计数器和持有锁的线程标识,实现了可重入锁的功能。
4.1.3 简单使用
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;/*** 服务类示例*/
@RequiredArgsConstructor
@Service
public class XXXXService {private final RedissonClient redissonClient; /*** 使用 Redisson 可重入锁执行任务*/public void performTaskWithLock() {// 获取可重入锁对象,指定锁的名称RLock lock = redissonClient.getLock("myLock"); try {// 尝试获取锁,参数分别是:获取锁的最大等待时间,锁自动释放时间,时间单位,返回值为是否获取锁成功boolean isLock = lock.tryLock(1, 10, TimeUnit.SECONDS); // 判断获取锁成功if (isLock) { try {System.out.println("执行业务"); // 在这里编写需要进行锁保护的业务逻辑} finally {// 释放锁lock.unlock(); }} else {// 获取锁失败,可以进行相应的处理,例如记录日志或返回错误信息System.err.println("获取锁失败!"); }} catch (InterruptedException e) {// 处理中断异常throw new RuntimeException(e); }}
}
在上述代码中,我们使用
redissonClient.getLock("myLock")
获取一个分布式锁对象,然后使用lock.tryLock()
方法尝试获取锁,并在任务完成后释放锁。锁的获取和释放
- 获取锁:使用
RLock
对象的tryLock()
或lock()
方法来获取锁。tryLock()
方法允许设置等待时间和锁的自动释放时间。- 释放锁:使用
RLock
对象的unlock()
方法来释放锁。确保在finally
块中释放锁,以避免死锁。
4.2 公平锁
4.2.1 公平锁的概念
公平锁(Fair Lock)是一种确保锁的获取顺序与请求顺序相同的锁机制。即先请求锁的线程优先获取锁,后请求的线程只能在前面的线程释放锁后才能获取锁。这种机制可以避免“饥饿”现象,确保每个线程都能公平地获取锁。
4.2.2 公平锁的实现原理
公平锁的实现通常依赖于一个队列来记录请求锁的顺序。每次有线程请求锁时,会将其添加到队列中,当锁被释放时,从队列中按照请求顺序依次唤醒等待的线程。
在Redisson中,公平锁的实现基于Redis的有序集合(Sorted Set)和Lua脚本。每次请求锁时,线程会被添加到一个有序集合中,并按照时间戳排序。当锁被释放时,按照有序集合中的顺序依次唤醒等待的线程。
4.2.3 简单使用
public void performTaskWithFairLock() {// 1. 获取公平锁对象RLock fairLock = redissonClient.getFairLock("myFairLock");try {// 2. 尝试获取锁boolean isLock = fairLock.tryLock(1, 10, TimeUnit.SECONDS); // 3. 判断是否获取到锁if (isLock) { try {System.out.println("获得公平锁,正在执行任务...");// 执行任务} finally {// 4. 释放锁fairLock.unlock(); System.out.println("释放公平锁。");}} else {System.out.println("无法获取公平锁。");}} catch (InterruptedException e) {e.printStackTrace();}
}
4.3 读写锁
4.3.1 读写锁的概念
读写锁(Read-Write Lock)是一种允许多个读操作同时进行,但写操作必须独占的锁机制。读写锁分为两种锁:读锁和写锁。
- 读锁:允许多个线程同时获取读锁,只要没有线程持有写锁。读锁之间是共享的。
- 写锁:只允许一个线程获取写锁,并且在写锁持有期间,其他线程不能获取读锁或写锁。写锁是独占的。
读写锁的主要目的是提高并发性和性能。在读多写少的场景下,读写锁可以显著提高系统的并发处理能力。
4.3.2 读写锁的实现原理
读写锁的实现通常依赖于两个锁:一个读锁和一个写锁。读锁允许多个线程同时获取,而写锁只允许一个线程获取。在获取写锁时,需要确保没有线程持有读锁或写锁。
在Redisson中,读写锁的实现基于Redis的原子操作和Lua脚本。Redisson通过两个键来分别控制读锁和写锁,并使用Lua脚本确保锁操作的原子性。
4.3.3 简单使用
public void performTaskWithReadWriteLock() {// 1. 获取读写锁对象RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("myReadWriteLock");// 2. 从读写锁对象中分别获取读锁和写锁RLock readLock = readWriteLock.readLock();RLock writeLock = readWriteLock.writeLock();try {// 3. 尝试获取读锁if (readLock.tryLock(10, 60, TimeUnit.SECONDS)) { try {System.out.println("获取读锁,正在执行读任务...");// 执行读任务} finally {// 4. 释放读锁readLock.unlock(); System.out.println("释放读锁。");}}// 5. 尝试获取写锁if (writeLock.tryLock(10, 60, TimeUnit.SECONDS)) { try {System.out.println("获取写锁,正在执行写任务...");// 执行写任务} finally {// 6. 释放写锁writeLock.unlock();System.out.println("释放写锁。");}}} catch (InterruptedException e) {e.printStackTrace();}
}
4.4 联锁
4.4.1 联锁的概念
联锁(MultiLock)是一种允许将多个锁关联在一起,实现“全部获取”或“全部释放”的锁机制。
- 全部获取: 只有当所有参与联锁的锁都被成功获取后,才算成功获取联锁。
- 全部释放: 释放联锁时,会自动释放所有参与联锁的锁。
联锁适用于需要同时获取多个资源的场景,例如分布式事务中需要锁定多个数据表。
4.4.2 联锁的实现原理
Redisson 的联锁基于 RedissonMultiLock
对象实现。RedissonMultiLock
对象可以将多个 RLock
对象关联在一起,并提供 tryLock()
和 unlock()
方法来统一管理这些锁。
在调用 tryLock()
方法时,RedissonMultiLock
会尝试依次获取所有参与联锁的锁。如果所有锁都获取成功,则返回 true
,否则释放已经获取到的锁,并返回 false
。
在调用 unlock()
方法时,RedissonMultiLock
会自动释放所有参与联锁的锁,无论这些锁是否被当前线程持有。
4.4.3 简单使用
public void performTaskWithMultiLock() {// 获取多个锁对象RLock lock1 = redissonClient.getLock("lock1");RLock lock2 = redissonClient.getLock("lock2");RLock lock3 = redissonClient.getLock("lock3");// 创建联锁对象RLock multiLock = redissonClient.getMultiLock(lock1, lock2, lock3);try {// 尝试获取联锁,等待 10 秒if (multiLock.tryLock(10, TimeUnit.SECONDS)) {try {System.out.println("获取联锁成功,正在执行任务...");// 执行需要所有锁的任务} finally {// 释放联锁multiLock.unlock();System.out.println("释放联锁。");}} else {System.out.println("获取联锁失败。");}} catch (InterruptedException e) {e.printStackTrace();}
}
代码分析:
- 获取多个锁对象: 首先,获取需要参与联锁的多个
RLock
对象。- 创建联锁对象: 使用
redissonClient.getMultiLock(lock1, lock2, lock3)
创建一个RLock
对象,并将之前获取的多个锁对象作为参数传入。- 尝试获取联锁: 调用
multiLock.tryLock(10, TimeUnit.SECONDS)
尝试获取联锁,最多等待 10 秒。- 执行任务: 如果成功获取联锁,则执行需要所有锁保护的任务。
- 释放联锁: 最后,在
finally
块中调用multiLock.unlock()
释放联锁,这会自动释放所有参与联锁的锁。
5. WatchDog机制
想象一下,我们正在进行一场激烈的拔河比赛。我们队好不容易抓住了绳子,眼看就要赢了,结果突然有人手滑,绳子就被对方抢走了!
在分布式系统中,获取锁就好像抓住这根拔河绳。Redisson 分布式锁的租约时间就好像我们抓住绳子的时间。如果在租约时间内,我们没有完成任务,锁就自动释放了,其他线程就有机会获取锁,这就像拔河比赛中我们手滑绳子被抢走一样,可能会导致数据不一致的问题。
为了避免这种情况发生,Redisson 提供了 Watch Dog 机制,就像我们队伍里安排了一个“观察员”。这位观察员会每隔一段时间关注我们是否还抓着绳子,如果发现我们快坚持不住了,就会及时提醒我们,让我们重新握紧绳子,并延长我们抓住绳子的时间。
具体来说,Redisson 的Watch Dog 机制会在 Redisson 实例被关闭前,不断的延长锁的有效期,也就是说,如果一个拿到锁的线程一直没有完成逻辑,那么看门狗会帮助线程不断的延长锁超时时间,锁不会因为超时而被释放。
**开启方式:**在获取锁的时候,不能指定leaseTime
或者只能将leaseTime
设置为-1,这样才能开启看门狗机制。
public void test() throws Exception {RLock lock = redissonClient.getLock("myLock");// 方式一: 不停重试,直到获取锁成功,具有 Watch Dog 自动延期机制,默认续约时间为 30 秒lock.lock(); // 方式二: 尝试获取锁 10 秒,获取成功返回 true,否则返回 false,具有 Watch Dog 自动延期机制,默认续约时间为 30 秒boolean res1 = lock.tryLock(10, TimeUnit.SECONDS); // 方式三: 尝试获取锁 10 秒,如果获取成功,则持有锁,否则抛出异常,leaseTime 为 10 秒,不会自动续约try {lock.lock(10, TimeUnit.SECONDS); } catch (InterruptedException e) {// 处理异常}// 方式四: 尝试获取锁 100 秒,如果获取成功,则持有锁 10 秒,leaseTime 为 10 秒,不会自动续约boolean res2 = lock.tryLock(100, 10, TimeUnit.SECONDS); Thread.sleep(40000L);lock.unlock();
}
6. 总结
在本文中,我们简要介绍了Redisson及其优势,介绍了如何在Spring Boot项目中集成Redisson。通过代码示例展示了基本的分布式锁用法,以及高级用法如公平锁、可重入锁、读写锁和联锁。除此之外我们还简要介绍了Redisson 的Watch Dog 机制,希望本文对大家有所帮助😊。
相关文章:

Redis学习——Redisson 分布式锁集成及其简单使用
文章目录 引言1. Redisson概述1.1 Redisson的基本概念1.2 Redisson的主要功能1.3 Redisson的优点 2. 开发环境3. Redisson的安装与配置3.1 添加依赖3.2 配置Redisson 4. 使用Redisson4.1 可重入锁4.1.1 可重入锁的概念4.1.2 可重入锁的实现原理4.1.3 简单使用锁的获取和释放 4.…...

08 - matlab m_map地学绘图工具基础函数 - 绘制线、图例、添加文字注释等函数
08 - matlab m_map地学绘图工具基础函数 - 绘制线、图例、添加文字注释等函数 0. 引言1. 关于m_line2. 关于m_quiver3. 关于m_text4. 关于m_plot5. 结语 0. 引言 本篇介绍下m_map中添加绘制基础线(m_line、m_plot)、绘制箭头(m_quiver&#x…...

Luminar Neo 1.20.0 (macOS Universal) - 创新 AI 图像编辑器
Luminar Neo 1.20.0 (macOS Universal) - 创新 AI 图像编辑器 利用尖端的人工智能生成技术,轻松增强照片效果 请访问原文链接:https://sysin.org/blog/luminar-neo/,查看最新版。原创作品,转载请保留出处。 作者主页࿱…...

谈谈Flink消费kafka的偏移量
offset配置: flinkKafkaConsumer.setStartFromEarliest():从topic的最早offset位置开始处理数据,如果kafka中保存有消费者组的消费位置将被忽略。 flinkKafkaConsumer.setStartFromLatest():从topic的最新offset位置开始处理数据,如果kafka中保存有消费…...

MySQL 高级SQL高级语句(二)
一.CREATE VIEW 视图 可以被当作是虚拟表或存储查询。 视图跟表格的不同是,表格中有实际储存数据记录,而视图是建立在表格之上的一个架构,它本身并不实际储存数据记录。 临时表在用户退出或同数据库的连接断开后就自动消失了,而…...

MySQL之高可用性(四)
高可用性 故障转移和故障恢复 冗余是很好的技术,但实际上只有在遇到故障需要恢复时才会用到。(见鬼,这可以用备份来实现)。冗余一点儿也不会增加可用性或减少宕机。在故障转移的过程中,高可用性是建立在冗余的基础上。当有一个组件失效&…...
招聘智能管理系统设计
设计一个招聘智能管理系统,需要从多个维度考虑,包括但不限于用户界面、功能模块、数据安全、算法模型等。以下是一个基本的设计框架: 1. 系统架构: 前端:提供直观的用户界面,包括应聘者和招聘者的登录/注册…...
达梦数据库系列—15. 表的备份和还原
目录 1、表备份 2、表还原 1、表备份 表备份和表还原恢复,都必须在联机状态下进行。 与备份数据库与表空间不同,不需要备份归档日志,不存在增量备份之说。 CREATE TABLE TAB_FOR_RES_02(C1 INT);CREATE INDEX I_TAB_FOR_RES_02 ON TAB_F…...

无线领夹麦克风哪个品牌音质最好,直播用领夹麦克风还是声卡麦
随着社交媒体的兴起,直播和Vlog已经成为内容创作的新趋势,这些变化不仅改变了人们分享生活的方式,也带动了音频设备市场的增长。无线领夹麦克风,以其便携性和卓越的录音品质,迅速成为视频制作者的重要工具。它们在直播…...

《Windows API每日一练》6.2 客户区鼠标消息
第五章已经讲到,Windows只会把键盘消息发送到当前具有输入焦点的窗口。鼠标消息则不同:当鼠标经过窗口或在窗口内被单击,则即使该窗口是非活动窗口或不带输入焦点, 窗口过程还是会收到鼠标消息。Windows定义了 21种鼠标消息。不过…...

体验升级:扫描全能王智能高清滤镜2.0全面测评
🤵♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞Ǵ…...

【JVM系列】JVM调优
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Linux基础 - Postfix 与 Dovecot 部署邮件系统
目录 零. 简介 一. 部署 二. 设置用户别名信箱 三. Linux 邮件客户端 零. 简介 Postfix 和 Dovecot 是在 Linux 系统中常用于部署邮件系统的两个重要组件。 Postfix 是一种邮件传输代理(MTA),主要负责接收、转发和发送邮件。它具有高性能…...

Qt的安装
一、Qt安装 下载地址:https://download.qt.io/archive/qt/ opencv下载安装 下载地址:https://opencv.org/releases/ 陈年旧文,没有下文,以此纪念。。。。。...

ThreeJS-3D教学十二:ShaderMaterial
一、首先 Shader 是做什么的 Shader 可以自定义每个顶点、每个片元/像素如何显示,而控制顶点和片元显示是通过设置 vertexShader 顶点着色器和 fragmentShader 片元着色器,这两个着色器用在 ShaderMaterial 和 RawShaderMaterial 材质上。 我们先看一个例…...

计算机网络面试TCP篇之TCP三次握手与四次挥手
TCP 三次握手与四次挥手面试题 任 TCP 虐我千百遍,我仍待 TCP 如初恋。 巨巨巨巨长的提纲,发车!发车! PS:本次文章不涉及 TCP 流量控制、拥塞控制、可靠性传输等方面知识,这些知识在这篇: TCP …...

Python-数据分析组合可视化实例图【附完整源码】
数据分析组合可视化实例图 开篇:应女朋友的要求,于是写下了这篇详细的数据可视化代码及完整注释 一:柱状图、折线图横向组合网格布局 本段代码使用了pyecharts库来创建一个包含多个图表(柱状图、折线图)和网格布局的…...

【JavaEE】Spring Web MVC详解
一.基本概念. 1.什么是Spring Web MVC? 官方链接: https://docs.spring.io/spring-framework/reference/web/webmvc.html Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning…...

docker安装rocketMq5x以上的版本
1.背景 安装RocketMQ 5.x以上的版本主要是因为新版本引入了许多性能优化、新功能以及对已有特性的增强,这些改进可以帮助提升消息队列系统的稳定性和效率。 1.性能提升:RocketMQ 5.x版本通常包括了对消息处理速度、吞吐量和延迟的优化,使得系…...

【Spring】DAO 和 Repository 的区别
DAO 和 Repository 的区别 1.概述2.DAO 模式2.1 User2.2 UserDao2.3 UserDaoImpl 3.Repository 模式3.1 UserRepository3.2 UserRepositoryImpl 4.具有多个 DAO 的 Repository 模式4.1 Tweet4.2 TweetDao 和 TweetDaoImpl4.3 增强 User 域4.4 UserRepositoryImpl 5.比较两种模式…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...