Go gorm库(详细版)

目录

01. 什么是ORM

02. 环境搭建

03. 连接数据库

高级设置

gorm 的命名策略

创建表

日志显示

04. 模型定义

定义一张表

自动生成表结构

修改表字段大小

字段标签

05. 单表查询

5.1 表结构

5.2 添加单条记录

5.3 批量插入

5.4 单条数据查询

5.5 根据主键查询

5.6 根据结构体进行查询

5.7 获取查询的结构

5.8 查询多条记录并返回Json数据

5.9 根据主键列表去查询

06. 更新数据

6.1 Save 保存所有字段

Select更新指定字段​编辑

6.2 Update批量更新

6.3 Updates更新

07. 删除数据

08. 添加钩子函数(HOOK)

09. Gorm高级查询

9.01 Where查询

9.02 Select 选择字段

9.03 排序

9.04 分页查询

9.05 去重

​编辑9.06 分组查询

9.07 gorm执行原生sql

9.08 子查询

9.09 命名参数

9.10 从Find到Map

9.11 查询引用Scope

10. 一对多关系

10.1 表结构建立

重写外键关联

10.2 添加数据

外键添加

10.3 查询数据

预加载

嵌套预加载

带条件的预加载

自定义预加载

10.4 删除数据

级联删除

清除外键关系

11. 一对一关系

表结构搭建

添加记录

查询

删除

12. 多对多关系

12.1 表结构搭建

12.2 添加

添加文章,并创建标签

创建文章,添加已有标签

12.3 查询

12.4 更新

12.5 多对多自定义连接表(第三张表)

12.5.1 表结构及生成

12.5.2 操作案例

1. 添加文章并添加标签,并自动关联

2. 添加文章,关联已有标签

3. 给已有文章关联标签

4. 替换已有文章的标签

5. 查询文章列表,显示标签

SetupJoinTable

12.5.3 自定义连接表主键

生成表结构

12.5.4 操作连接表(自定义连接表的时候)

13. 自定义数据类型

13.1 存储json

插入数据

查询数据

13.2 存储数组

13.3 枚举类型

枚举1.0

枚举2.0

枚举3.0(用这个)

在grom中使用

14. gorm 事务

14.1 普通事务

14.2 手动事务


01. 什么是ORM

02. 环境搭建

go mod init 文件名

go get gorm.io/driver/mysql //mysql的驱动

go get "gorm.io/gorm"

03. 连接数据库

package mainimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm"
)// 定义一个全局变量db,用于后面数据库的读写操作,通常就放在全局里面
var DB *gorm.DBfunc init() {username := "root"       //账号password := "password"   //密码host := "IP"             //数据库地址port := "3306"           //端口Dnname := "dtbase"       //数据库名timeout := "10s"         //连接超时,10s//root:root@tcp(127.0.0.1:3306)/test?dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?timeout=%s", username, password, host, port, Dnname, timeout)//连接mysql,获得DB类型实例,用于后面数据库的读写操作db, err := gorm.Open(mysql.Open(dsn))if err != nil {panic("连接数据库失败,error=" + err.Error())}DB = db//连接成功fmt.Println("连接数据库成功")
}func main() {}

高级设置

是在open的地方设置

gorm 的命名策略

创建表

注意虽然我们的结构为Student,但是表名却是studens,并且字段全小写,至于为什么是这样,就是我们上面gorm命名规则的原因了

日志显示

gorm默认日志是只打印错误和慢sql,我们可以设置日志的显示等级

可以设置日志等级为info,但是这样显示会很占用空间

推荐:

04. 模型定义

模型是标准的 struct ,由Go的基本数据类型,实现了Scanner和Valuer接口的自定义类型及其指针或别名组成

定义一张表

PS:小写属性是不会生成字段的

自动生成表结构

AutoMigrate的逻辑是只新增,不擅长,不修改(大小会修改)

例如将 Name 修改为 Name1,进行迁移,会多出一个name1的字段

新增Email和改Name为Name1

修改表字段大小

有两种方式

下面那种样例

字段标签

05. 单表查询

5.1 表结构

5.2 添加单条记录

添加记录就是实例化结构体

有两条是因为点了两下哈

如果此时

那么他们分别是空字符串和null

这就是指针的好处,当然email也可以直接传nil因为他是指针

还可以打印s1看看

5.3 批量插入

Creat方法还可以用于插入多条记录

5.4 单条数据查询

会查询第一个数据

Take就是传统的:SELECT * FROM 'students' LIMIT 1

而Frist和Last是按照主键去查询的:SELECT * FROM 'students' ORDER BY 'studens'.'id' LIMIT 1

5.5 根据主键查询

注意这是前端传进来的话一定要用?拼接,不能fprintf,这样可以有效防止sql注入

5.6 根据结构体进行查询

但是注意只能根据主键查询

5.7 获取查询的结构

5.8 查询多条记录并返回Json数据

5.9 根据主键列表去查询

根据其他条件就可以

DB.Find(&studentList,"name in ?",[]string{"yuanlai","chenchen"})

06. 更新数据

有三个操作可以进行,Save,Uptate,Updates

6.1 Save 保存所有字段

用于单个记录的全字段更新,他会保存所有的字段,即使零值也会保存 

相当于:UPDATE 'students_two' SET 'name'='y145','age'=23,'gender'=true,'emaI'=2777137742@qq.com WHERE 'id'=1

Select更新指定字段

6.2 Update批量更新

或者Model

6.3 Updates更新

可以传结构体

也可以传map

07. 删除数据

08. 添加钩子函数(HOOK)

比如再插入一条数据之前,我想要做一点事情

其实就是实现一个 BeforeCreate 的方法

在实现BeforeCreate之后

插入这个

09. Gorm高级查询

9.01 Where查询

我们重构一些数据

上面用了一个函数,传string返回他的地址,这样插入的时候好看些

然后正文,这个Where就等价于mysql的where

9.02 Select 选择字段

因为直接Find是select * 比较耗费性能

9.03 排序

9.04 分页查询

先看纯sql的分页查询

9.05 去重

 先看sql去重

gorm去重(Scan就是把前面得到的结果给Scan里面的结构体)


9.06 分组查询

sql拼接名字

gorm写法

9.07 gorm执行原生sql

就上面例子来说,就是DB.Raw("saw_sql").Scan(&groupList)

9.08 子查询

子查询就是使用上次查询的结果来作为这次查询的参数

9.09 命名参数

我们之前是?,但是如果查询语句比较多,看的就不直观,orm就可以提供像@name(给参数命名)这样的方式

9.10 从Find到Map

我们每次查询的时候,都要写一个变量去接收查到的值,感觉很麻烦

(之前的 var students []Student,这个students用来Find(&students)传参的)

我们就可以用一个map来接收

emmmmmm好像没什么区别

9.11 查询引用Scope

10. 一对多关系

10.1 表结构建立

对于外键的命名,我们这里就必须要叫做UserID,其他的就不可以

或者不一样的话,我们就需要重写外键关联

重写外键关联

这就要注意,两边都要加上

10.2 添加数据

创建用户的时候创建文章

创建文章的时候,再去关联用户

又或者,但是这样就会又创建一个新的用户去关联他

又或者,不创建user,用已经有的

外键添加

其中Association和Append的方式更常用

10.3 查询数据

预加载

嵌套预加载

带条件的预加载

自定义预加载

10.4 删除数据

级联删除

清除外键关系

11. 一对一关系

表结构搭建

PS:UserInfo里面用指针是因为如果不用,就是和User相互引用了

添加记录

查询

删除

删除和一对多是一样的

12. 多对多关系

多对多关系,需要用第三张表存储两张表的关系

12.1 表结构搭建

12.2 添加

添加文章,并创建标签

查看表

创建文章,添加已有标签

12.3 查询

查询文章,显示文章的标签列表

查询标签,显示文章列表

12.4 更新

之前的方式

gorm提供的方法

让tag1替换为tag2

12.5 多对多自定义连接表(第三张表)

默认的连接表,只有双方的主键id,展示不了更多信息了,比如我们现在想要连接表里面添加数据的时候加上添加的时间,这个时候就需要自定义连接表,这就是他的意义

12.5.1 表结构及生成

注意`form:"many2many:article_tags"` article_tags这个名字是对应ArticleTag的,这个是对应的然后加上 _ 和 s,要是想改gorm里面的名字,那么AticleTag也要改

// 设置Article的Tags表为ArticleTag
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
// 如果tag要反向应用Article,那么也得加上
// DB.SetupJoinTable(&Tag{}, "Articles", &ArticleTag{})
err := DB.AutoMigrate(&Article{}, &Tag{}, &ArticleTag{})
fmt.Println(err)

12.5.2 操作案例

举一些简单的例子

  1. 添加文章并添加标签,并自动关联

  2. 添加文章,关联已有标签

  3. 给已有文章关联标签

  4. 替换已有文章的标签

  5. 添加文章并添加标签,并自动关联

1. 添加文章并添加标签,并自动关联
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})  // 要设置这个,才能走到我们自定义的连接表
DB.Create(&Article{Title: "flask零基础入门",Tags: []Tag{{Name: "python"},{Name: "后端"}, {Name: "web"},},
})
// CreatedAt time.Time 由于我们设置的是CreatedAt,gorm会自动填充当前时间,
// 如果是其他的字段,需要使用到ArticleTag 的添加钩子 BeforeCreate
2. 添加文章,关联已有标签
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
var tags []Tag
DB.Find(&tags, "name in ?", []string{"python", "web"})
DB.Create(&Article{Title: "flask请求对象",Tags:  tags,
})
3. 给已有文章关联标签
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
article := Article{Title: "django基础",
}
DB.Create(&article)
var at Article
var tags []Tag
DB.Find(&tags, "name in ?", []string{"python", "web"})
DB.Take(&at, article.ID).Association("Tags").Append(tags)
4. 替换已有文章的标签
var article Article
var tags []Tag
DB.Find(&tags, "name in ?", []string{"后端"})
DB.Take(&article, "title = ?", "django基础")
DB.Model(&article).Association("Tags").Replace(tags)
5. 查询文章列表,显示标签
var articles []Article
DB.Preload("Tags").Find(&articles)
fmt.Println(articles)
SetupJoinTable

添加和更新的时候得用这个

这样才能走自定义的连接表,以及走它的钩子函数

查询则不需要这个

(如果添加和更新不加,就我们这个情况的话时间就不会添加上去,因为他就不会走SetupJoinTable的那张表,而是默认的那张表,而那张表里面则没有时间,所以不会添加时间,但是不会添加失败)

12.5.3 自定义连接表主键

这个功能还是很有用的,例如你的文章表 可能叫ArticleModel,你的标签表可能叫TagModel

那么按照gorm默认的主键名,那就分别是ArticleModelID,TagModelID,太长了,根本就不实用

这个地方,官网给的例子看着也比较迷,不过我已经跑通了

主要是要修改这两项

joinForeignKey 连接的主键id

JoinReferences 关联的主键id

type ArticleModel struct {ID    uintTitle stringTags  []TagModel `gorm:"many2many:article_tags;joinForeignKey:ArticleID;JoinReferences:TagID"`
}type TagModel struct {ID       uintName     stringArticles []ArticleModel `gorm:"many2many:article_tags;joinForeignKey:TagID;JoinReferences:ArticleID"`
}type ArticleTagModel struct {ArticleID uint `gorm:"primaryKey"` // article_idTagID     uint `gorm:"primaryKey"` // tag_idCreatedAt time.Time
}
生成表结构
DB.SetupJoinTable(&ArticleModel{}, "Tags", &ArticleTagModel{})
DB.SetupJoinTable(&TagModel{}, "Articles", &ArticleTagModel{})
err := DB.AutoMigrate(&ArticleModel{}, &TagModel{}, &ArticleTagModel{})
fmt.Println(err)

添加,更新,查询操作和上面的都是一样

12.5.4 操作连接表(自定义连接表的时候)

如果通过一张表去操作连接表,这样会比较麻烦

比如查询某篇文章关联了哪些标签

或者是举个更通用的例子,用户和文章,某个用户在什么时候收藏了哪篇文章

无论是通过用户关联文章,还是文章关联用户都不太好查

最简单的就是直接查连接表

type UserModel struct {ID       uintName     stringCollects []ArticleModel `gorm:"many2many:user_collect_models;joinForeignKey:UserID;JoinReferences:ArticleID"`
}type ArticleModel struct {ID    uintTitle string// 这里也可以反向引用,根据文章查哪些用户收藏了
}// UserCollectModel 用户收藏文章表
type UserCollectModel struct {UserID    uint `gorm:"primaryKey"` // article_idArticleID uint `gorm:"primaryKey"` // tag_idCreatedAt time.Time
}func main() {DB.SetupJoinTable(&UserModel{}, "Collects", &UserCollectModel{})err := DB.AutoMigrate(&UserModel{}, &ArticleModel{}, &UserCollectModel{})fmt.Println(err)
}

常用的操作就是根据用户查收藏的文章列表

var user UserModel
DB.Preload("Collects").Take(&user, "name = ?", "枫枫")
fmt.Println(user)

但是这样不太好做分页,并且也拿不到收藏文章的时间

var collects []UserCollectModel
DB.Find(&collects, "user_id = ?", 2)
fmt.Println(collects)

这样虽然可以查到用户id,文章id,收藏的时间,但是搜索只能根据用户id搜,返回也拿不到用户名,文章标题等

我们需要改一下表结构,不需要重新迁移,加一些字段

type UserModel struct {ID       uintName     stringCollects []ArticleModel `gorm:"many2many:user_collect_models;joinForeignKey:UserID;JoinReferences:ArticleID"`
}type ArticleModel struct {ID    uintTitle string
}// UserCollectModel 用户收藏文章表
type UserCollectModel struct {UserID       uint         `gorm:"primaryKey"` // article_idUserModel    UserModel    `gorm:"foreignKey:UserID"`ArticleID    uint         `gorm:"primaryKey"` // tag_idArticleModel ArticleModel `gorm:"foreignKey:ArticleID"`CreatedAt    time.Time
}

查询

var collects []UserCollectModelvar user UserModel
DB.Take(&user, "name = ?", "枫枫")
// 这里用map的原因是如果没查到,那就会查0值,如果是struct,则会忽略零值,全部查询
DB.Debug().Preload("UserModel").Preload("ArticleModel").Where(map[string]any{"user_id": user.ID}).Find(&collects)for _, collect := range collects {fmt.Println(collect)
}

13. 自定义数据类型

很多情况下我们存储到数据库中的数据是多变的

例如我需要存储json或者是数组

然后很多数据库并不能直接存储这些数据类型,我们就需要自定义数据类型

自定义的数据类型必须实现 Scanner 和 Valuer 接口,以便让 GORM 知道如何将该类型接收、保存到数据库

gorm中自定义数据类型无外乎就两个方法

在数据入库的时候要转换为什么数据,已经出库的时候数据变成什么样子

13.1 存储json

存储json可能是经常使用到的

我们需要定义一个结构体,在入库的时候,把它转换为[]byte类型,查询的时候把它转换为结构体

type Info struct {Status string `json:"status"`Addr   string `json:"addr"`Age    int    `json:"age"`
}// Scan 从数据库中读取出来
func (i *Info) Scan(value interface{}) error {bytes, ok := value.([]byte)if !ok {return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))}err := json.Unmarshal(bytes, i)return err
}// Value 存入数据库
func (i Info) Value() (driver.Value, error) {return json.Marshal(i)
}type AuthModel struct {ID   uintName stringInfo Info `gorm:"type:string"`
}func main() {DB.AutoMigrate(&AuthModel{})
}

插入数据

DB.Debug().Create(&AuthModel{Name: "枫枫",Info: Info{Status: "success",Addr:   "湖南省长沙市",Age:    21,},
})// INSERT INTO `auth_models` (`name`,`info`) VALUES ('枫枫','{"status":"success","addr":"湖南省长沙市","age":21}')

查询数据

var auth AuthModel
DB.Take(&auth, "name = ?", "枫枫")
fmt.Println(auth)

13.2 存储数组

很多时候存储数组也是很常见的

最简单的方式就是存json

type Array []string// Scan 从数据库中读取出来
func (arr *Array) Scan(value interface{}) error {bytes, ok := value.([]byte)if !ok {return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))}err := json.Unmarshal(bytes, arr)return err
}// Value 存入数据库
func (arr Array) Value() (driver.Value, error) {return json.Marshal(arr)
}type HostModel struct {ID    uint   `json:"id"`IP    string `json:"ip"`Ports Array  `gorm:"type:string" json:"ports"`
}func main() {//DB.AutoMigrate(&HostModel{})//DB.Create(&HostModel{//  IP:    "192.168.200.21",//  Ports: []string{"80", "8080"},//})var host HostModelDB.Take(&host, 1)fmt.Println(host)
}

当然,也可以用字符串拼接,例如 |, =,  , 

type Array []string// Scan 从数据库中读取出来
func (arr *Array) Scan(value interface{}) error {data, ok := value.([]byte)if !ok {return errors.New(fmt.Sprintf("解析失败: %v %T", value, value))}*arr = strings.Split(string(data), "|")return nil
}// Value 存入数据库
func (arr Array) Value() (driver.Value, error) {return strings.Join(arr, "|"), nil
}

当然,拼接的字符串不能是输入字符串中存在的

13.3 枚举类型

枚举1.0

很多时候,我们会对一些状态进行判断,而这些状态都是有限的

例如,主机管理中,状态有 Running 运行中, OffLine 离线, Except 异常

如果存储字符串,不仅是浪费空间,每次判断还要多复制很多字符,最主要是后期维护麻烦

type Host struct {ID     uintName   stringStatus string
}func main() {host := Host{}if host.Status == "Running" {fmt.Println("在线")}if host.Status == "Except" {fmt.Println("异常")}if host.Status == "OffLine" {fmt.Println("离线")}
}

后来,我们知道了用常量存储这些不变的值

type Host struct {ID     uintName   stringStatus string
}const (Running = "Running"Except = "Except"OffLine = "OffLine"
) func main() {host := Host{}if host.Status == Running {fmt.Println("在线")}if host.Status == Except {fmt.Println("异常")}if host.Status == OffLine {fmt.Println("离线")}
}

虽然代码变多了,但是维护方便了

但是数据库中存储的依然是字符串,浪费空间这个问题并没有解决

枚举2.0

于是想到使用数字表示状态

type Host struct {ID     uintName   stringStatus int
}const (Running = 1Except  = 2OffLine = 3
)func main() {host := Host{}if host.Status == Running {fmt.Println("在线")}if host.Status == Except {fmt.Println("异常")}if host.Status == OffLine {fmt.Println("离线")}
}

但是,如果返回数据给前端,前端接收到的状态就是数字,不过问题不大,前端反正都要搞字符映射的

因为要做颜色差异显示

但是这并不是后端偷懒的理由

于是我们想到,在json序列化的时候,根据映射转换回去

type Host struct {ID     uint   `json:"id"`Name   string `json:"name"`Status int    `json:"status"`
}func (h Host) MarshalJSON() ([]byte, error) {var status stringswitch h.Status {case Running:status = "Running"case Except:status = "Except"case OffLine :status = "OffLine"}return json.Marshal(&struct {ID     uint   `json:"id"`Name   string `json:"name"`Status string `json:"status"`}{ID:     h.ID,Name:   h.Name,Status: status,})
}const (Running = 1Except  = 2OffLine  = 3
)func main() {host := Host{1, "枫枫", Running}data, _ := json.Marshal(host)fmt.Println(string(data)) // {"id":1,"name":"枫枫","status":"Running"}
}

这样写确实可以实现我们的需求,但是根本就不够通用,凡是用到枚举,都得给这个Struct实现MarshalJSON方法

枚举3.0(用这个)

于是类型别名出来了

type Status intfunc (status Status) MarshalJSON() ([]byte, error) {var str stringswitch status {case Running:str = "Running"case Except:str = "Except"case OffLine:str = "Status"}return json.Marshal(str)
}type Host struct {ID     uint   `json:"id"`Name   string `json:"name"`Status Status `json:"status"`
}const (Running Status = 1Except  Status = 2OffLine Status = 3
)func main() {host := Host{1, "枫枫", Running}data, _ := json.Marshal(host)fmt.Println(string(data)) // {"id":1,"name":"枫枫","status":"Running"}
}

嗯,代码简洁了不少,在使用层面已经没有问题了

在grom中使用

type Status intfunc (s Status) MarshalJSON() ([]byte, error) {return json.Marshal(s.String())
}func (s Status) String() string {var str stringswitch s {case Running:str = "Running"case Except:str = "Except"case OffLine:str = "Status"}return str
}const (Running Status = 1OffLine Status = 2Except  Status = 3
)type Host struct {ID     uint   `json:"id"`Status Status `gorm:"size:8" json:"status"`IP     string `json:"ip"`
}func main() {//DB.AutoMigrate(&Host{})//DB.Create(&Host{//  IP:     "192.168.200.12",//  Status: Running,//})var host HostDB.Take(&host)fmt.Println(host)fmt.Printf("%#v,%T\n", host.Status, host.Status)data, _ := json.Marshal(host)fmt.Println(string(data))}

14. gorm 事务

事务就是用户定义的一系列数据库操作,这些操作可以视为一个完成的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元。

很形象的一个例子,张三给李四转账100元,在程序里面,张三的余额就要-100,李四的余额就要+100
整个事件是一个整体,哪一步错了,整个事件都是失败的

gorm事务默认是开启的。为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。

如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。

一般不推荐禁用

// 全局禁用
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{SkipDefaultTransaction: true,
})

本节课表结构

type User struct {ID    uint   `json:"id"`Name  string `json:"name"`Money int    `json:"money"`
}// InnoDB引擎才支持事务,MyISAM不支持事务
// DB.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})

14.1 普通事务

以张三给李四转账为例,不使用事务的后果

var zhangsan, lisi User
DB.Take(&zhangsan, "name = ?", "张三")
DB.Take(&lisi, "name = ?", "李四")
// 张三给李四转账100元
// 先给张三-100
zhangsan.Money -= 100
DB.Model(&zhangsan).Update("money", zhangsan.Money)
// 模拟失败的情况// 再给李四+100
lisi.Money += 100
DB.Model(&lisi).Update("money", lisi.Money)

在失败的情况下,要么张三白白损失了100,要么李四凭空拿到100元

这显然是不合逻辑的,并且不合法的

那么,使用事务是怎样的

var zhangsan, lisi User
DB.Take(&zhangsan, "name = ?", "张三")
DB.Take(&lisi, "name = ?", "李四")
// 张三给李四转账100元
DB.Transaction(func(tx *gorm.DB) error {// 先给张三-100zhangsan.Money -= 100err := tx.Model(&zhangsan).Update("money", zhangsan.Money).Errorif err != nil {fmt.Println(err)return err}// 再给李四+100lisi.Money += 100err = tx.Model(&lisi).Update("money", lisi.Money).Errorif err != nil {fmt.Println(err)return err}// 提交事务return nil
})

使用事务之后,他们就是一体,一起成功,一起失败

14.2 手动事务

// 开始事务
tx := db.Begin()// 在事务中执行一些 db 操作(从这里开始,您应该使用 'tx' 而不是 'db')
tx.Create(...)// ...// 遇到错误时回滚事务
tx.Rollback()// 否则,提交事务
tx.Commit()

刚才的代码也可以这样实现

var zhangsan, lisi User
DB.Take(&zhangsan, "name = ?", "张三")
DB.Take(&lisi, "name = ?", "李四")// 张三给李四转账100元
tx := DB.Begin()// 先给张三-100
zhangsan.Money -= 100
err := tx.Model(&zhangsan).Update("money", zhangsan.Money).Error
if err != nil {tx.Rollback()
}// 再给李四+100
lisi.Money += 100
err = tx.Model(&lisi).Update("money", lisi.Money).Error
if err != nil {tx.Rollback()
}
// 提交事务
tx.Commit()

本篇文章根据 小破站 枫枫知道 所著,也是作者很喜欢的博主哈~

创作不易,希望读者三连支持 💖
赠人玫瑰,手有余香 💖

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库被rmallox勒索病毒加密,如何还原?

近年来,网络安全问题日益严峻,勒索病毒作为其中的一种恶意软件,已成为网络安全领域的一大难题。其中,rmallox勒索病毒以其高度的隐蔽性和破坏性,给不少企业和个人带来了严重损失。本文将从rmallox勒索病毒的特点、传播…

小程序视频怎么保存

新的小程序视频保存方法来了!不再需要依赖繁琐的Fiddler,也无需分析数据包。这款工具简单易用,帮助你轻松下载小程序视频,摆脱了繁琐的配置步骤。快来体验这个下载高手,让视频保存变得轻松简便! 下载高手我…

Github 2024-04-09 Python开源项目日报 Top10

根据Github Trendings的统计,今日(2024-04-09统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10Vue项目1JavaScript项目1系统设计指南 创建周期:2507 天开发语言:Python协议类型:OtherStar数量:241693 个Fork数量:42010 次…

漫途水产养殖水质智能监测方案,科技助力养殖业高效生产!

随着水产养殖业的蓬勃发展,水质和饲料等多重因素逐渐成为影响其持续健康发展的关键因素。由于传统养殖模式因监控和调节手段不足,往往造成养殖环境的恶化。需要通过智能化养殖,调控养殖环境,实现养殖的精细化管理模式,…

智能网联汽车自动驾驶数据记录系统DSSAD数据元素

目录 第一章 数据元素分级 第二章 数据元素分类 第三章 数据元素基本信息表 表1 车辆及自动驾驶数据记录系统基本信息 表2 车辆状态及动态信息 表3 自动驾驶系统运行信息 表4 行车环境信息 表5 驾驶员操作及状态信息 第一章 数据元素分级 自动驾驶数据记录系统记录的数…

thinkphp6入门(22)-- 如何下载文件

假设在public/uploads文件夹下有一个文件test.xlsx 在前端页面添加下载链接&#xff0c;用户点击该链接即可下载对应的文件。 <a href"xxxxxxx/downloadFile">下载文件</a> 2. 在后端控制器方法中&#xff0c;我们需要获取要下载的文件路径&#xff0…

【赛题】2024年“认证杯”数模网络挑战赛赛题发布

2024年"认证杯"数学建模网络挑战赛——正式开赛&#xff01;&#xff01;&#xff01; 赛题已发布&#xff0c;后续无偿分享各题的解题思路、参考文献、完整论文可运行代码&#xff0c;帮助大家最快时间&#xff0c;选择最适合是自己的赛题。祝大家都能取得一个好成…

实用工具系列-ADB使用方式

作者持续关注 WPS二次开发专题系列&#xff0c;持续为大家带来更多有价值的WPS开发技术细节&#xff0c;如果能够帮助到您&#xff0c;请帮忙来个一键三连&#xff0c;更多问题请联系我&#xff08;WPS二次开发QQ群:250325397&#xff09;&#xff0c;摸鱼吹牛嗨起来&#xff0…

day5 nest商业项目初探·一(java转ts全栈/3R教室)

背景&#xff1a;从头一点点学起太慢了&#xff0c;直接看几个商业项目吧&#xff0c;看看根据Java的经验&#xff0c;自己能看懂多少&#xff0c;然后再系统学的话也会更有针对性。先看3R教室公开的 kuromi 移民机构官方网站吧 【加拿大 | 1.5w】Nextjs&#xff1a;kuromi 移民…

[STM32+HAL]DengFOC移植之闭环位置控制

一、源码来源 DengFOC官方文档 二、HAL库配置 1、开启硬件IIC低速模式 低速更稳定 2、PWM波开启 三、keil填写代码 1、AS5600读取编码器数值 #include "AS5600.h" #include "math.h"float angle_prev0; int full_rotations0; // full rotation trac…

Linux下使用C语言实现线程池---代码及分析

线程池 相关文章 协议 Socket编程 高并发服务器实现 线程池 如果一个客户端建立连接使用创建一个线程用于处理这一个线程, 处理结束的时候把这一个线程删除, 这个时候会导致线程的创建以及销毁会消耗大量的时间 这时候可以一次性创建多个线程, 这几个线程统称线程池, 如果客户…

Mac下用adb命令安装apk到android设备笔记

查询了些资料记录备用。以下是在Mac上使用命令行安装APK文件的步骤&#xff1a; 1. 下载并安装ADB&#xff1a; 如果您的Mac上没有安装ADB&#xff0c;请从官方的Android开发者网站下载Android SDK Platform Tools&#xff1a;Android SDK Platform Tools。将下载的ZIP文件解…

Maven创建项目

目录 1.创建项目 2.从Maven Repository: Search/Browse/Explore (mvnrepository.com)链接&#xff0c;下载API 3.1.0 3.在main文件内创建webapp文件夹&#xff0c;再webapp文件夹内创建WEB-INF文件夹&#xff0c;在WEB-INF文件夹内创建web.xml 4.网络编程 5.打包 6.部署 …

前端服务请求跨域被拦截,Java后端Springboot服务解决办法

跨域问题 跨域前端遇到的问题&#xff1a; Access to XMLHttpRequest at ‘http://www.xxx.xxxx/api/x/d/xc’ from origin ‘http://127.0.0.1:3000’ has been blocked by cors policy: No ‘Access-Contorl-Allow-Origin’ header is present on the requested resource. …

雪亮工程视频联网综合管理/视频智能分析系统建设方案(二)

一、我国雪亮工程当前建设需求 1&#xff09;加强社会治安防控感知网络建设 加强社会治安防控智能感知网络建设&#xff0c;针对城中村、背街小巷、城乡结合部等重点区域建设安装视频监控设备&#xff0c;减少死角和盲区&#xff0c;与已有感知系统结合&#xff0c;形成高低搭…

Transformer模型-decoder解码器,target mask目标掩码的简明介绍

今天介绍transformer模型的decoder解码器&#xff0c;target mask目标掩码 背景 解码器层是对前面文章中提到的子层的包装器。它接受位置嵌入的目标序列&#xff0c;并将它们通过带掩码的多头注意力机制传递。使用掩码是为了防止解码器查看序列中的下一个标记。它迫使模型仅使用…

Unity 中画线

前言&#xff1a; 在Unity项目中&#xff0c;调试和可视化是开发过程中不可或缺的部分。其中&#xff0c;绘制线条是一种常见的手段&#xff0c;可以用于在Scene场景和Game视图中进行调试和展示。本篇博客将为你介绍多种不同的绘制线条方法&#xff0c;帮助你轻松应对各种调试…

新手尝试硬件买单片机还是树莓派?

新手尝试硬件买单片机还是树莓派&#xff1f; 新手的话&#xff0c;先学单片机吧&#xff0c;51&#xff0c;stm32&#xff0c;都可以&#xff0c;很多学习平台给的例子比较多&#xff0c;程序相对都比较简单&#xff0c;更贴近硬件&#xff0c;玩起来比较容易做出小东西&…

SI案例分享--实用的单端口Delta-L测试方法

目录 0 引言 1 单端口Delta-L技术 2 基于单端口Delta-L方法的反射灵敏度分析 3 用充分表征的材料系统验证该方法 4 在单端口法中提取总损耗 5 总结 0 引言 Intel Delta-L方法已被公认为一种常规方法&#xff0c;通过对测试线进行2端口测量来提取层压板材料的Dk和插入损耗…

机器学习——模型融合:Stacking算法

机器学习——模型融合&#xff1a;Stacking算法 在机器学习中&#xff0c;模型融合是一种常用的方法&#xff0c;它可以提高模型的泛化能力和预测性能。Stacking算法&#xff08;又称为堆叠泛化&#xff09;是一种强大的模型融合技术&#xff0c;它通过组合多个基本分类器的预…