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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: 《Go 简易速速上手小册》第9章:数据库交互(2024 最新版)

4001a6010e053ebe5ba4462482fdd0d.png

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与数据库进行交互,实现一个基本的图书管理系统。这为进一步开发更复杂的数据库驱动应用奠定了基础。随着对数据库操作的深入掌握,你将能够构建更加强大和灵活的数据管理和分析功能。


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

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3天前
|
JSON 缓存 数据库
Django ORM的QuerySet:解锁数据库交互的魔法钥匙
Django ORM的QuerySet:解锁数据库交互的魔法钥匙
|
8天前
|
Java 关系型数据库 数据库连接
【MyBatis】初步解析MyBatis:实现数据库交互与关系映射的全面指南
【MyBatis】初步解析MyBatis:实现数据库交互与关系映射的全面指南
15 1
|
9天前
|
Java 数据库连接 数据库
解密Persistence Context,精通ORM和数据库交互的关键!
解密Persistence Context,精通ORM和数据库交互的关键!
|
12天前
|
关系型数据库 MySQL Go
Go语言介绍以及如何在Go语言中操作MySQL数据库
Go语言介绍以及如何在Go语言中操作MySQL数据库
27 3
|
22天前
|
存储 NoSQL Go
轻松上手,使用Go语言操作Redis数据库
轻松上手,使用Go语言操作Redis数据库
|
2天前
|
存储 SQL PHP
PHP中的PDO与数据库交互
PHP的PDO扩展提供了一种方式来统一访问多种数据库
|
26天前
|
NoSQL 关系型数据库 MongoDB
DTS支持哪些非关系型数据库的数据交互?
【6月更文挑战第4天】DTS支持哪些非关系型数据库的数据交互?
23 1
|
4天前
|
缓存 Java 数据库连接
构建高效数据库交互:Hibernate与JPA的性能优化策略
【6月更文挑战第25天】在大数据时代,优化Hibernate和JPA的数据库性能至关重要。本文探讨了优化策略:正确配置映射以减少冗余,利用JPQL/HQL提升查询效率,避免全字段选择,使用索引和分页,有效利用缓存策略,以及管理事务以平衡资源锁定。示例代码展示了分页查询的实现,以防止性能下降。
|
1月前
|
存储 数据挖掘 关系型数据库
DataFrame 与数据库交互:从导入到导出
【5月更文挑战第19天】本文介绍了如何在数据分析中实现DataFrame与MySQL数据库之间的数据交互。通过`pandas`的`read_sql`函数可将数据库中的数据导入DataFrame,处理后使用数据库游标执行插入或更新操作将数据导回。注意数据类型匹配、数据完整性和一致性。对于大量数据,可采用分块读取和批量操作提升效率。这种交互能结合数据库的存储管理和DataFrame的分析功能,提高数据处理效率。
48 2
|
1月前
|
缓存 监控 中间件
中间件Cache-Aside策略应用程序直接与缓存和数据库进行交互
【5月更文挑战第8天】中间件Cache-Aside策略应用程序直接与缓存和数据库进行交互
37 4