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

《Go 简易速速上手小册》第9章:数据库交互(2024 最新版)

在这里插入图片描述

文章目录

  • 9.1 连接数据库 - Go 语言的海底宝藏之门
    • 9.1.1 基础知识讲解
      • 安装数据库驱动
      • 数据库连接
    • 9.1.2 重点案例:用户信息管理系统
      • 准备数据库
      • Go 代码实现
        • 连接数据库
        • 添加新用户
        • 查询用户信息
        • 用户登录验证
        • 主函数
    • 9.1.3 拓展案例 1:批量添加用户
      • 准备数据库
      • Go 代码实现
        • 实现批量添加用户功能
        • 主函数
    • 9.1.4 拓展案例 2:用户登录验证
      • 准备数据库
      • Go 代码实现
        • 生成和验证密码哈希
        • 实现用户登录验证
        • 主函数
  • 9.2 执行查询与操作数据 - Go 语言的数据潜水艇
    • 9.2.1 基础知识讲解
    • 9.2.2 重点案例:图书管理系统
      • 准备数据库
      • Go 代码实现
        • 连接数据库
        • 添加新图书
        • 查询图书列表
        • 更新图书信息
        • 删除图书记录
        • 主函数
    • 9.2.3 拓展案例 1:图书借阅记录
      • 准备数据库
      • Go 代码实现
        • 添加用户
        • 添加借阅记录
        • 查询借阅记录
        • 主函数
    • 9.2.4 拓展案例 2:图书搜索功能
      • 准备数据库
      • Go 代码实现
        • 实现搜索图书功能
        • 主函数
  • 9.3 使用ORM框架 - Go 语言的数据航海术
    • 9.3.1 基础知识讲解
      • GORM 介绍
      • 连接数据库
    • 9.3.2 重点案例:员工管理系统
      • 定义模型
      • 初始化数据库并自动迁移模型
      • 实现员工的增删改查操作
      • 主函数
    • 9.3.3 拓展案例 1:员工请假记录
      • 扩展数据库模型
      • 实现请假记录操作
        • 添加请假记录
        • 查询员工的请假记录
      • 主函数
    • 9.3.4 拓展案例 2:部门管理
      • 扩展数据库模型
      • 实现部门管理操作
        • 添加部门
        • 查询部门列表
        • 将员工分配到部门
      • 主函数

9.1 连接数据库 - Go 语言的海底宝藏之门

9.1.1 基础知识讲解

在Go语言的海洋中,连接数据库是获取深海宝藏的第一步。Go通过database/sql包提供了一个通用的接口来与SQL数据库进行交云,但实际上你还需要一个具体数据库的驱动来完成这个任务。

安装数据库驱动

首先,选择并安装你需要的数据库驱动。对于MySQL,你可能会选择github.com/go-sql-driver/mysql

go get -u github.com/go-sql-driver/mysql

对于PostgreSQL,则可能是github.com/lib/pq

go get -u github.com/lib/pq

数据库连接

连接数据库通常涉及创建一个sql.DB对象,它代表一个数据库的长连接。使用sql.Open函数并传入相应的驱动名和数据库的DSN(数据源名称)即可:

db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname")
if err != nil {log.Fatal(err)
}
defer db.Close()

确保在不再需要数据库连接时调用db.Close()来关闭连接。

9.1.2 重点案例:用户信息管理系统

在这个扩展案例中,我们将构建一个用户信息管理系统,该系统将演示如何在Go语言中连接MySQL数据库、添加新用户以及查询现有用户信息。此外,我们还将实现一个简单的用户登录验证功能。

准备数据库

首先,确保你的MySQL数据库服务正在运行,并执行以下SQL脚本来创建数据库和表:

CREATE DATABASE IF NOT EXISTS userdb;
USE userdb;
CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255) NOT NULL,email VARCHAR(255) NOT NULL,password VARCHAR(255) NOT NULL
);

Go 代码实现

在Go项目中,使用database/sql包和github.com/go-sql-driver/mysql驱动来实现与数据库的连接和操作。

连接数据库

首先,实现一个函数来创建数据库连接:

// db.gopackage mainimport ("database/sql"_ "github.com/go-sql-driver/mysql""log"
)func connectDB() *sql.DB {db, err := sql.Open("mysql", "user:password@/userdb?parseTime=true")if err != nil {log.Fatal(err)}return db
}
添加新用户

实现一个函数,用于添加新用户到数据库:

// user.gopackage mainimport ("log"
)func addUser(db *sql.DB, name, email, password string) {_, err := db.Exec("INSERT INTO users (name, email, password) VALUES (?, ?, ?)", name, email, password)if err != nil {log.Fatal(err)}log.Println("New user added successfully:", name)
}
查询用户信息

实现一个函数,用于根据邮箱查询用户信息:

func getUserByEmail(db *sql.DB, email string) {var name, userEmail stringerr := db.QueryRow("SELECT name, email FROM users WHERE email = ?", email).Scan(&name, &userEmail)if err != nil {log.Println("User not found:", err)return}log.Printf("User found: Name: %s, Email: %s\n", name, userEmail)
}
用户登录验证

实现一个简单的用户登录验证功能:

func verifyUserLogin(db *sql.DB, email, password string) {var dbPassword stringerr := db.QueryRow("SELECT password FROM users WHERE email = ?", email).Scan(&dbPassword)if err != nil {log.Println("Authentication failed:", err)return}if dbPassword == password {log.Println("User authenticated successfully")} else {log.Println("Invalid password")}
}
主函数

main函数中,调用上述函数演示添加新用户和查询用户信息的功能:

// main.gopackage mainfunc main() {db := connectDB()defer db.Close()addUser(db, "Jack Sparrow", "jack@sparrow.com", "pirate")getUserByEmail(db, "jack@sparrow.com")verifyUserLogin(db, "jack@sparrow.com", "pirate")
}

通过运行main.go文件,你可以看到添加新用户、查询用户信息和用户登录验证的过程。

通过这个扩展案例,你已经学会了如何在Go语言中连接MySQL数据库、执行基本的数据操作以及实现简单的用户登录验证功能。这为构建更复杂的Web应用和服务提供了坚实的基础。随着你对数据库操作的深入,你将能够更有效地管理和利用数据,为用户提供丰富和安全的服务。

9.1.3 拓展案例 1:批量添加用户

在这个案例中,我们将扩展之前的用户信息管理系统,实现一个功能以批量添加用户到数据库中。这项功能非常适合于需要一次性导入大量用户数据的场景,比如从CSV文件导入或者在系统初始化时预填充用户数据。为了保证数据的一致性和完整性,我们将使用事务来处理批量添加操作。

准备数据库

确保你已经按照之前的指示创建了userdb数据库和users表。

Go 代码实现

实现批量添加用户功能

我们将实现一个addUsers函数,接收一个用户信息列表,并使用事务批量添加用户到数据库中:

// user.gopackage mainimport ("database/sql""log"
)type User struct {Name     stringEmail    stringPassword string
}func addUsers(db *sql.DB, users []User) {tx, err := db.Begin()if err != nil {log.Fatal("Failed to begin transaction:", err)}stmt, err := tx.Prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)")if err != nil {log.Fatal("Failed to prepare statement:", err)}defer stmt.Close()for _, user := range users {_, err = stmt.Exec(user.Name, user.Email, user.Password)if err != nil {log.Fatal("Failed to execute statement:", err)}}err = tx.Commit()if err != nil {log.Fatal("Failed to commit transaction:", err)}log.Println("Users added successfully")
}

在这个函数中,我们首先开始一个新的事务。对于传入的每个用户,我们使用预编译的SQL语句和事务执行插入操作。最后,如果所有插入操作都成功执行,我们提交事务;如果在过程中遇到任何错误,事务将被回滚,保证数据库状态的一致性。

主函数

main函数中,调用addUsers函数演示批量添加用户的功能:

// main.gopackage mainfunc main() {db := connectDB()defer db.Close()users := []User{{"Will Turner", "will@turner.com", "Bootstrap"},{"Elizabeth Swann", "elizabeth@swann.com", "PirateKing"},{"Hector Barbossa", "hector@barbossa.com", "BlackPearl"},}addUsers(db, users)
}

通过运行main.go文件,你可以看到批量添加用户的过程。使用事务可以确保批量添加操作的原子性,即要么所有用户都成功添加,要么一个都不添加,避免了可能出现的数据不一致问题。

通过这个拓展案例,你已经学会了如何在Go语言中实现批量添加用户的功能,并了解了事务在保证数据库操作一致性中的重要作用。掌握这些技能后,你将能够更高效地管理和操作数据库中的数据。

9.1.4 拓展案例 2:用户登录验证

在这个案例中,我们将为用户信息管理系统添加用户登录验证功能。这个功能允许用户通过提供邮箱和密码来验证其身份。为了保证安全性,我们将存储密码的哈希值,而不是明文密码。

准备数据库

首先,确保你的users表已经准备好,并且有一个用于存储密码哈希值的字段:

ALTER TABLE users ADD COLUMN password_hash VARCHAR(255) NOT NULL;

Go 代码实现

为了处理密码,我们将使用golang.org/x/crypto/bcrypt包来生成和验证密码哈希。首先,安装bcrypt包:

go get -u golang.org/x/crypto/bcrypt
生成和验证密码哈希

我们将实现两个函数:一个用于生成密码的哈希值,另一个用于验证提供的密码是否与存储的哈希值匹配:

// auth.gopackage mainimport ("golang.org/x/crypto/bcrypt"
)// GeneratePasswordHash 生成密码的哈希值
func GeneratePasswordHash(password string) (string, error) {bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)return string(bytes), err
}// VerifyPassword 检查密码是否与其哈希值匹配
func VerifyPassword(password, hash string) bool {err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))return err == nil
}
实现用户登录验证

接下来,我们扩展用户信息管理系统,添加用户登录验证功能:

// user.gopackage mainimport ("database/sql""fmt""log"
)// VerifyUserLogin 验证用户登录
func VerifyUserLogin(db *sql.DB, email, password string) {var passwordHash stringerr := db.QueryRow("SELECT password_hash FROM users WHERE email = ?", email).Scan(&passwordHash)if err != nil {if err == sql.ErrNoRows {fmt.Println("用户不存在")} else {log.Fatal("查询错误:", err)}return}if VerifyPassword(password, passwordHash) {fmt.Println("登录成功")} else {fmt.Println("密码错误")}
}
主函数

main函数中,调用VerifyUserLogin函数演示用户登录验证的过程:

// main.gopackage mainfunc main() {db := connectDB()defer db.Close()// 假设用户已经被添加到数据库,并且密码哈希已经存储email := "jack@sparrow.com"password := "pirate"VerifyUserLogin(db, email, password)
}

通过运行main.go文件,你可以测试用户登录验证的功能。这个过程首先查询用户的密码哈希值,然后使用bcrypt库来验证提供的密码是否与哈希值匹配。

通过这个拓展案例,你已经学会了如何在Go语言中实现基本的用户登录验证功能,包括如何安全地处理和存储密码。这为构建需要用户认证的Web应用和服务提供了坚实的基础。随着你对安全性的深入理解,你将能够为你的应用实现更高级的安全特性。

9.2 执行查询与操作数据 - Go 语言的数据潜水艇

9.2.1 基础知识讲解

在Go的数据海洋中,执行查询和操作数据是寻找和管理宝藏的关键步骤。database/sql包提供了一套通用的接口,允许我们执行SQL查询、插入、更新和删除操作,以及处理结果集。

执行查询

查询数据库并处理结果集通常包括以下几个步骤:

  1. 使用QueryQueryRow执行SQL查询Query用于返回多行结果,而QueryRow用于期望最多一行结果的查询。

  2. 遍历Rows结果集(如果是多行结果)。使用Next方法迭代结果集,并使用Scan方法将行数据扫描到变量中。

  3. 处理Row结果(如果是单行结果)。直接使用Scan方法将结果扫描到变量中。

操作数据

插入、更新和删除操作通常使用Exec方法执行SQL命令。这个方法返回一个Result对象,它提供了关于操作影响的行数等信息。

9.2.2 重点案例:图书管理系统

在这个扩展案例中,我们将构建一个简单的图书管理系统,该系统将演示如何在Go语言中连接MySQL数据库、添加新图书、查询图书列表、更新图书信息以及删除图书记录。

准备数据库

首先,确保你的MySQL数据库服务正在运行,并执行以下SQL脚本来创建数据库和books表:

CREATE DATABASE IF NOT EXISTS library;
USE library;
CREATE TABLE IF NOT EXISTS books (id INT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(255) NOT NULL,author VARCHAR(255) NOT NULL,published_date DATE
);

Go 代码实现

连接数据库

首先,实现一个函数来创建数据库连接:

// db.gopackage mainimport ("database/sql"_ "github.com/go-sql-driver/mysql""log"
)func connectDB() *sql.DB {db, err := sql.Open("mysql", "user:password@/library")if err != nil {log.Fatal(err)}return db
}

确保替换user:password@/library中的userpassword为你的数据库用户名和密码。

添加新图书
// book.gopackage mainimport ("database/sql""fmt""log""time"
)func addBook(db *sql.DB, title, author string, publishedDate time.Time) {_, err := db.Exec("INSERT INTO books (title, author, published_date) VALUES (?, ?, ?)", title, author, publishedDate)if err != nil {log.Fatal("Failed to add book:", err)}fmt.Println("Successfully added new book:", title)
}
查询图书列表
func listBooks(db *sql.DB) {rows, err := db.Query("SELECT id, title, author, published_date FROM books")if err != nil {log.Fatal("Failed to list books:", err)}defer rows.Close()for rows.Next() {var id intvar title, author stringvar publishedDate time.Timeif err := rows.Scan(&id, &title, &author, &publishedDate); err != nil {log.Fatal("Failed to scan book:", err)}fmt.Printf("%d: %s by %s, published on %s\n", id, title, author, publishedDate.Format("2006-01-02"))}
}
更新图书信息
func updateBook(db *sql.DB, id int, title, author string) {_, err := db.Exec("UPDATE books SET title = ?, author = ? WHERE id = ?", title, author, id)if err != nil {log.Fatal("Failed to update book:", err)}fmt.Println("Successfully updated book with ID:", id)
}
删除图书记录
func deleteBook(db *sql.DB, id int) {_, err := db.Exec("DELETE FROM books WHERE id = ?", id)if err != nil {log.Fatal("Failed to delete book:", err)}fmt.Println("Successfully deleted book with ID:", id)
}
主函数

main.go中,整合上述功能,并运行演示:

// main.gopackage mainimport "time"func main() {db := connectDB()defer db.Close()// 添加图书示例addBook(db, "Go Programming Language", "Alan A. A. Donovan & Brian W. Kernighan", time.Date(2015, 11, 17, 0, 0, 0, 0, time.UTC))// 查询图书列表listBooks(db)// 更新图书信息updateBook(db, 1, "The Go Programming Language", "Alan A. A. Donovan & Brian W. Kernighan")// 删除图书记录deleteBook(db, 1)
}

通过运行main.go文件,你可以测试图书管理系统的各项功能。这个简单的应用展示了在Go中如何执行常见的数据库操作,包括连接数据库、执行SQL命令以及处理查询结果。

通过这个案例,你学会了如何使用Go与数据库进行交互,实现一个基本的图书管理系统。这为进一步开发更复杂的数据库驱动应用奠定了基础。随着对数据库操作的深入掌握,你将能够构建更加强大和灵活的数据管理和分析功能。

9.2.3 拓展案例 1:图书借阅记录

在这个案例中,我们将扩展图书管理系统,添加功能以记录用户的图书借阅信息。这项功能涉及到创建新的数据库表来存储借阅记录,并实现相关的增、查操作。

准备数据库

首先,除了已有的books表之外,我们还需要创建两个新的表:usersborrow_records

CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255) NOT NULL,email VARCHAR(255) UNIQUE NOT NULL
);CREATE TABLE IF NOT EXISTS borrow_records (id INT AUTO_INCREMENT PRIMARY KEY,user_id INT NOT NULL,book_id INT NOT NULL,borrow_date DATE NOT NULL,return_date DATE,FOREIGN KEY (user_id) REFERENCES users(id),FOREIGN KEY (book_id) REFERENCES books(id)
);

Go 代码实现

添加用户

首先,我们需要能够添加用户到users表中,因为借阅记录需要关联到具体的用户。

// user.gofunc addUser(db *sql.DB, name, email string) {_, err := db.Exec("INSERT INTO users (name, email) VALUES (?, ?)", name, email)if err != nil {log.Fatal("Failed to add user:", err)}fmt.Println("User added successfully:", name)
}
添加借阅记录

接下来,实现添加借阅记录的功能:

// borrow.gofunc addBorrowRecord(db *sql.DB, userID, bookID int, borrowDate time.Time) {_, err := db.Exec("INSERT INTO borrow_records (user_id, book_id, borrow_date) VALUES (?, ?, ?)", userID, bookID, borrowDate)if err != nil {log.Fatal("Failed to add borrow record:", err)}fmt.Println("Borrow record added successfully for user ID:", userID)
}
查询借阅记录

实现一个函数,用于查询特定用户的所有借阅记录:

func listBorrowRecords(db *sql.DB, userID int) {rows, err := db.Query("SELECT b.id, bk.title, b.borrow_date, b.return_date FROM borrow_records b JOIN books bk ON b.book_id = bk.id WHERE b.user_id = ?", userID)if err != nil {log.Fatal("Failed to list borrow records:", err)}defer rows.Close()for rows.Next() {var id intvar title stringvar borrowDate, returnDate sql.NullTimeif err := rows.Scan(&id, &title, &borrowDate, &returnDate); err != nil {log.Fatal("Failed to scan borrow record:", err)}fmt.Printf("Record %d: %s, Borrowed on %s, Returned on %v\n", id, title, borrowDate.Time.Format("2006-01-02"), returnDate.Time.Format("2006-01-02"))}
}
主函数

main.go中,整合上述功能,并运行演示:

// main.gopackage mainfunc main() {db := connectDB()defer db.Close()// 添加用户示例addUser(db, "Elizabeth Swann", "elizabeth@swann.com")// 添加图书示例addBook(db, "Pirates of the Caribbean", "Ted Elliott & Terry Rossio", time.Date(2003, 7, 9, 0, 0, 0, 0, time.UTC))// 添加借阅记录addBorrowRecord(db, 1, 1, time.Now())// 查询借阅记录listBorrowRecords(db, 1)
}

通过运行main.go文件,你可以测试添加用户、图书以及借阅记录的过程,并且能够查询特定用户的所有借阅记录。

通过这个拓展案例,你已经学会了如何在Go语言中实现与数据库相关的更复杂的操作,包括处理多表关联和实现具体的业务逻辑。随着你对数据库操作的掌握越来越深入,你将能够构建更加复杂和功能丰富的应用。

9.2.4 拓展案例 2:图书搜索功能

在这个案例中,我们将扩展图书管理系统,添加图书搜索功能,允许用户通过书名或作者名进行搜索。这项功能能够帮助用户快速找到感兴趣的图书,提高系统的用户体验。

准备数据库

假设我们已经有了一个books表,其中包含图书的标题(title)和作者(author)。

Go 代码实现

实现搜索图书功能

我们将实现一个searchBooks函数,接收一个搜索关键字,并在书名和作者名中查找匹配项。

// search.gopackage mainimport ("database/sql""fmt""log"
)func searchBooks(db *sql.DB, keyword string) {// 使用LIKE操作符进行模糊匹配,同时搜索书名和作者名query := fmt.Sprintf("%%s%", keyword) // 构建一个包含通配符的查询字符串rows, err := db.Query("SELECT id, title, author FROM books WHERE title LIKE ? OR author LIKE ?", query, query)if err != nil {log.Fatal("Failed to search books:", err)}defer rows.Close()fmt.Println("Search results:")for rows.Next() {var id intvar title, author stringif err := rows.Scan(&id, &title, &author); err != nil {log.Fatal("Failed to scan book:", err)}fmt.Printf("ID: %d, Title: %s, Author: %s\n", id, title, author)}// 检查是否有错误发生在迭代结果集中if err := rows.Err(); err != nil {log.Fatal(err)}
}

请注意,搜索时使用LIKE操作符和通配符%来实现模糊匹配,以便匹配包含关键字的所有图书。

主函数

main.go中,调用searchBooks函数演示搜索图书的功能:

// main.gopackage mainfunc main() {db := connectDB()defer db.Close()// 示例:搜索图书searchKeyword := "Caribbean"searchBooks(db, searchKeyword)
}

通过运行main.go文件,你可以测试图书搜索功能。输入一个关键字,程序将列出所有在书名或作者名中包含该关键字的图书。

通过这个拓展案例,你已经学会了如何在Go语言中为图书管理系统实现一个基本的搜索功能。这种功能在现实世界的应用中非常有用,尤其是在数据量大的情况下,能够帮助用户快速定位到他们感兴趣的信息。随着你对数据库操作和查询优化的进一步学习和实践,你将能够构建出更加强大和高效的搜索功能。

9.3 使用ORM框架 - Go 语言的数据航海术

9.3.1 基础知识讲解

在Go的数据探险旅程中,使用ORM(Object-Relational Mapping)框架可以让我们以更直观和对象化的方式与数据库进行交互,而无需编写繁琐的SQL语句。ORM框架提供了一种机制,将数据库表映射为Go中的结构体,数据库表中的行(记录)映射为结构体的实例,这样我们就可以使用Go代码来操作数据库了。

GORM 介绍

GORM是Go语言中最受欢迎的ORM库之一,它具有全功能的ORM功能,支持关联(包括一对一、一对多、多对多)、钩子(回调)、事务、迁移、SQL构建器、自动加载和预加载等特性。

要使用GORM,首先需要安装:

go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite // 对于SQLite
go get -u gorm.io/driver/mysql // 对于MySQL
go get -u gorm.io/driver/postgres // 对于PostgreSQL

连接数据库

使用GORM连接数据库非常简单,以下是一个连接SQLite数据库的示例:

import ("gorm.io/driver/sqlite""gorm.io/gorm"
)db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {panic("failed to connect database")
}

9.3.2 重点案例:员工管理系统

在这个扩展案例中,我们将构建一个简单的员工管理系统,使用GORM实现对员工数据的增删改查操作。该系统将演示如何在Go语言中使用ORM框架来简化数据库操作,提高开发效率。

定义模型

首先,我们定义Employee模型来映射数据库中的employees表:

// models.gopackage mainimport ("gorm.io/gorm""time"
)type Employee struct {ID        uint           `gorm:"primaryKey"`CreatedAt time.TimeUpdatedAt time.TimeDeletedAt gorm.DeletedAt `gorm:"index"`Name      stringEmail     string         `gorm:"uniqueIndex"`Position  string
}

初始化数据库并自动迁移模型

接下来,初始化数据库连接并自动迁移模型,确保数据库表结构与Go中的模型结构一致:

// db.gopackage mainimport ("gorm.io/driver/sqlite""gorm.io/gorm""log"
)func InitDB() *gorm.DB {db, err := gorm.Open(sqlite.Open("employees.db"), &gorm.Config{})if err != nil {log.Fatalf("Failed to connect to database: %v", err)}// 自动迁移模式db.AutoMigrate(&Employee{})return db
}

实现员工的增删改查操作

在员工管理系统中,我们需要实现以下功能:

  • 添加新员工
func AddEmployee(db *gorm.DB, employee *Employee) {result := db.Create(employee)if result.Error != nil {log.Fatalf("Failed to add employee: %v", result.Error)}log.Printf("Added new employee: %s", employee.Name)
}
  • 查询所有员工
func ListEmployees(db *gorm.DB) {var employees []Employeeresult := db.Find(&employees)if result.Error != nil {log.Fatalf("Failed to list employees: %v", result.Error)}for _, employee := range employees {log.Printf("ID: %d, Name: %s, Email: %s, Position: %s", employee.ID, employee.Name, employee.Email, employee.Position)}
}
  • 更新员工信息
func UpdateEmployee(db *gorm.DB, id uint, updateData map[string]interface{}) {result := db.Model(&Employee{}).Where("id = ?", id).Updates(updateData)if result.Error != nil {log.Fatalf("Failed to update employee: %v", result.Error)}log.Printf("Updated employee with ID: %d", id)
}
  • 删除员工
func DeleteEmployee(db *gorm.DB, id uint) {result := db.Delete(&Employee{}, id)if result.Error != nil {log.Fatalf("Failed to delete employee: %v", result.Error)}log.Printf("Deleted employee with ID: %d", id)
}

主函数

main.go中,我们整合上述功能,并运行演示:

// main.gopackage mainfunc main() {db := InitDB()// 添加新员工newEmployee := Employee{Name: "Jack Sparrow", Email: "jack@sparrow.com", Position: "Captain"}AddEmployee(db, &newEmployee)// 查询所有员工ListEmployees(db)// 更新员工信息UpdateEmployee(db, newEmployee.ID, map[string]interface{}{"Position": "Pirate Lord"})// 删除员工DeleteEmployee(db, newEmployee.ID)
}

通过运行main.go文件,你可以测试员工管理系统的各项功能。这个简单的应用展示了如何使用GORM与SQLite数据库进行交互,实现对员工数据的操作。

通过这个案例,你已经学会了如何在Go语言中使用GORM框架来简化数据库操作。随着对GORM和ORM概念的深入理解,你将能够更高效地开发出数据驱动的应用。

9.3.3 拓展案例 1:员工请假记录

在这个拓展案例中,我们将为员工管理系统添加员工请假记录的功能。这项功能涉及到新的数据库表leave_records的创建,并实现员工请假记录的增加和查询操作。

扩展数据库模型

首先,我们需要创建一个新的表leave_records来存储请假记录,并且这个表与employees表通过外键关联。

CREATE TABLE IF NOT EXISTS leave_records (id INT AUTO_INCREMENT PRIMARY KEY,employee_id INT NOT NULL,leave_date DATE NOT NULL,return_date DATE NOT NULL,reason TEXT,FOREIGN KEY (employee_id) REFERENCES employees(id)
);

接着,在Go中定义LeaveRecord模型以映射leave_records表:

// models.gotype LeaveRecord struct {gorm.ModelEmployeeID uintLeaveDate  time.TimeReturnDate time.TimeReason     string
}

确保在初始化数据库时自动迁移新模型:

db.AutoMigrate(&Employee{}, &LeaveRecord{})

实现请假记录操作

添加请假记录

我们实现一个函数来添加新的请假记录:

func AddLeaveRecord(db *gorm.DB, record *LeaveRecord) {if err := db.Create(record).Error; err != nil {log.Fatalf("Failed to add leave record: %v", err)} else {fmt.Println("Leave record added successfully.")}
}
查询员工的请假记录

实现一个函数来查询特定员工的所有请假记录:

func ListLeaveRecords(db *gorm.DB, employeeID uint) {var records []LeaveRecordif err := db.Where("employee_id = ?", employeeID).Find(&records).Error; err != nil {log.Fatalf("Failed to list leave records: %v", err)} else {for _, record := range records {fmt.Printf("Leave from %s to %s, Reason: %s\n", record.LeaveDate.Format("2006-01-02"), record.ReturnDate.Format("2006-01-02"), record.Reason)}}
}

主函数

main.go中,调用上述函数演示添加和查询请假记录的功能:

// main.gopackage mainfunc main() {db := InitDB()// 假设已存在员工Jack Sparrow,其ID为1employeeID := uint(1)// 添加请假记录record := LeaveRecord{EmployeeID: employeeID,LeaveDate:  time.Date(2023, 1, 10, 0, 0, 0, 0, time.UTC),ReturnDate: time.Date(2023, 1, 20, 0, 0, 0, 0, time.UTC),Reason:     "Sailing the seven seas",}AddLeaveRecord(db, &record)// 查询员工的请假记录ListLeaveRecords(db, employeeID)
}

通过运行main.go文件,你可以测试添加和查询请假记录的功能。这个拓展案例展示了如何使用GORM处理更复杂的数据模型和关联关系,为员工管理系统添加新的功能。

通过这个案例,你进一步理解了在Go语言中使用ORM框架进行数据库操作的便利性,以及如何为应用添加实际业务逻辑。随着你对GORM和数据库操作的深入掌握,你将能够构建更加复杂和功能丰富的应用。

9.3.4 拓展案例 2:部门管理

在这个案例中,我们将为员工管理系统添加部门管理功能,允许创建部门、查询部门列表、将员工分配到部门等。这涉及到处理多对多的关联关系,并展示如何使用GORM进行复杂的查询和更新操作。

扩展数据库模型

首先,我们需要定义Department模型并创建一个新表departments来存储部门信息。同时,因为一个员工可以属于多个部门,一个部门也可以有多个员工,我们还需要一个关联表employee_departments来实现多对多的关系。

CREATE TABLE IF NOT EXISTS departments (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255) NOT NULL,description TEXT
);CREATE TABLE IF NOT EXISTS employee_departments (employee_id INT,department_id INT,FOREIGN KEY (employee_id) REFERENCES employees(id),FOREIGN KEY (department_id) REFERENCES departments(id),PRIMARY KEY (employee_id, department_id)
);

接着,在Go中定义Department模型并更新Employee模型以映射新的关系:

// models.gotype Department struct {gorm.ModelName        stringDescription stringEmployees   []Employee `gorm:"many2many:employee_departments;"`
}type Employee struct {gorm.ModelName       stringEmail      string `gorm:"uniqueIndex"`Position   stringDepartments []Department `gorm:"many2many:employee_departments;"`
}

确保在初始化数据库时自动迁移新模型:

db.AutoMigrate(&Employee{}, &Department{})

实现部门管理操作

添加部门
func AddDepartment(db *gorm.DB, department *Department) {if err := db.Create(department).Error; err != nil {log.Fatalf("Failed to add department: %v", err)} else {fmt.Println("Department added successfully:", department.Name)}
}
查询部门列表
func ListDepartments(db *gorm.DB) {var departments []Departmentif err := db.Find(&departments).Error; err != nil {log.Fatalf("Failed to list departments: %v", err)} else {for _, department := range departments {fmt.Printf("ID: %d, Name: %s, Description: %s\n", department.ID, department.Name, department.Description)}}
}
将员工分配到部门
func AssignEmployeeToDepartment(db *gorm.DB, employeeID, departmentID uint) {var employee Employeevar department Departmentif err := db.First(&employee, employeeID).Error; err != nil {log.Fatalf("Employee not found: %v", err)}if err := db.First(&department, departmentID).Error; err != nil {log.Fatalf("Department not found: %v", err)}db.Model(&employee).Association("Departments").Append(&department)fmt.Printf("Employee %s assigned to department %s\n", employee.Name, department.Name)
}

主函数

main.go中,整合上述功能,并运行演示:

// main.gopackage mainfunc main() {db := InitDB()// 添加部门dept := Department{Name: "IT", Description: "Information Technology"}AddDepartment(db, &dept)// 查询部门列表ListDepartments(db)// 将员工分配到部门AssignEmployeeToDepartment(db, 1, 1) // 假设员工ID和部门ID都为1
}

通过运行main.go文件,你可以测试部门管理的各项功能。这个拓展案例展示了如何使用GORM处理多对多的关系,并在应用中实现复杂的业务逻辑。

通过这个案例,你已经学会了如何在Go语言中使用GORM框架来管理多对多的关系,并实现了一个部门管理功能。随着你对GORM和数据库操作的深入掌握,你将能够构建更加复杂和功能丰富的应用。

相关文章:

《Go 简易速速上手小册》第9章:数据库交互(2024 最新版)

文章目录 9.1 连接数据库 - Go 语言的海底宝藏之门9.1.1 基础知识讲解安装数据库驱动数据库连接 9.1.2 重点案例:用户信息管理系统准备数据库Go 代码实现连接数据库添加新用户查询用户信息用户登录验证主函数 9.1.3 拓展案例 1:批量添加用户准备数据库Go…...

redis的hash数据结构底层简记

hash:k和v都是string的hash表。 HSET(设置集合数据,4.0之前只能设置1个,之后可以设置多个),HSETNX(若k不存在则设置对应v),HDEL(删除指定kv,可以一次删除多个&#xff09…...

清除Django的管理员admin站点中“Recent Actions“最近活动面板上的所有信息

清除Django的管理员admin站点中"Recent Actions"最近活动面板上的所有信息 本文主要介绍了如何清除Django的管理员admin站点中"Recent Actions"最近活动面板上的所有信息 操作步骤如下 进入Django项目目录中运行代python manage.py shell进入Django shell…...

【JVM篇】ThreadLocal中为什么要使用弱引用

文章目录 🍔ThreadLocal中为什么要使用弱引用⭐总结 🍔ThreadLocal中为什么要使用弱引用 ThreadLocal可以在线程中存放线程的本地变量,保证数据的线程安全 ThreadLocal是这样子保存对象的: 在每个线程中,存放了一个…...

Stable Diffusion教程——stable diffusion基础原理详解与安装秋叶整合包进行出图测试

前言 在2022年,人工智能创作内容(AIGC)成为了AI领域的热门话题之一。在ChatGPT问世之前,AI绘画以其独特的创意和便捷的创作工具迅速走红,引起了广泛关注。随着一系列以Stable Diffusion、Midjourney、NovelAI等为代表…...

【JavaEE】_线程与多线程的创建

目录 1. 线程的概念 2. 创建与使用多线程 2.1 方式1:继承Thread类 2.2 方式2: 实现Runnable接口 2.3 以上两种创建线程方式的对比 3. 多线程的优势-增加运行速度 1. 线程的概念 进程的存在是由于系统的多任务执行需求,这也要求程序员进…...

【前端工程化面试题】如何优化提高 webpack 的构建速度

使用最新版本的 Webpack 和相关插件: 每个新版本的 Webpack 都会带来性能方面的改进和优化,因此始终确保你在使用最新版本。同时,更新你的相关插件也是同样重要的。 使用DllPlugin动态链接库: 使用DllPlugin和DllReferencePlugin来将第三方库的代码进行…...

免费chatgpt使用

基本功能如下: https://go.aigcplus.cc/auth/register?inviteCode3HCULH2UD...

OpenCV识别人脸案例实战

使用级联函数 基本流程 函数介绍 在OpenCV中,人脸检测使用的是cv2.CascadeClassifier.detectMultiScale()函数,它可以检测出图片中所有的人脸。该函数由分类器对象调用,其语法格式为: objects cv2.CascadeClassifier.detectMul…...

VOSK——离线语音库

文章目录 识别函数调用添加自定义热词表1. SetWords2. SetLatticeWords3. SetPartialWords使用示例注意1. SetMaxAlternatives2. SetNLSML3. SetSpkModel4. SetGrammar使用示例注意SetLogLevel示例用法注意事项 识别函数调用 在使用Vosk库进行语音识别时,PartialRe…...

ELAdmin 隐藏添加编辑按钮

使用场景 做了一个监控模块,数据都是定时生成的,所以不需要手动添加和编辑功能。 顶部不显示 可以使用 true 或者 false 控制现实隐藏 created() {this.crud.optShow {add: false,edit: false,del: true,download: true,reset: true}},如果没有 crea…...

浅谈Websocket

由于 http 存在⼀个明显的弊端(消息只能有客户端推送到服务器端,⽽服务器端不能主动推送到客户端),导致如果服务器如果有连续的变化,这时只能使⽤轮询,⽽轮询效率过低,并不适合。于是 WebSocket 被发明出来 WebSocket 是⼀种在 Web 应⽤程序中实现双向通信的协议。与传…...

JavaScript闭包详细介绍

文章目录 什么是闭包优点:变量持久化:封装私有变量:模块化:函数工厂: 缺点:内存占用:调试困难:过度使用导致性能下降: 什么是闭包 闭包是指有权访问另一个函数作用域中的…...

pytorch神经网络入门代码

import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms# 定义神经网络结构 class SimpleNN(nn.Module):def __init__(self, input_size, hidden_size, num_classes):super(SimpleNN, self).__init_…...

代码随想录算法训练营第三十四天|860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球

860.柠檬水找零 链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 细节: 1. 首先根据题意就是只有5.的成本,然后就开始找钱,找钱也是10.和5. 2. 直接根据10 和 5 进行变量定义,然后去循环…...

Ditto:提升剪贴板体验的宝藏软件(复制粘贴效率翻倍、文本处理好助手)

名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、什么是Ditto?二、下载安装三、如…...

【自然语言处理-工具篇】spaCy<2>--模型的使用

前言 之前已经介绍了spaCy的安装,接下来我们要通过下载和加载模型去开始使用spaCy。 下载模型 经过训练的 spaCy 管道可以作为 Python 包安装。这意味着它们是应用程序的一个组件,就像任何其他模块一样。可以使用 spaCy download的命令安装模型,也可以通过将 pip 指向路径或…...

Java之通过Jsch库连接Linux实现文件传输

Java之通过JSch库连接Linux实现文件传输 文章目录 Java之通过JSch库连接Linux实现文件传输1. JSch2. Java通过Jsch连接Linux1. poxm.xml2. 工具类3. 调用案例 1. JSch 官网:JSch - Java Secure Channel (jcraft.com) JSch是SSH2的纯Java实现。 JSch 允许您连接到 ss…...

Nginx七层负载均衡之动静分离

思路: servera:负载均衡服务器 serverb:静态服务器 serverc:动态服务器 serverd:默认服务器 servera(192.168.233.132): # 安装 Nginx 服务器 yum install nginx -y#关闭防火墙和selinux systemctl stop firewalld setenforce 0# 切换到 Nginx 配置文…...

305_C++_定义了一个定时器池 TimerPool 类和相关的枚举类型和结构体

头文件:定义了一个定时器池 TimerPool 类和相关的枚举类型和结构体 #ifndef TIMERPOOL_H #define TIMERPOOL_H #include "rsglobal.h" #include "taskqueue.h" #incl...

大整数因数分解工具——yafu

一、安装 yafu--下载链接 二、配置环境变量,直接从cmd打开 1.找到yafu-x64.exe 所在的文件路径 2.点击设置——系统——系统信息——高级系统设置——环境变量——点击PATH(上下都可以)——新建 添加yafu-x64.exe 所在路径——点击确定 3…...

非关系型数据库(NOSQL)和关系型数据库(SQL)区别详解

前言: 在我们的日常开发中,关系型数据库和非关系型数据库的使用已经是一个成熟的软件产品开发过程中必不可却的存储数据的工具了。那么用了这么久的关系数据库和非关系型数据库你们都知道他们之间的区别了吗?下面我们来详细的介绍一下。 关系…...

7.Cloud-GateWay

0.概述 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/ 1.入门配置 1.1 POM <!--新增gateway--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-sta…...

【Linux】Framebuffer 应用

# 前置知识 LCD 操作原理 在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。 Frame 是帧的意思&#xff0c; buffer 是缓冲的意思&#xff0c;这意味着 Framebuffer 就是一块内存&#xff0c;里面保存着一帧图像。 Framebuffer 中保存着一帧图像的每一个像素颜色值&…...

markdown绘制流程图相关代码片段记录

有时候会使用typora来绘制一些流程图&#xff0c;进行编码之类的工作&#xff0c;在网络搜集了一些笔记&#xff0c;做个记录&#xff0c;方便日后进行复习&#xff0c;相关的记录如下&#xff1a; 每次作图时&#xff0c;代码以「graph <布局方向>」开头&#xff0c;如…...

云计算基础-计算虚拟化-CPU虚拟化

CPU指令系统 在CPU的工作原理中&#xff0c;CPU有不同的指令集&#xff0c;如下图&#xff0c;CPU有4各指令集&#xff1a;Ring0-3&#xff0c;指令集是在服务器上运行的所有命令&#xff0c;最终都会在CPU上执行&#xff0c;但是CPU并不是说所有的命令都是一视同仁的&#xf…...

MySQL数据库⑪_C/C++连接MySQL_发送请求

目录 1. 下载库文件 2. 使用库 3. 链接MySQL函数 4. C/C链接示例 5. 发送SQL请求 6. 获取查询结果 本篇完。 1. 下载库文件 要使用C/C连接MySQL&#xff0c;需要使用MySQL官网提供的库。 进入MySQL官网选择适合自己平台的mysql connect库&#xff0c;然后点击下载就行…...

选择排序和快速排序(1)

目录 选择排序 基本思想 选择排序的实现 图片实现 代码实现 快速排序 基本思想 快速排序的实现 图片实现 代码实现 选择排序 基本思想 每一次从待排序的数据元素中选出最小&#xff08;最大&#xff09;的元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部…...

得物面试:Redis用哈希槽,而不是一致性哈希,为什么?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; Redis为何用哈希槽而不用一致性哈希&#xff1f; 最近…...

matlab发送串口数据,并进行串口数据头的添加,我们来看下pwm解析后并通过串口输出的效果

uintt16位的话会在上面前面加上00&#xff0c;16位的话一定是两个字节&#xff0c;一共16位的数据 如果是unint8的话就不会&#xff0c; 注意这里给的是13&#xff0c;但是现实的00 0D&#xff0c;这是大小端的问题&#xff0c;在matlanb里设置&#xff0c;我们就默认用这个模式…...

二分、快排、堆排与双指针

二分 int Binary_Search(vector<int> A,int key){int nA.size();int low0,highn-1,mid;while(low<high){mid(lowhigh)/2;if(A[mid]key)return mid;else if(A[mid]>key)highmid-1;elselowmid1; }return -1; }折半插入排序 ——找到第一个 ≥ \ge ≥tem的元素 voi…...

微信小程序步数返还的时间戳为什么返回的全是1970?

微信小程序步数返还的时间戳为什么返回的全是1970&#xff1f; 将返回的时间 乘以 1000 再 new Date() 转化就对了 微信返回的是秒S单位的&#xff0c;我们要转化为毫秒ms单位&#xff0c;才能进行格式化日期。 微信给我们下了个坑&#xff0c; 参考&#xff1a; https://d…...

Python函数——函数介绍

一、引言 在Python编程中&#xff0c;函数是构建高效代码的关键。通过创建可重用的代码块&#xff0c;我们可以使程序更加清晰、易读且易于维护。在本文中&#xff0c;我们将深入了解Python函数的基本概念及其特性。 二、Python函数的基本概念 函数是一段具有特定功能的代码块…...

【Linux系统化学习】文件重定向

目录 文件内核对象 文件描述符的分配规则 重定向 重定向的概念 dup2系统调用 输出重定向 追加重定向 输入重定向 stderr解析 重定向到同一个文件中 分离常规输出和错输出 文件内核对象 上篇文章中我们介绍到了操作系统中的文件&#xff0c;操作系统为了方…...

防火墙工作模式详解

防火墙工作模式是指防火墙在网络中的工作方式和策略。常见的防火墙工作模式包括以下几种&#xff1a; 1. 包过滤工作模式&#xff1a;根据事先确定的规则集合&#xff0c;对进出网络的网络包进行过滤和检查。根据规则&#xff0c;防火墙可以允许或阻止特定的网络流量。 2. 代…...

CCF编程能力等级认证GESP—C++6级—20231209

CCF编程能力等级认证GESP—C6级—20231209 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)闯关游戏工作沟通 答案及解析单选题判断题编程题1编程题2 单选题…...

ES6 ~ ES11 学习笔记

课程地址 ES6 let let 不能重复声明变量&#xff08;var 可以&#xff09; let a; let b, c, d; let e 100; let f 521, g "atguigu", h [];let 具有块级作用域&#xff0c;内层变量外层无法访问 let 不存在变量提升&#xff08;运行前收集变量和函数&#…...

001 - Hugo, 创建一个网站

001 - Hugo, 创建一个网站安装hugoWindows系统Macos Hugo博客搭建初始化博客主题安装配置博客各个页面开始创作创建 GitHub Page 仓库本地调试和预览发布内容 教程及鸣谢文字教程视频教程 001 - Hugo, 创建一个网站 这篇文章假设你已经&#xff1a; 了解基本的终端命令行知识&…...

前端开发:Vue框架与前端部署

Vue Vue是一套前端框架&#xff0c;免除原生)avaScript中的DOM操作&#xff0c;简化书写。是基于MVVM(Model–View-ViewModel)思想&#xff0c;实现数据的双向绑定&#xff0c;将编程的关注点放在数据上。简单来说&#xff0c;就是数据变化的时候, 页面会自动刷新, 页面变化的时…...

【leetcode】深搜、暴搜、回溯、剪枝(C++)3

深搜、暴搜、回溯、剪枝&#xff08;C&#xff09;3 一、解数独1、题目描述2、代码3、解析 二、单词搜索1、题目描述2、代码3、解析 三、黄金矿工1、题目描述2、代码3、解析 四、不同路径III1、题目描述2、代码3、解析 一、解数独 1、题目描述 leetcode链接 2、代码 class…...

社区养老|社区养老服务系统|基于springboot社区养老服务系统设计与实现(源码+数据库+文档)

社区养老服务系统目录 目录 基于springboot社区养老服务系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员部分功能 &#xff08;1&#xff09; 用户管理 &#xff08;2&#xff09;服务种类管理 &#xff08;3&#xff09;社区服务管理 &#xff08…...

云计算基础-存储虚拟化(深信服aSAN分布式存储)

什么是存储虚拟化 分布式存储是利用虚拟化技术 “池化”集群存储卷内通用X86服务器中的本地硬盘&#xff0c;实现服务器存储资源的统一整合、管理及调度&#xff0c;最终向上层提供NFS、ISCSI存储接口&#xff0c;供虚拟机根据自身的存储需求自由分配使用资源池中的存储空间。…...

数学实验第三版(主编:李继成 赵小艳)课后练习答案(十二)(3)

实验十二&#xff1a;微分方程模型 练习三 1.分别用数值解命令ode23t和ode45 计算示例3中微分方程的数值解,同用命令ode23 算得的数值解以及解析解比较,哪种方法精度较高?你用什么方法比较它们之间的精度? clc;clear; f(x,y)2*yx2; figure(1) [x,y]ode23t(f,[1,2],1); plo…...

CSS Transition:为网页元素增添优雅过渡效果

随着互联网的发展&#xff0c;网页的视觉效果和用户体验变得尤为重要。CSS Transition作为一种能够让网页元素在状态改变时呈现平滑过渡效果的工具&#xff0c;受到了广大前端开发者的青睐。本文将详细介绍CSS Transition的基本概念、使用方法以及常见应用&#xff0c;帮助读者…...

JDK 17 新特性 (一)

既然 Springboot 3.0 强制使用 JDK 17 那就看看 JDK17 有哪些新特性吧 参考链接 介绍一下 新特性的历史渊源 JDK 17是Java Development Kit&#xff08;JDK&#xff09;的一个版本&#xff0c;它是Java编程语言的一种实现。JDK 17于2021年9月14日发布&#xff0c;并作为Java …...

杨中科 ASP.NET DI综合案例

综合案例1 需求说明 1、目的:演示DI的能力; 2、有配置服务、日志服务&#xff0c;然后再开发一个邮件发送器服务。可以通过配置服务来从文件、环境变量、数据库等地方读取配置&#xff0c;可以通过日志服务来将程序运行过程中的日志信息写入文件、控制台、数据库等。 3、说明…...

蓝桥杯嵌入式第12届真题(完成) STM32G431

蓝桥杯嵌入式第12届真题(完成) STM32G431 题目 程序 main.c /* USER CODE BEGIN Header */ /********************************************************************************* file : main.c* brief : Main program body**************************…...

C#系列-多线程(4)

在C#中&#xff0c;多线程编程主要涉及使用System.Threading命名空间下的类和接口来创建和管理线程。以下是一些C#多线程编程的基本用法和示例&#xff1a; 1. 使用Thread类创建线程 csharp代码 using System; using System.Threading; class Program { static void …...

VS如何调试C运行时库

C运行时库(简称crt)是C标准库等组件的基础, 其会在进入main函数之前运行一些代码, 包括但不限于初始化堆栈, 内存分配等操作     这些代码是可以随着VC工具集一起安装到我们本地的。看一下这个情况, 就是VS调试器没找到对应的crt源码的情况, 调用堆栈是空的。为了解决这个问…...

软件工程师,超过35岁怎么办

概述 随着科技行业的飞速发展&#xff0c;软件开发工程师的职业道路充满了各种机遇和挑战。对于已经在这个行业摸爬滚打了十多年的软件开发工程师来说&#xff0c;当他们步入35岁这个年纪时&#xff0c;可能会感到一些迷茫和焦虑。许多人担忧&#xff0c;在以创新、活力、快速迭…...