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

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

《Go 简易速速上手小册》第9章:数据库交互(2024 最新版)(上)+https://developer.aliyun.com/article/1487013


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


目录
相关文章
|
4天前
|
存储 SQL 监控
Visual Basic与数据库交互:实现数据访问和管理
【4月更文挑战第27天】本文探讨了使用Visual Basic进行数据库编程的基础,包括数据库基础、连接、数据访问技术如ADO.NET,数据绑定,事务处理,存储过程与视图。还强调了性能优化、安全性、测试与调试,以及持续维护的重要性。通过掌握这些概念和技巧,开发者能构建高效、可靠的数据驱动应用。
|
4天前
|
关系型数据库 Go 数据库
【Go语言专栏】Go语言中的数据库迁移与版本控制
【4月更文挑战第30天】本文介绍了Go语言中的数据库迁移和版本控制。针对数据库迁移,文章提到了使用Flyway和Liquibase两个工具。通过示例展示了如何在Go中集成这两个工具进行数据库结构的修改,以适应业务变化。而对于版本控制,文章以Git为例,说明了如何利用Git进行源代码和配置文件的管理,确保代码一致性与可追溯性。
|
4天前
|
SQL 关系型数据库 MySQL
【Go语言专栏】使用Go语言连接MySQL数据库
【4月更文挑战第30天】本文介绍了如何使用Go语言连接和操作MySQL数据库,包括选择`go-sql-driver/mysql`驱动、安装导入、建立连接、执行SQL查询、插入/更新/删除操作、事务处理以及性能优化和最佳实践。通过示例代码,展示了连接数据库、使用连接池、事务管理和性能调优的方法,帮助开发者构建高效、稳定的Web应用。
|
4天前
|
SQL 关系型数据库 Go
【Go语言专栏】Go语言中的数据库操作基础
【4月更文挑战第30天】本文介绍了Go语言中使用`database/sql`包与SQLite数据库交互的基础,包括导入包、建立连接、创建表、插入、查询、更新和删除数据。还涉及事务处理和错误处理,强调了错误检查的重要性。通过示例代码,展示了如何在Go中执行常见的数据库操作。更多学习资源可参考Go语言官方文档和SQLite官方文档。
|
4天前
|
算法 Go 分布式数据库
构建高可用的分布式数据库集群:使用Go语言与Raft共识算法
随着数据量的爆炸式增长,单一数据库服务器已难以满足高可用性和可扩展性的需求。在本文中,我们将探讨如何使用Go语言结合Raft共识算法来构建一个高可用的分布式数据库集群。我们不仅会介绍Raft算法的基本原理,还会详细阐述如何利用Go语言的并发特性和网络编程能力来实现这一目标。此外,我们还将分析构建过程中可能遇到的挑战和解决方案,为读者提供一个完整的实践指南。
|
4天前
|
缓存 监控 中间件
中间件Cache-Aside策略应用程序直接与缓存和数据库进行交互
【5月更文挑战第8天】中间件Cache-Aside策略应用程序直接与缓存和数据库进行交互
23 4
|
4天前
|
存储 负载均衡 Go
【Go 语言专栏】使用 Go 语言实现分布式数据库操作
【4月更文挑战第30天】本文探讨了使用Go语言实现分布式数据库操作,强调其在并发性能、网络编程、语法简洁和跨平台性上的优势。关键技术和步骤包括数据分片、数据同步、负载均衡及故障转移。通过实例分析和挑战解决,展示了Go语言在大规模数据处理中的高效与可靠性,为开发者提供指导。
|
4天前
|
监控 安全 数据库连接
【Go语言专栏】Go语言中的数据库连接池管理
【4月更文挑战第30天】本文探讨了Go语言中数据库连接池的概念、实现和最佳实践。连接池预先创建并维护数据库连接,减少建立和关闭连接的开销,提高效率和应用稳定性。文中提供了一个简单的连接池实现示例,并列出使用连接池的最佳实践,包括合理设置连接池大小、控制连接生命周期及错误处理等。Go语言的并发机制如协程和通道有助于实现线程安全的连接池。通过实际案例分析,文章旨在帮助开发者更好地理解和应用连接池技术。
|
4天前
|
SQL 关系型数据库 MySQL
【PHP开发专栏】PHP与数据库交互入门
【4月更文挑战第29天】本文介绍了PHP与数据库交互的基础,包括选择MySQL或PostgreSQL等关系型数据库,使用MySQLi或PDO扩展进行连接。示例展示了如何使用PHP连接数据库,如MySQLi的面向对象连接方式和PDO的多数据库支持。此外,还讲解了执行SQL查询(如SELECT、INSERT、UPDATE、DELETE)的操作,并强调了安全性与错误处理,如使用预处理语句防止SQL注入。通过学习,读者可掌握PHP操作数据库的基本技能。
|
4天前
|
Java 关系型数据库 MySQL
【JDBC编程】基于MySql的Java应用程序中访问数据库与交互数据的技术
【JDBC编程】基于MySql的Java应用程序中访问数据库与交互数据的技术