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


目录
相关文章
|
17天前
|
存储 SQL 关系型数据库
PHP与数据库交互:从基础到进阶
【10月更文挑战第9天】在编程的世界里,数据是流动的血液,而数据库则是存储这些珍贵资源的心脏。PHP作为一门流行的服务器端脚本语言,其与数据库的交互能力至关重要。本文将带你从PHP与数据库的基本连接开始,逐步深入到复杂查询的编写和优化,以及如何使用PHP处理数据库结果。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的知识和技巧,让你在PHP和数据库交互的道路上更加从容不迫。
|
21天前
|
SQL 关系型数据库 MySQL
Go语言项目高效对接SQL数据库:实践技巧与方法
在Go语言项目中,与SQL数据库进行对接是一项基础且重要的任务
30 11
|
3月前
|
SQL 关系型数据库 MySQL
PHP与数据库交互的艺术:深入探讨PDO扩展
【8月更文挑战第28天】在数字信息时代的海洋里,PHP作为一艘灵活的帆船,承载着无数网站和应用的梦想。而PDO扩展,则是这艘帆船上不可或缺的导航仪,指引着数据安全与效率的航向。本文将带你领略PHP与数据库交互的艺术,深入浅出地探索PDO的世界,从连接数据库到执行复杂的查询,每一步都清晰可见。我们将一起航行在这段奇妙的旅程上,解锁数据的奥秘,体验编程的乐趣。
37 1
|
3月前
|
SQL 关系型数据库 MySQL
干货!python与MySQL数据库的交互实战
干货!python与MySQL数据库的交互实战
|
3月前
|
数据库 C# 开发者
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
48 0
|
3月前
|
SQL 数据库 Java
Hibernate 日志记录竟藏着这些秘密?快来一探究竟,解锁调试与监控最佳实践
【8月更文挑战第31天】在软件开发中,日志记录对调试和监控至关重要。使用持久化框架 Hibernate 时,合理配置日志可帮助理解其内部机制并优化性能。首先,需选择合适的日志框架,如 Log4j 或 Logback,并配置日志级别;理解 Hibernate 的多级日志,如 DEBUG 和 ERROR,以适应不同开发阶段需求;利用 Hibernate 统计功能监测数据库交互情况;记录自定义日志以跟踪业务逻辑;定期审查和清理日志避免占用过多磁盘空间。综上,有效日志记录能显著提升 Hibernate 应用的性能和稳定性。
47 0
|
3月前
|
存储 编译器 Go
|
3月前
|
开发者 UED Java
Play Framework惊天秘密:如何让异常处理优雅得像芭蕾舞?
【8月更文挑战第31天】在Web应用开发中,异常处理至关重要,直接影响应用稳定性和用户体验。Play Framework作为轻量级Java Web框架,提供了基于Scala偏函数的灵活异常处理机制。通过实现`HttpErrorHandler`接口可定义全局异常逻辑,而在控制器中使用try-catch块则能捕获特定异常。定义自定义异常类也有助于表示特定错误情况。最佳实践包括保持处理一致性、提供有用错误信息、记录日志及分类处理异常。掌握这些技巧,能使Play应用更健壮可靠。
60 0
|
3月前
|
SQL 数据库 开发者
全面提速你的数据访问:Entity Framework Core性能优化指南,从预加载到批量操作的最佳实践揭秘,打造高性能数据库交互体验
【8月更文挑战第31天】本文详细介绍如何在Entity Framework Core(EF Core)中优化数据访问性能,涵盖从创建项目到定义领域模型、配置数据库上下文的最佳实践。文章通过具体代码示例讲解了预加载、惰性加载、显式加载、投影及批量操作等技术的应用,并介绍了如何使用SQL查询和调整查询性能来进一步提升效率。通过合理运用这些技术,开发者可以构建出高效且响应迅速的数据访问层,提升应用程序的整体性能和用户体验。
51 0
|
3月前
|
API 数据库 开发者
【独家揭秘】Django ORM高手秘籍:如何玩转数据模型与数据库交互的艺术?
【8月更文挑战第31天】本文通过具体示例详细介绍了Django ORM的使用方法,包括数据模型设计与数据库操作的最佳实践。从创建应用和定义模型开始,逐步演示了查询、创建、更新和删除数据的全过程,并展示了关联查询与过滤的技巧,帮助开发者更高效地利用Django ORM构建和维护Web应用。通过这些基础概念和实践技巧,读者可以更好地掌握Django ORM,提升开发效率。
36 0