《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.go

package main

import (
    "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.go

package main

import (
    "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 string
    err := 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 string
    err := 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.go

package main

func 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.go

package main

import (
    "database/sql"
    "log"
)

type User struct {
    Name     string
    Email    string
    Password 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.go

package main

func 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.go

package main

import (
    "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.go

package main

import (
    "database/sql"
    "fmt"
    "log"
)

// VerifyUserLogin 验证用户登录
func VerifyUserLogin(db *sql.DB, email, password string) {
    var passwordHash string
    err := 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.go

package main

func 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.go

package main

import (
    "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.go

package main

import (
    "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 int
        var title, author string
        var publishedDate time.Time
        if 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.go

package main

import "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.go

func 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.go

func 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 int
        var title string
        var borrowDate, returnDate sql.NullTime
        if 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.go

package main

func 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.go

package main

import (
    "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 int
        var title, author string
        if 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.go

package main

func 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.go

package main

import (
    "gorm.io/gorm"
    "time"
)

type Employee struct {
    ID        uint           `gorm:"primaryKey"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt gorm.DeletedAt `gorm:"index"`
    Name      string
    Email     string         `gorm:"uniqueIndex"`
    Position  string
}

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

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

// db.go

package main

import (
    "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 []Employee
    result := 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.go

package main

func 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.go

type LeaveRecord struct {
    gorm.Model
    EmployeeID uint
    LeaveDate  time.Time
    ReturnDate time.Time
    Reason     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 []LeaveRecord
    if 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.go

package main

func main() {
    db := InitDB()

    // 假设已存在员工Jack Sparrow,其ID为1
    employeeID := 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.go

type Department struct {
    gorm.Model
    Name        string
    Description string
    Employees   []Employee `gorm:"many2many:employee_departments;"`
}

type Employee struct {
    gorm.Model
    Name       string
    Email      string `gorm:"uniqueIndex"`
    Position   string
    Departments []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 []Department
    if 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 Employee
    var department Department
    if 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.go

package main

func 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和数据库操作的深入掌握,你将能够构建更加复杂和功能丰富的应用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SCI文章复现 | GEO文章套路,数据下载和批次效应处理

原文链接: SCI文章复现 | GEO文章套路,数据下载和批次效应处理https://mp.weixin.qq.com/s/KBA67EJ7cCK5NDTUzrwJ2Q 一、前言 这是2024年春节后的第一个推送教程,我们也给大家赠送一个福利。将前期的付费教程免费推送给大家。其实&#xff…

第13章 网络 Page741~744 asio核心类 ip::tcp::socket

1. ip::tcp::socket liburl库使用"curl*" 代表socket 句柄 asio库使用ip::tcp::socket类代表TCP协议下的socket对象。 将“句柄”换成“对象”,因为asio库是不打折扣的C库 ip::tcp::socket提供一下常用异步操作都以async开头 表13-3 tcp::socket提供的异步操作 …

乡政府|乡政府管理系统|基于Springboot的乡政府管理系统设计与实现(源码+数据库+文档)

乡政府管理系统目录 目录 基于Springboot的乡政府管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、活动信息管理 3、新闻类型管理 4、新闻动态管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推…

BeginCTF2024 RE WP 剩下的复现

12. goforfun(寄) 前面是一些无关紧要的初始化 下面看到疑似rc4 虽然函数支离破碎,但可以看到rc4的结构,异或的部分做了魔改 后面似乎是base64换表,但脚本跑不出来,这里的算法没搞懂,只能贴一下…

layui表格中使用cascader后导致表格滚动条消失

修改前,受影响页面 修改后最终想要的效果 修改方法

智慧校园规划建设方案

校园信息化建设呈现智能化、应用多样化发展趋势,多种技术和应用交叉渗透至校园生活的各个方面,全面的智慧校园时代已经到来。 对智慧校园的四大应用领域分析 智慧的教学 信息共享交互:建立信息发布、共享、传播与交互的公共平台 教学流程…

torch.utils.data

整体架构 平时使用 pytorch 加载数据时大概是这样的: import numpy as np from torch.utils.data import Dataset, DataLoaderclass ExampleDataset(Dataset):def __init__(self):self.data [1, 2, 3, 4, 5]def __getitem__(self, idx):return self.data[idx]def…

Linux: GDB 调试工具

目录 概念: Linux 下 debug 和 release 的区别: GDB 的使用 : 激活和进入工作模式: 查看文件的内容: 运行调试的文件: 打断点: 查看断点: 删除断点: 禁用断点…

17.3.1.3 灰度

版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 灰度的算法主要有以下三种: 1、最大值法: 原图像:颜色值color(R,G,B&a…

wayland(xdg_wm_base) client 使用 dmabuf 最简实例

文章目录 前言一、zwp_linux_dmabuf_v1 协议二、wayland client 使用 zwp_linux_dmabuf_v1 协议传递dma-buf代码实例1. wayland_dmabuf.c 代码实例2. xdg-shell-protocol.c 和 xdg-shell-client-protocol.h3. linux-dmabuf-unstable-v1-client-protocol.h 和 linux-dmabuf-unst…

如何在JavaScript中使用大于和小于运算符

在你的 JavaScript 程序中,你经常需要比较两个值,以确定一个是否大于另一个或小于另一个。这就是大于和小于运算符派上用场的地方。 在本文中,我们将通过代码示例更详细地介绍如何使用这些运算符。 (本文内容参考:ja…

Stable Diffusion 模型下载:Beautiful Realistic Asians(美丽真实的亚洲人)

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十 下载地址 模型介绍 Beautiful Realistic Asians(BRA)模型是由作者自己训练…

阿里云服务器租用价格 2024年新版活动报价及租用收费标准

2024年最新阿里云服务器租用费用优惠价格表,轻量2核2G3M带宽轻量服务器一年61元,折合5元1个月,新老用户同享99元一年服务器,2核4G5M服务器ECS优惠价199元一年,2核4G4M轻量服务器165元一年,2核4G服务器30元3…

NumPyML 源码解析(四)

numpy-ml\numpy_ml\neural_nets\utils\__init__.py """ 神经网络特定的常见辅助函数。neural_nets.utils 模块包含神经网络特定的辅助函数,主要用于处理 CNNs。 """# 从当前目录下的 utils 模块中导入所有内容 from .utils import *…

天锐绿盾|防泄密系统|计算机文件数据\资料安全管理软件

“天锐绿盾”似乎是一款专注于防泄密和计算机文件数据/资料安全管理的软件。在信息安全日益受到重视的今天,这样的软件对于保护企业的核心数据资产和防止敏感信息泄露至关重要。 通用地址:www.drhchina.com 防泄密系统的主要功能通常包括: 文…

组合数的计算

1.由定义式直接算&#xff1a;n!/m!*(n-m)! #include <iostream> using namespace std; long long combine(long long m,long long n ){long long result1;for(int i1;i<n1;i){//n!result*i;}for(int i1;i<m1;i){//n!/m!result/i;}for(int i1;i<n-m1;i){//n!/(…

红蓝对抗:网络安全领域的模拟实战演练

引言&#xff1a; 随着信息技术的快速发展&#xff0c;网络安全问题日益突出。为了应对这一挑战&#xff0c;企业和组织需要不断提升自身的安全防护能力。红蓝对抗作为一种模拟实战演练方法&#xff0c;在网络安全领域得到了广泛应用。本文将介绍红蓝对抗的概念、目的、过程和…

问卷设计初探:题目类型概览与注意事项梳理

问卷法常被人们应用于社会调查中&#xff0c;它能反馈出最真实的社会信息。所以&#xff0c;很多企业为了最大程度地了解市场&#xff0c;也经常使用问卷调查法进行研究。不过&#xff0c;想要发挥出问卷法的最大用处&#xff0c;前提是要将问卷设计规范并且可量化。 想要设计…

【漏洞复现】企语iFair协同管理系统任意文件读取漏洞

Nx01 产品简介 企语iFair协同管理系统是一款专业的协同办公软件&#xff0c;该管理系统兼容性强&#xff0c;适合多种企业类型。 Nx02 漏洞描述 企语iFair协同管理系统存在任意文件读取漏洞&#xff0c;未经身份认证的攻击者可以通过此漏洞获取服务器敏感信息。 Nx03 产品主页…

租房招聘|在线租房和招聘平台|基于Springboot的在线租房和招聘平台设计与实现(源码+数据库+文档)

在线租房和招聘平台目录 目录 基于Springboot的在线租房和招聘平台设计与实现 一、前言 二、系统功能设计 三、系统实现 1、房屋管理 2、招聘管理 3、平台资讯管理 4、平台资讯类型管理 四、数据库设计 1、实体ER图 六、论文参考 七、最新计算机毕设选题推荐 八、源…