【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用

这篇具有很好参考价值的文章主要介绍了【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

**本人是第六届字节跳动青训营(后端组)的成员。本文由博主本人整理自该营的日常学习实践,首发于稀土掘金。

我的go开发环境:

*本地IDE:GoLand 2023.1.2

*go:1.20.6

*MySQL:8.0

本文介绍Go框架三件套的使用。

Go 框架三件套通常指的是 GORM、Kitex 和 Hertz,它们分别是 Go 语言中数据库 ORM 库、分布式微服务框架和 Web 框架。

下面我们来逐个介绍各框架的使用。

GORM:数据库 ORM 库

🔗GORM 官方文档:https://gorm.cn/zh_CN/docs/connecting_to_the_database.html

1、GORM的简介

GORM 是 Go 语言中一个强大的 ORM 库(ORM 即对象关系映射,是一种程序设计技术,用于将不同类型的数据进行转换从而实现面向对象编程语言与数据库之间的交互),用于简化数据库操作。

它目前支持 MySQL、SQLServer、PostgreSQL、SQLite,提供了一系列便捷的 API 用于进行数据库的增删改查等操作,还支持模型定义、关联查询等高级功能。

GORM 是通过驱动的方式来连接数据库的, GORM 的基本使用步骤如下:

  • 安装 GORM:使用 go get 命令获取 GORM 包及数据库驱动。
  • 连接数据库:导入 GORM 包并创建数据库连接,例如连接 SQLite。
  • 定义模型:创建结构体来定义数据库表与字段的映射关系。
  • 自动迁移:使用 AutoMigrate 方法自动创建或更新数据库表结构。
  • 数据操作:使用 CreateFirstWhere 等方法进行增删改查操作。

本文以 MySQL 数据库为例进行演示。

2、GORM的基本使用(以MySQL为例)

我们先来看一下总体的GORM的使用:

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

*GORM的约定(默认情况)

  1. GORM使用名为ID的字段作为主键。
  2. (未给model定义表名时)使用结构体的蛇形复数作为表名。
  3. 字段名的蛇形作为列名。
  4. 使用 CreatedAt、UpdatedAt 字段作为创建更新时间。

蛇形命名:

在数据库中,蛇形命名(Snake Case)是一种命名约定,用于在标识符中使用下划线(_)分隔单词。蛇形命名的主要特点是所有单词都小写,并且使用下划线分隔,例如:user_infoorder_details。与蛇形命名相对的是驼峰命名(Camel Case)。

复数形式: 在 GORM 中默认情况下,如果结构体名称是单数形式(例如 User),那么 GORM 会将其转换为表名的复数形式(例如 users)。这个行为是 GORM 的默认命名约定之一,目的是在数据库中使用表的复数形式来存储多条记录。

这种默认的复数形式表名的转换规则是为了遵循一些数据库的命名习惯,同时也有助于避免表名与保留关键字冲突。

步骤 1:安装 GORM 和 MySQL 驱动

首先,打开Goland终端,使用 go get 命令安装 GORM 包和 MySQL 驱动:

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

步骤 2:连接数据库

安装好驱动后,可以在 Go 代码中导入 GORM 包和 MySQL 驱动并创建数据库连接:

package main

import (
        "gorm.io/driver/mysql"
        "gorm.io/gorm"
        "log"
)

func main() {
        dsn := "user:password@tcp(host:port)/database?charset=utf8mb4&parseTime=True&loc=Local"
        db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
        if err != nil {
                log.Fatal("无法连接数据库")
        }

        // 在这里可以使用 db 进行数据库操作
}

DSN中包含了数据库连接相关的信息。🔗MySQL的DSN说明文档

将上面的代码中DSN的 userpasswordhostportdatabase 分别替换为实际要连接的 MySQL 数据库的信息即可连接成功。

步骤 3:定义模型和操作数据库

在连接数据库之后,定义数据模型 model 并使用 GORM 进行数据库操作。

以下是一个简单的示例,演示了如何定义一个 User 模型,并进行插入、查询、更新和删除操作:

package main

import (
        "gorm.io/driver/mysql"
        "gorm.io/gorm"
        "log"
)

type User struct {
        ID   uint   `gorm:"primaryKey"`
        Name string
        Age  int
}

func main() {
        dsn := "user:password@tcp(host:port)/database?charset=utf8mb4&parseTime=True&loc=Local"
        db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
        if err != nil {
                log.Fatal("无法连接数据库")
        }

        db.AutoMigrate(&User{})

        // 插入数据
        newUser := User{Name: "Alice", Age: 25}
        db.Create(&newUser)

        // 查询数据
        var user User
        db.First(&user, 1)

        // 更新数据
        db.Model(&user).Update("Age", 26)

        // 删除数据
        db.Delete(&user)
}

db.AutoMigrate(&User{}) 是 GORM 提供的一个方法,用于自动创建或更新数据库表结构,以使其与你定义的模型保持一致。它在应用程序启动时非常有用,可以确保数据库表的结构与代码中定义的模型一致,而无需手动创建表或执行 SQL 脚本。

具体来说,AutoMigrate 方法会根据你定义的模型结构(通过结构体字段的标签)生成相应的数据库表,并且可以自动处理新增的字段、修改的字段类型、删除的字段等变化。这在开发过程中特别有用,因为你可以在模型结构中进行更改,然后通过自动迁移保持数据库表结构的更新。

在上述示例中,当应用程序启动时,db.AutoMigrate(&User{}) 会检查数据库中是否存在名为 users 的表,如果不存在则创建这张表,字段与 User 结构体中的定义保持一致。如果已存在表,GORM 会根据模型定义的变化自动更新表结构,例如新增、修改、删除字段。

更改DSN的信息后,在本地运行上述代码,观察结果:

// 插入数据
newUser := User{Name: "Alice", Age: 25}
db.Create(&newUser)

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

// 查询数据
var user User
db.First(&user, 1)

fmt.Printf("%+v\n", user)

//%+v 格式化占位符会打印出结构体的字段名和对应的值,以便更清晰地查看结构体的内容。

控制台打印查询结果:

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

注意:在实际使用中,请务必妥善保管数据库的敏感信息,如用户名、密码等,避免泄露。

//要先通过查询的操作将数据库中某一字段写入model,以建立起关联
//该代码查询出数据库中主id为6的记录
var user User
db.First(&user, 6)    
// 更新数据
db.Model(&user).Update("Age", 26)

在 GORM 中,如果想要更新数据库中的数据,首先需要通过查询语句获取到要更新的数据,并将获取到的结果赋值给相应的结构体变量,然后再使用 UpdateUpdates 方法来进行实际的更新操作。

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

// 删除数据
db.Delete(&user)

将指定数据删除:

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

总之,使用 GORM 连接 MySQL 数据库非常简单,只需要按照上述步骤导入相关包并配置数据库连接信息,就能够使用 GORM 提供的便捷 API 进行数据库操作。

3、GORM主要API详解

GORM中,各个API是链式调用的。Where()的工作只是拼接sql,而Create(),First(),Update(),Delet()等才是真正执行sql的。如果顺序颠倒,调用完后者,再去调用Where(),那么Where条件是不会生效的。

(1)GORM创建数据 Create()

Create()方法可以创建一条数据,也可以批量创建数据。

创建一条数据记录
newUser := User{Name: "Alice", Age: 25}    //创建结构体
result := db.Create(&newUser)

if result.Error != nil {
        log.Fatal("无法创建数据:", result.Error)
}
批量创建多条数据记录

在 GORM 中,要使用 Create 方法批量创建数据,需要将多个数据记录组成切片,然后使用 Create 方法进行批量插入。

users := []User{
        {Name: "Alice", Age: 25},
        {Name: "Bob", Age: 30},
        {Name: "Charlie", Age: 28},
}
result := db.Create(&users)

if result.Error != nil {
        log.Println("无法创建数据:", result.Error)
}

青训营培训中,李龙讲师给出的代码解析如下:

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

使用 clause.OnConflict 处理数据冲突

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

如何使用默认值?

通过使用 default 标签为字段定义默认值。

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

(2)GORM查询数据 First() Find()

查询一条数据

First() 方法用于查询数据库中的第一条符合条件的记录,并将结果存储在指定的结构体变量中。默认按照主键顺序进行查询,通常为创建记录时的顺序。如果需要按照其他字段排序,可以使用 Order 方法进行排序。

这个方法适用于需要查询一条记录的情况。

以下是 First() 方法的基本用法:

db.First(&user, 1)
  • db:是一个 GORM 数据库连接实例。
  • First:是 GORM 提供的查询方法。
  • &user:表示要将查询结果存储到名为 user 的结构体变量中。注意,这里使用了 & 操作符,表示传递了 user 变量的内存地址,以便在查询结果中存储数据。
  • 1:是查询的条件,这里表示按照主键为 1 进行查询。

First() 方法执行后,会从数据库中获取满足条件的第一条数据记录,并将结果存储在 user 变量中。如果没有找到符合条件的记录,user 变量将保持不变(即空的结构体值),会返回 ErrRecordNotFound

如果需要根据其他条件进行查询,可以使用 GORM 的查询条件构造方法(例如 WhereOr 等)来构建查询条件:

基本的条件查询:

// 查询 name 为 "Alice" 的第一条记录
db.Where("name = ?", "Alice").First(&user)

AND 和 OR 条件查询:

// 查询 age 大于等于 25 并且 name 不为 "Bob" 的记录
db.Where("age >= ? AND name <> ?", 25, "Bob").Find(&users)

// 查询 age 小于 30 或者 name 为 "Alice" 的记录
db.Where("age < ? OR name = ?", 30, "Alice").Find(&users)

IN 条件查询:

// 查询 age 在给定的列表 [25, 30] 中的记录
ages := []int{25, 30}
db.Where("age IN ?", ages).Find(&users)

LIKE 条件查询:

// 查询 name 包含 "li" 的记录
db.Where("name LIKE ?", "%li%").Find(&users)

其他查询条件:

GORM 还提供了许多其他的查询条件构造方法,如 NotOrBetweenIsNullNotNull 等,可以根据需要选择合适的条件方法来构建复杂的查询。

查询一组数据

在 GORM 中,Find() 方法用于执行查询并从数据库中检索满足指定条件的多条记录。它会将查询结果存储到指定的切片或数组中。Find() 方法适用于需要查询多条记录的情况,例如根据某个条件查找多个数据记录。

以下是 Find() 方法的基本用法:

db.Find(&users)
  • Find:是 GORM 提供的查询方法。
  • &users:表示要将查询结果存储到名为 users 的切片或数组中。注意,这里使用了 & 操作符,表示传递了 users 变量的内存地址,以便在查询结果中存储数据。

Find() 方法执行后,会从数据库中获取满足条件的多条数据记录,并将结果存储到 users 变量中。如果没有找到符合条件的记录,users 变量将保持为空切片(或空数组)。

需要注意的是,当使用 Find() 方法时,需要确保目标切片或数组的元素类型与数据库中的记录结构体类型相匹配。

培训中代码解析:

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

为什么要创建一个指向结构体的指针的切片

在 GORM 中,查询多组数据通常会使用切片来存储查询结果。而为什么要创建一个指向结构体的指针的切片,涉及到 Go 语言中切片和结构体的内存管理以及 GORM 的工作机制。

切片的引用语义: 在 Go 语言中,切片是引用类型。这意味着当你将切片传递给函数或方法时,实际上传递的是切片的引用,而不是它的拷贝。当切片被修改时,所有引用这个切片的地方都会受到影响。因此,使用切片可以在多个地方共享数据,而无需进行显式的复制。

指向结构体的指针: 在 GORM 中,查询结果需要映射到特定的结构体上。由于 GORM 需要修改结构体字段的值以反映数据库的实际数据,所以在查询结果存储时,必须传递结构体的指针。这样 GORM 才能直接修改结构体的字段。

因此,当使用 GORM 查询多组数据时,需要创建一个指向结构体的指针的切片,以便将查询结果存储在切片中。这样,切片中的每个元素都指向一个具体的结构体实例,而 GORM 可以直接修改这些实例的字段来填充查询结果。

在示例代码中,users := make([]*User, 0) 创建了一个初始为空的指向 User 结构体的指针的切片。然后,通过 db.Where(query:"age > 0").Find(&users) 将查询结果存储到这个切片中。这样就可以在切片中得到查询的多组数据,并且每个元素都是一个指向 User 结构体的指针,GORM 可以使用这些指针来填充查询结果。

First 的使用踩坑
  1. 使用 First 时,需要注意查询不到数据会返回 ErrRecordNotFound。
  2. 使用 Find 查询多条数据,查询不到数据不会返回错误。(更多的是使用Find,然后自己通过判断处理是否查询到数据。)
  3. 使用结构体作为查询条件。
  4. 当使用结构作为条件查询时,GORM只会查询非零值字段。这意味着如果您的字段值为 0、"、false 或其他零值该字段不会被用于构建查询条件,使用Map 来构建查询条件。

(3)GORM更新数据 Update() Updates()

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

注意:

  1. 使用 Struct 进行更新时,只会更新非零值,如果需要更新零值可以使用 Map 更新或使用Select 选择字段。
  2. map[string]interface{} 是 Go 语言中的一种数据结构,用于存储键值对,其中键是字符串类型,值是空接口类型。这种数据结构允许你在一个 map 中存储不同类型的值。

解释一下其中的各个部分:

  • map:是 Go 语言中的一种内置数据结构,用于存储键值对。每个键在 map 中必须是唯一的。
  • string:表示 map 的键的数据类型,这里是字符串类型。
  • interface{}:表示 map 的值的数据类型,这里是空接口类型。空接口可以存储任何类型的值,因为所有类型都满足空接口类型。

使用 map[string]interface{} 时,可以将任何类型的值与字符串键关联起来。这在一些动态的情况下非常有用,比如需要在一个 map 中存储不同类型的配置项或数据。

以下示例演示了如何使用 map[string]interface{} 存储不同类型的值:

package main

import "fmt"

func main() {
        // 创建一个 map,键是字符串,值是空接口类型
        data := make(map[string]interface{})

        // 存储不同类型的值
        data["name"] = "Alice"
        data["age"] = 25
        data["isStudent"] = true

        // 输出 map 中的值
        fmt.Println(data["name"])
        fmt.Println(data["age"])
        fmt.Println(data["isStudent"])
}

(4)GORM删除数据 Delete()

物理删除

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

软删除

以往我们实现软删的思路通常是设定一个flag,flag为1时没有删除,flag为0是删除。但GORM中已经给我们提供了一个比较完备的软删方案。

GORM 提供了 gorm.DeletedAt 用于帮助用户实现软删,拥有软删除能力的 Model 调用 Delete 时,记录不会被从数据库中真正删除。但 GORM 会将 DeletedAt 置为当前时间并且你不能再通过正常的查询方法找到该记录。

而使用 Unscoped 可以查询到被软删的数据。

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

4、GORM事务

Gorm 提供了 Begin、Commit、Rollback 方法用于使用事务。

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

在 GORM 中,使用 tx := db.Begin() 开启事务后,建议后续的数据库操作都使用 tx 来调用,而不是使用 db。这是因为事务对象 tx 是从数据库连接对象 db 衍生出来的,它继承了数据库连接的属性,并且使用事务对象 tx 可以确保数据库操作的一致性、原子性和性能,同时简化错误处理。在事务中进行操作可以保证这些操作在同一个数据库事务内执行,从而避免了许多潜在的并发问题。

  1. 事务的原子性: 在事务中进行的所有数据库操作要么全部成功提交,要么全部回滚。这确保了操作的原子性,避免了因为其中一个操作失败而导致数据库数据的不一致性。
  2. 性能优化: 在事务中进行操作会优化数据库连接的使用。事务通常会使用数据库连接池中的一个连接,而不是每个操作都创建新的连接。这可以降低资源消耗,提高性能。
  3. 数据一致性: 使用 tx 调用后续的数据库操作可以确保这些操作在同一个事务内执行。这意味着在事务中的操作都是基于同一个数据库快照,避免了因为并发操作而导致数据不一致的问题。
  4. 错误处理: 使用 tx 可以更方便地处理错误。如果在事务中的任何操作出现错误,可以直接调用 tx.Rollback() 来回滚整个事务。而使用 db 进行操作时则需要在出现错误时手动处理回滚。

5、GORM Hook

GORM 在 提供了 CURD 的 Hook 能力。Hook 是在创建、查询、更新、删除等操作之前、之后自动调用的函数。

如果任何 Hook 返回错误,GORM 将停止后续的操作并回滚事务。

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

6、GORM性能提高

  1. 对于写操作(创建、更新、删除),为了确保数据的完整性,GORM 会将它们封装在事务内运行但这会降低性能,可以使用 SkipDefaultTransaction 关闭默认事务。
  2. 使用 PrepareStmt 缓存预编译语句可以提高后续调用的速度,本机测试提高大约 35 %左右。

【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用,字节跳动青训营/Go语言,笔记,golang,开发语言

其他的性能优化方案见官方文档:🔗GORM性能提高

7、GORM生态

GORM 拥有非常丰富的扩展生态,以下列举一部分常用扩展:

GORM 代码生成工具:https://github.com/go-gorm/gen

GORM 分片库方案:https://github.com/go-gorm/sharding

GORM 手动索引:https://github.com/go-gorm/hints

GORM 乐观锁:https://github.com/go-gorm/optimisticlock

GORM 读写分离:https://github.com/go-gorm/dbresolver

GORM OpenTelemetry 扩展:https://github.com/go-gorm/opentelemetry

关于更多的 GORM 用法可以查看 Gorm 的文档(https://gorm.cn)。文章来源地址https://www.toymoban.com/news/detail-685723.html

到了这里,关于【字节跳动青训营】后端笔记整理-4 | Go框架三件套之GORM的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go语言上手(三) | 青训营笔记

    高质量: 各种边界条件考虑完备 异常情况处理,稳定性 易读易维护 编程原则 简单性 可读性 生产力 例外:实现接口的方法不需要注释 使用 gofmt (官方工具)自动格式化 代码作用(适合公共符号) 代码如何实现 (适合注释实现过程) 代码实现的原因(适合解释代码的外部

    2023年04月23日
    浏览(22)
  • 大一下暑期计划 + 2023字节青训营预告直播

    目录 🌼前言 🌹后端学习方法 🌳1,层次 🌳2,体系 🌳3,算法和数据结构 🌳4,总结 🌹前端学习方法 🌳基础 🌹求职中如何弥补学历差距? 🌹项目经历怎么准备? 🎂官网链接 + 简历如何写 🎂0基础可以跟项目吗 🎂主修Java或者C++能不能参加青训营? 🍍大一下暑期计划

    2024年02月11日
    浏览(33)
  • Go 语言的实战案例 | 青训营

    Powered by: NEFU AB-IN GO语言工程实践课后作业:实现思路、代码以及路径记录 在计算机编程领域,Go 语言(也称为 Golang)正逐渐成为越来越受欢迎的选择。它是一门由 Google 开发的开源编程语言,以其简洁性、高效性和强大的并发支持而闻名。Go 语言的设计目标是提供一种简单

    2024年02月11日
    浏览(34)
  • Go 语言进阶与依赖管理 | 青训营

    Powered by: NEFU AB-IN GO语言工程实践课后作业:实现思路、代码以及路径记录 Go可以充分发挥多核优势,高效运行 Goroutine 是Go语言中的 协程 ,一种 轻量级的线程 ,由Go语言的运行时管理,可以实现高并发的程序设计,由于轻量级的特性,goroutine可以创建成千上万个,而且消耗

    2024年02月11日
    浏览(30)
  • Go语言实践案例之猜谜游戏| 青训营

    目录 一、程序要实现效果: 二、思路分析: 三、具体代码 四、可能存在的疑问 1.程序首先生成一个0-100的随机整数。 2.提示玩家进行猜测。 3.每次玩家需要输入一个数字,程序将会告诉玩家输入的数字与生成的数字的大小关系,并且让玩家再次猜测。 4.如果猜对了,则会告

    2024年02月09日
    浏览(31)
  • 走进 Go 语言基础语法 | 青训营 (1)

    Powered by: NEFU AB-IN Go 语言入门指南:基础语法和常用特性解析 go.mod 这个文件里记录了当前项目里所有依赖包的 git 仓库地址以及对应的 版本号 ,来解决了包依赖管理的问题,后续在构建编译时,就会根据对应的版本号去拉取依赖包。 注意, 如果当前的项目是要给外部使用的

    2024年02月14日
    浏览(28)
  • HTTP 框架修炼之道 | 青训营

    Powered by: NEFU AB-IN 走进 HTTP 协议 HTTP 框架的设计与实现 性能修炼之道与企业实践 前后端通过http通信,负责对http请求解析,根据路由选择对应逻辑 超文本 通常包括文本、图像、音频、视频等多种媒体类型,这些内容通过链接与其他相关信息相互连接。最著名的超文本系统之

    2024年02月11日
    浏览(22)
  • Go 语言的实战案例 SOCKS5 代理 | 青训营

    Powered by: NEFU AB-IN GO语言工程实践课后作业:实现思路、代码以及路径记录 代理是指在计算机网络中,代理服务器充当客户端和目标服务器之间的中介。它接收来自客户端的请求,然后将请求转发给目标服务器,再将目标服务器的响应返回给客户端。 用途 : 匿名浏览 :Soc

    2024年02月10日
    浏览(30)
  • Go 语言入门指南: 环境搭建、基础语法和常用特性解析 | 青训营

    Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。 Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且

    2024年02月14日
    浏览(27)
  • Go 字节跳动—从需求到上线全流程

    整个课程会带大家先从理论出发,思考为什么有流程 大家以后工作的团队可能不一样,那么不同的团队也会有不同的流程,这背后的逻辑是什么 然后会带大家按照走一遍从需求到上线的全流程,告诉大家在流程的每个阶段,究竟要做什么 最后会给大家介绍一下我们实践当中

    2024年02月07日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包