go-redis的基本使用

news2024/9/20 18:44:19

Golang操作Redis

安装go-redis

//redis 6
go get github.com/go-redis/redis/v8
//redis 7
go get github.com/go-redis/redis/v9
  1. golang连接redis

    import "github.com/go-redis/redis/v8"
    var rdb *redis.Client
    
    func init() {
        rdb := redis.NewClient(&redis.Options{
    	Addr:	  "localhost:6379",
    	Password: "", // no password set
    	DB:		  0,  // use default DB
        })
    }
    
  2. 通过go向redis写入数据

    ctx := context.Background()
    	//0代表永不过期
    err := rdb.Set(ctx, "gorediskey", "goredisvalue", 0).Err()
    if err != nil {
    	panic(err)
    }
    
  3. 读取数据

    val, err := rdb.Get(ctx, "name1").Result()
    if err != nil {
    	panic(err)
    }
    fmt.Println(val)
    //或者
    val, err := rdb.Do(ctx, "get", "gorediskey").Result()
    if err != nil {
    	if err == redis.Nil {
    		fmt.Println("gorediskey 不存在")
    		return
    	}
    	panic(err)
    }
    fmt.Println("do operator : gorediskey", val.(string))
    

基本使用

string类型

1. Set

err := rdb.Set(ctx, "gorediskey", "goredisvalue", 0).Err()
	if err != nil {
		panic(err)
	}

2. Get

value, err := rdb.Get(ctx, "gorediskey").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("gorediskey", value)

3. GetSet

设置一个key的值,并返回这个key的旧值

oldVal, err := rdb.GetSet(ctx, "gorediskey", "new value").Result()

	if err != nil {
		panic(err)
	}
	// 打印key的旧值
	fmt.Println("key", oldVal)

4. SetNX

如果key不存在,则设置这个key的值

  err := rdb.SetNX(ctx, "key1", "value", 0).Err()
	if err != nil {
		panic(err)
	}

5. MGet

批量查询key的值

vals, err := rdb.MGet(ctx, "key1", "key2", "key3").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println(vals)

6. MSet

批量设置key的值

err := rdb.MSet(ctx, "key1", "value1", "key2", "value2", "key3", "value3").Err()
	if err != nil {
		panic(err)
	}

7. Incr,IncrBy

针对一个key的数值进行递增操作

8. Decr,DecrBy

针对一个key的数值进行递减操作

9. Del

删除key操作,支持批量删除

// 删除key
	rdb.Del(ctx, "key")

	// 删除多个key, Del函数支持删除多个key
	err := rdb.Del(ctx, "key1", "key2", "key3").Err()
	if err != nil {
		panic(err)
	}

10. Expire

设置key的过期时间

rdb.Expire(ctx, "key", 3*time.Second)

Hash类型

  1. HSet

根据key和field字段设置,field字段的值

// user_1 是hash key,username 是字段名, zhangsan是字段值
err := rdb.HSet(ctx,"user_1", "username", "zhangsan").Err()
if err != nil {
	panic(err)
}

2. HGet

根据key和field字段,查询field字段的值

// user_1 是hash key,username是字段名
username, err := rdb.HGet(ctx,"user_1", "username").Result()
if err != nil {
	panic(err)
}
fmt.Println(username)

3. HGetAll

根据key查询所有字段和值

// 一次性返回key=user_1的所有hash字段和值
data, err := rdb.HGetAll(ctx,"user_1").Result()
if err != nil {
	panic(err)
}

// data是一个map类型,这里使用使用循环迭代输出
for field, val := range data {
	fmt.Println(field,val)
}

4. HIncrBy

根据key和field字段,累加字段的数值

// 累加count字段的值,一次性累加2, user_1为hash key
count, err := rdb.HIncrBy(ctx,"user_1", "count", 2).Result()
if err != nil {
	panic(err)
}

fmt.Println(count)

5. HKeys

根据key返回所有字段名

// keys是一个string数组
keys, err := rdb.HKeys(ctx,"user_1").Result()
if err != nil {
	panic(err)
}

fmt.Println(keys)

6. HLen

根据key,查询hash的字段数量

size, err := rdb.HLen(ctx,"user_1").Result()
if err != nil {
	panic(err)
}

fmt.Println(size)

7. HMGet

根据key和多个字段名,批量查询多个hash字段值

// HMGet支持多个field字段名,意思是一次返回多个字段值
vals, err := rdb.HMGet(ctx,"user_1","username", "count").Result()
if err != nil {
	panic(err)
}

// vals是一个数组
fmt.Println(vals)

8. HMSet

根据key和多个字段名和字段值,批量设置hash字段值

// 初始化hash数据的多个字段值
data := make(map[string]interface{})
data["id"] = 1
data["username"] = "lisi"

// 一次性保存多个hash字段值
err := rdb.HMSet(ctx,"key", data).Err()
if err != nil {
	panic(err)
}

9. HSetNX

如果field字段不存在,则设置hash字段值

err := rdb.HSetNX(ctx,"key", "id", 100).Err()
if err != nil {
	panic(err)
}

10. HDel

根据key和字段名,删除hash字段,支持批量删除hash字段

// 删除一个字段id
rdb.HDel(ctx,"key", "id")

// 删除多个字段
rdb.HDel(ctx,"key", "id", "username")

11. HExists

检测hash字段名是否存在

// 检测id字段是否存在
result, err2 := rdb.HExists(ctx, "key", "id").Result()
if err2 != nil {
	panic(err2)
}
fmt.Println(result)

List类型

1. LPush

从列表左边插入数据

// 插入一个数据
rdb.LPush(ctx,"key", "data1")

// LPush支持一次插入任意个数据
err := rdb.LPush(ctx,"key", 1,2,3,4,5).Err()
if err != nil {
	panic(err)
}

2. LPushX

跟LPush的区别是,仅当列表存在的时候才插入数据,用法完全一样。

err := rdb.LPushX(ctx, "key", "sss").Err()
	if err != nil {
		panic(err)
	}

3. RPop

从列表的右边删除第一个数据,并返回删除的数据

val, err := rdb.RPop(ctx,"key").Result()
if err != nil {
	panic(err)
}

fmt.Println(val)

4. RPush

从列表右边插入数据

// 插入一个数据
rdb.RPush(ctx,"key", "data1")

// 支持一次插入任意个数据
err := rdb.RPush(ctx,"key", 1,2,3,4,5).Err()
if err != nil {
	panic(err)
}

5. RPushX

跟RPush的区别是,仅当列表存在的时候才插入数据, 他们用法一样

err := rdb.RPushX(ctx,"key", "right_x").Err()
if err != nil {
	panic(err)
}

6. LPop

从列表左边删除第一个数据,并返回删除的数据

val, err := rdb.LPop(ctx,"key").Result()
if err != nil {
	panic(err)
}

fmt.Println(val)

7. LLen

返回列表的大小

val, err := rdb.LLen(ctx,"key").Result()
if err != nil {
	panic(err)
}

fmt.Println(val)

8. LRange

返回列表的一个范围内的数据,也可以返回全部数据

// 返回从0开始到-1位置之间的数据,意思就是返回全部数据
vals, err := rdb.LRange(ctx,"key",0,-1).Result()
if err != nil {
	panic(err)
}
fmt.Println(vals)

9. LRem

删除列表中的数据

// 从列表左边开始,删除100, 如果出现重复元素,仅删除1次,也就是删除第一个
dels, err := rdb.LRem(ctx,"key",1,100).Result()
if err != nil {
	panic(err)
}
fmt.Println(dels)

// 如果存在多个100,则从列表左边开始删除2个100
rdb.LRem(ctx,"key",2,100)


// 如果存在多个100,则从列表右边开始删除2个100
// 第二个参数负数表示从右边开始删除几个等于100的元素
rdb.LRem(ctx,"key",-2,100)

// 如果存在多个100,第二个参数为0,表示删除所有元素等于100的数据
rdb.LRem(ctx,"key",0,100)

10. LIndex

根据索引坐标,查询列表中的数据

// 列表索引从0开始计算,这里返回第6个元素
val, err := rdb.LIndex(ctx,"key",5).Result()
if err != nil {
	panic(err)
}

fmt.Println(val)

11. LInsert

在指定位置插入数据

// 在列表中5的前面插入4
// before是之前的意思
err := rdb.LInsert(ctx,"key","before", 5, 4).Err()
if err != nil {
	panic(err)
}

// 在列表中 zhangsan 元素的前面插入 欢迎你
rdb.LInsert(ctx,"key","before", "zhangsan", "欢迎你")

// 在列表中 zhangsan 元素的后面插入 2022
rdb.LInsert(ctx,"key","after", "zhangsan", "2022")

Set

1. SAdd

添加集合元素

// 添加100到集合中
err := rdb.SAdd(ctx,"key",100).Err()
if err != nil {
	panic(err)
}

// 将100,200,300添加到集合中
rdb.SAdd(ctx,"key",100, 200, 300)

2. SCard

获取集合元素个数

size, err := rdb.SCard(ctx,"key").Result()
if err != nil {
	panic(err)
}
fmt.Println(size)

3. SIsMember

判断元素是否在集合中

// 检测100是否包含在集合中
ok, _ := rdb.SIsMember(ctx,"key", 100).Result()
if ok {
	fmt.Println("集合包含指定元素")
}

4. SMembers

获取集合中所有的元素

es, _ := rdb.SMembers(ctx,"key").Result()
// 返回的es是string数组
fmt.Println(es)

5. SRem

删除集合元素

// 删除集合中的元素100
	rdb.SRem(ctx, "key", 100)

	// 删除集合中的元素200和300
	rdb.SRem(ctx, "key", 200, 300)

6. SPop,SPopN

随机返回集合中的元素,并且删除返回的元素

// 随机返回集合中的一个元素,并且删除这个元素
val, _ := rdb.SPop(ctx,"key").Result()
fmt.Println(val)

// 随机返回集合中的5个元素,并且删除这些元素
vals, _ := rdb.SPopN(ctx,"key", 5).Result()
fmt.Println(vals)

sorted set

1. ZAdd

添加一个或者多个元素到集合,如果元素已经存在则更新分数

// 添加一个集合元素到集合中, 这个元素的分数是2.5,元素名是zhangsan
err := rdb.ZAdd(ctx, "key", &redis.Z{Score: 2.5, Member: "zhangsan"}).Err()
if err != nil {
		panic(err)
}	

2. ZCard

返回集合元素个数

size, err := rdb.ZCard(ctx,"key").Result()
if err != nil {
	panic(err)
}
fmt.Println(size)

3. ZCount

统计某个分数范围内的元素个数

// 返回: 1<=分数<=5 的元素个数, 注意:"1", "5"两个参数是字符串
size, err := rdb.ZCount(ctx,"key", "1","5").Result()
if err != nil {
	panic(err)
}
fmt.Println(size)

// 返回: 1<分数<=5 的元素个数
// 说明:默认第二,第三个参数是大于等于和小于等于的关系。
// 如果加上( 则表示大于或者小于,相当于去掉了等于关系。
size, err := rdb.ZCount(ctx,"key", "(1","5").Result()

4. ZIncrBy

增加元素的分数

// 给元素zhangsan,加上2分
rdb.ZIncrBy(ctx,"key", 2,"zhangsan")

5. ZRange,ZRevRange

返回集合中某个索引范围的元素,根据分数从小到大排序

// 返回从0到-1位置的集合元素, 元素按分数从小到大排序
// 0到-1代表则返回全部数据
vals, err := rdb.ZRange(ctx,"key", 0,-1).Result()
if err != nil {
	panic(err)
}

for _, val := range vals {
	fmt.Println(val)
}

ZRevRange用法跟ZRange一样,区别是ZRevRange的结果是按分数从大到小排序。

6. ZRangeByScore

根据分数范围返回集合元素,元素根据分数从小到大排序,支持分页。

// 初始化查询条件, Offset和Count用于分页
op := redis.ZRangeBy{
	Min:"2", // 最小分数
	Max:"10", // 最大分数
	Offset:0, // 类似sql的limit, 表示开始偏移量 
	Count:5, // 一次返回多少数据
}
	
vals, err := rdb.ZRangeByScore(ctx,"key", &op).Result()
if err != nil {
	panic(err)
}

for _, val := range vals {
	fmt.Println(val)
}

7. ZRevRangeByScore

用法类似ZRangeByScore,区别是元素根据分数从大到小排序。

8. ZRangeByScoreWithScores

用法跟ZRangeByScore一样,区别是除了返回集合元素,同时也返回元素对应的分数

// 初始化查询条件, Offset和Count用于分页
op := redis.ZRangeBy{
	Min:"2", // 最小分数
	Max:"10", // 最大分数
	Offset:0, // 类似sql的limit, 表示开始偏移量
	Count:5, // 一次返回多少数据
}

vals, err := rdb.ZRangeByScoreWithScores(ctx,"key", &op).Result()
if err != nil {
	panic(err)
}

for _, val := range vals {
	fmt.Println(val.Member) // 集合元素
	fmt.Println(val.Score) // 分数
}

9. ZRem

删除集合元素

// 删除集合中的元素zhangsan
rdb.ZRem(ctx,"key", "zhangsan")

// 删除集合中的元素zhangsan和zhangsan1
// 支持一次删除多个元素
rdb.ZRem(ctx,"key", "zhangsan", "zhangsan1")

10. ZRemRangeByRank

根据索引范围删除元素

// 集合元素按分数排序,从最低分到高分,删除第0个元素到第5个元素。
// 这里相当于删除最低分的几个元素
rdb.ZRemRangeByRank(ctx,"key", 0, 5)

// 位置参数写成负数,代表从高分开始删除。
// 这个例子,删除最高分数的两个元素,-1代表最高分数的位置,-2第二高分,以此类推。
rdb.ZRemRangeByRank(ctx,"key", -1, -2)

11.ZRemRangeByScore

根据分数范围删除元素

// 删除范围: 2<=分数<=5 的元素
rdb.ZRemRangeByScore(ctx,"key", "2", "5")

// 删除范围: 2<=分数<5 的元素
rdb.ZRemRangeByScore(ctx,"key", "2", "(5")

12. ZScore

查询元素对应的分数

// 查询集合元素zhangsan的分数
score, _ := rdb.ZScore(ctx,"key", "zhangsan").Result()
fmt.Println(score)

13. ZRank

根据元素名,查询集合元素在集合中的排名,从0开始算,集合元素按分数从小到大排序

rk, _ := rdb.ZRank(ctx,"key", "zhangsan").Result()
fmt.Println(rk)

ZRevRank的作用跟ZRank一样,区别是ZRevRank是按分数从大到小排序。

其他操作

发布订阅

Redis提供了发布订阅功能,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。

img

发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。

1. Subscribe

订阅channel

	// 订阅channel1这个channel
	sub := rdb.Subscribe(ctx, "channel1")
	// sub.Channel() 返回go channel,可以循环读取redis服务器发过来的消息
	for msg := range sub.Channel() {
		// 打印收到的消息
		fmt.Println(msg.Channel)
		fmt.Println(msg.Payload)
	}
//或者
for {
		msg, err := sub.ReceiveMessage(ctx)
		if err != nil {
			panic(err)
		}
		fmt.Println(msg.Channel, msg.Payload)
	}

2. Publish

将消息发送到指定的channel

// 将"message"消息发送到channel1这个通道上
rdb.Publish(ctx,"channel1","message")

3. PSubscribe

用法跟Subscribe一样,区别是PSubscribe订阅通道(channel)支持模式匹配。

// 订阅channel1这个channel
sub := rdb.PSubscribe(ctx,"ch_user_*")
// 可以匹配ch_user_开头的任意channel

4. Unsubscribe

取消订阅

// 订阅channel1这个channel
sub := rdb.Subscribe(ctx,"channel1")
// 取消订阅
sub.Unsubscribe(ctx,"channel1")

5. PubSubNumSub

查询指定的channel有多少个订阅者

// 查询channel_1通道的订阅者数量
	chs, _ := rdb.PubSubNumSub(ctx, "channel_1").Result()
	for ch, count := range chs {
		fmt.Println(ch)    // channel名字
		fmt.Println(count) // channel的订阅者数量
	}

事务处理

redis事务可以一次执行多个命令, 并且带有以下两个重要的保证:

  • 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

1. TxPipeline

以Pipeline的方式操作事务

// 开启一个TxPipeline事务
pipe := rdb.TxPipeline()

// 执行事务操作,可以通过pipe读写redis
incr := pipe.Incr(ctx,"tx_pipeline_counter")
pipe.Expire(ctx,"tx_pipeline_counter", time.Hour)

// 上面代码等同于执行下面redis命令
//
//     MULTI
//     INCR pipeline_counter
//     EXPIRE pipeline_counts 3600
//     EXEC

// 通过Exec函数提交redis事务
_, err := pipe.Exec(ctx)

// 提交事务后,我们可以查询事务操作的结果
// 前面执行Incr函数,在没有执行exec函数之前,实际上还没开始运行。
fmt.Println(incr.Val(), err)

2. watch

redis乐观锁支持,可以通过watch监听一些Key, 如果这些key的值没有被其他人改变的话,才可以提交事务

ctx := context.Background()

	// 定义一个回调函数,用于处理事务逻辑
	fn := func(tx *redis.Tx) error {
		// 先查询下当前watch监听的key的值
		v, err := tx.Get(ctx, "key").Int()
		if err != nil && err != redis.Nil {
			return err
		}
		// 这里可以处理业务
		v++

		// 如果key的值没有改变的话,Pipelined函数才会调用成功
		_, err = tx.Pipelined(ctx, func(pipe redis.Pipeliner) error {
			// 在这里给key设置最新值
			pipe.Set(ctx, "key", v, 0)
			return nil
		})
		return err
	}

	// 使用Watch监听一些Key, 同时绑定一个回调函数fn, 监听Key后的逻辑写在fn这个回调函数里面
	// 如果想监听多个key,可以这么写:client.Watch(ctx,fn, "key1", "key2", "key3")
	rdb.Watch(ctx, fn, "key")

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

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

相关文章

云原生之深入解析Prometheus AlertManager的实战操作

一、概述 Prometheus 包含一个报警模块&#xff0c;就是 AlertManager&#xff0c;Alertmanager 主要用于接收 Prometheus 发送的告警信息&#xff0c;它支持丰富的告警通知渠道&#xff0c;而且很容易做到告警信息进行去重、降噪、分组等&#xff0c;是一款前卫的告警通知系统…

Android Studio实现内容丰富的安卓校园二手交易平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号038 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看二手商品…

[学习笔记] 扩散模型 Diffusion

前置知识-从深度生成模型、隐变量、VAE开始 机器学习是人工智能的一种&#xff0c;它是一种通过利用数据&#xff0c;训练出模型&#xff0c;然后使用模型预测的一种方法。 机器学习分为监督学习、无监督学习和强化学习&#xff0c;这是根据数据训练方式分类的&#xff0c;通俗…

leetcode 100. 相同的树

2023.7.6 这题类似于树的对称性这道题&#xff0c;下面给出递归和迭代两种解法&#xff1a; 递归法&#xff1a; class Solution { public:bool isSameTree(TreeNode* p, TreeNode* q) {if(pnullptr && qnullptr) return true;if(pnullptr && q!nullptr || p…

python实现文本转语音音频

文章目录 文本转语音音频第一步&#xff1a;讯飞平台的注册第二步&#xff1a;导入程序所需要的依赖库第二步&#xff1a;websocket对象类的初始化第三步&#xff1a;websocket建立连接后的函数第四步&#xff1a;websocket数据返回结果的处理函数第五步&#xff1a;pcm音频转换…

VALSE 20200415 | 机器学习 vs 压缩感知:核磁共振成像与重建

【Talk】VALSE 20200415 | 机器学习 vs 压缩感知&#xff1a;核磁共振成像与重建 文章目录 【Talk】VALSE 20200415 | 机器学习 vs 压缩感知&#xff1a;核磁共振成像与重建Deep learning for MR imaging and analysis - Shanshan WangMachine Learning for CS MRI: From Model…

Spring Boot 中的视图解析器是什么,如何使用

Spring Boot 中的视图解析器是什么&#xff0c;如何使用 在 Spring Boot 中&#xff0c;视图解析器是将视图名称解析为具体视图对象的组件。视图对象可以是 JSP、FreeMarker、Thymeleaf 等模板引擎生成的 HTML 页面&#xff0c;也可以是 JSON、XML 等格式的数据响应。Spring B…

基于Javaweb实现ATM机系统开发实战(三)用户查询功能实现

首先通过我们查看前端界面发现&#xff0c;先要实现前端用户查询功能&#xff0c;主要就是要把list1和list2所需的数据传递给前端&#xff0c;由前端进行展示。 首先我们需要写一个servlet处理收到的请求&#xff1a; ps&#xff1a;Servlet是什么&#xff1f; Java Servlet 是…

FreeRTOS ~(五)队列的常规使用 ~ (1/5)队列解决同步缺陷

前情提要 FreeRTOS ~&#xff08;四&#xff09;同步互斥与通信 ~ &#xff08;1/3&#xff09;同步的缺陷 举例子说明&#xff1a;利用队列解决前述的"同步的缺陷"问题 static int sum 0; /* sum存放计算的结果 */ static volatile int flagCalcEnd 0; /* 标…

哪款3D虚拟人物建模软件好用?

3D虚拟人物建模软件一直以来受到许多人的关注和追捧。现在&#xff0c;随着智能手机的普及&#xff0c;3D虚拟人物手机建模软件也开始走进大家的视野。那么&#xff0c;市面上3D虚拟人物建模软件这么多&#xff0c;究竟哪款3D虚拟人物建模软件是好用的呢&#xff1f; 首先&…

【聚类算法】OPTICS基于密度聚类

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 对DBSCAN的补充&#xff0c;OPTICS聚类 1. 正文 1.0 DBSCAN的存在问题 前面我们介绍了DBSCAN&#xff0c;其能根据密度进行聚类。 但其存在这样一个问…

cv2 安装问题, opencv

解决安装了opencv-python&#xff0c;但 import cv2 报错。 需要安装&#xff1a; pip install opencv-python-headless

VS 2022 修改应用程序选择目标框架为4.8

一、设置访问项目属性为True 打开工具菜单---选项---适用于Unity的工具 将这个访问项目属性一栏设置为True。之后要解决方案再重新打开即可生效。 二、设置应用程序选择目标框架 点击项目-->属性-->应用程序选择目标框架为.netfromwork4.8

Java入门程序——运算符

文章目录 赋值运算符算术运算符自增运算符自减运算符 比较&#xff08;关系&#xff09;运算符逻辑运算符逻辑运算符——快速运算&#xff08;短路运算&#xff09; 复合赋值运算符条件运算符字符串连接运算符三元运算符总结 赋值运算符 • 格式&#xff1a;变量名表达式&…

1.7 用户注册_判断用户是否存在和自定义响应数据结构

步骤1&#xff1a;在顶级pom.xml添加常用工具依赖。 <!-- apache 工具类 --> <dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.11</version> </dependency> <depen…

实现TCP通信(socket套接字)

一、TCP通信实现的过程 服务器端 socket函数 与 通信域 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); -domain: 指定通信域&#xff08;通信地址族&#xff09;; -type: 指定套接字类型; -protocol: 指定协…

大象机器人myCobot 280 2023版全新功能展示

引言 机械臂是一种可编程的、自动化的机械系统&#xff0c;它可以模拟人类的动作&#xff0c;完成各种任务&#xff0c;例如装配、喷涂、包装、搬运、焊接、研磨等。由于其高度灵活性和多功能性&#xff0c;机械臂在现代社会中已经得到了广泛的应用。 myCobot 280 M5Stack 202…

项目需求管理

项目需求管理的五大过程 一、需求获取 编写项目视图 范围文档 用户群分类 选择用户代表 建立核心队伍 确定使用实例 召开联合会议 分析用户工作流程、 确定质量属性、 检查问题报告 需求重用 二、需求分析 1、绘制关联图&#xff0c;用于定义系统与系统外部实体间的边界和接口的…

多个六轴机械臂联合作业搬运仿真(机器人工具箱)

1、建立三个六轴机械臂、工作平台与货物 clear clc close all % theta d a alpha sigma L1Link([0 0 0 pi/2 0 ]);%连杆1参数 L2Link([0 -0.1455 0.4375 0 0 ]);L2.offsetpi/2;%连杆2参数 L3Link(…

Playwright自动化测试工具 java版本

Playwright 第一个程序 public static void main(String[] args) {Playwright playwright Playwright.create(); // Browser browser playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(false));BrowserType.LaunchOptions launchOptions …