前言
三个库的简介
database/sql
database/sql官方示例 它是Go语言标准库中的一个包,提供了一组通用的接口和功能,用于与各种关系型数据库进行交互。(标准库的意思就是语言自带,负责开发go的工程师开发了database/sql)
使用database/sql
,开发人员可以编写通用的数据库操作代码,而不需要针对每种数据库实现特定的代码。
它提供了连接数据库、执行查询和事务处理等功能。
但是,database/sql
只提供了较低级别的接口,需要开发人员编写更多的代码来处理查询结果、映射数据库和执行常见的数据库操作。
缺点:示例较少,新手不友好
GORM
GORM官方文档 它是Go语言中一个流行的对象关系映射(ORM)库,建立在database/sql
之上,为开发人员提供了更高级别的接口和功能。
ORM库的目标是简化数据库操作,通过将数据库表映射到Go语言的结构体,开发人员可以使用面向对象的方式进行数据库操作,而无需编写大量的SQL语句。
GORM提供了丰富的功能,包括模型定义、查询构建、关联关系管理、事务支持和数据库迁移等。它还支持多种数据库后端,如MySQL、PostgreSQL、SQLite等。
sqlc + migrate
sqlc + migrate
sqlc
是一个用于生成类型安全的Go代码的工具,用于与数据库进行交互。它通过解析 SQL 文件并生成相应的 Go 代码来提供类型安全的数据库访问层。
使用 sqlc
,可以定义 SQL 查询和数据库表结构,并使用它们生成类型安全的 Go 代码。生成的代码包括查询方法、结构体定义和数据库表映射,使得可以在编译时捕获错误,并以类型安全的方式访问数据库。
三个库的优缺点
问chatGPT后得到的总结,进行简化
database/sql
优点:
- 官方包,得到GO社区的支持和维护
- 轻量级,不会引入额外的依赖
- 良好的跨数据库兼容性(支持的数据库多)
缺点:
- 缺少高级功能,如查询构建器,关联,迁移等
- 手动管理SQL语句,易出错且难以维护
GORM
优点:
- 提供了丰富的功能,如查询构建器、关联、迁移等
- 支持自动迁移数据库
- 提供了更高级的查询接口,减少了手动编写 SQL 语句的需求
- 良好的文档和社区支持
缺点:
- 依赖更多的外部库,可能导致项目不稳定
- 抽象层可能导致性能损失
- 可能需要更多的学习成本
sqlc
优点
- 将 SQL 查询转换为类型安全的 Go 代码,提高代码的可读性和安全性
- 通过生成代码,可以减少手动编写 SQL 语句的错误
- 支持 PostgreSQL 和 MySQL 数据库。
- 自动生成代码,易于维护。
缺点
- 没有支持所有类型的数据库。
- 可能需要对 SQL 语句进行调整以生成正确的 Go 代码。
- 自动生成的代码可能难以理解或调试。
- 功能相对有限,缺少一些高级功能,如关联、迁移等。
后端小白基于任务学习三个库
在日常web开发中,用到数据库大概需要完成什么需求?
- 创建数据库
- 数据迁移
- 基本增删改查
- 复杂查询:过滤条件,join
- 事务处理:item_count
- 错误处理
- 性能测试
标准库的学习
使用标准库创建表和数据迁移
package database
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq"
)
const (
host = "pg-for-go-mangosteen"
port = 5432
user = "mangosteen"
password = "123456"
dbname = "mangosteen_dev"
)
func PgConnect() {
connStr := fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname,
)
db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatalln(err)
}
DB = db //放到全局变量里面。同一个包可以用的
err = db.Ping() //测试数据库是否可以连接
if err != nil {
log.Fatalln(err)
}
log.Println("Successfully connect to db")
}
func PgCreateTables() {
// 创建 users 表
_, err := DB.Exec(`CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
)`)
if err != nil {
log.Fatalln(err)
}
log.Println("Successfully create users table")
}
func Migreate(){
_,err := DB.Exec(`ALTER TABLE users ADD COLUMN phone VARCHAR(50)`)
if err != nil{
log.Fatalln(err)
}
log.Println("Successfully add phone column to users table")
_,err = DB.Exec(`ALTER TABLE users ADD COLUMN address VARCHAR(200)`)
if err != nil{
log.Fatalln(err)
}
log.Println("Successfully add address column to users table")
//新增items表 SERIAL是自增的意思 因为PRIMARY KEY不会自增
_, err = DB.Exec(`CREATE TABLE IF NOT EXISTS items (
id SERIAL PRIMARY KEY,
amount INT NOT NULL,
happened_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
)`)
if err != nil{
log.Fatalln(err)
}
log.Println("Successfully add items table")
}
func PgClose() {
DB.Close()
log.Println("Successfully close db")
}
使用标准库进行增删改查
func Crud() {
//创建一个user 需要返回结果 所以最好用Query 不需要返回结果的用Exec
//增加一个用户
result, err := DB.Query(`INSERT INTO users (email) values ('1@qq.com')`)
if err != nil {
log.Fatalln(err)
}
if result.Next() {
var email string
result.Scan(&email)
log.Println("email:", email)
}
log.Println("Successfully create a user")
//改一个用户
_, err = DB.Exec(`UPDATE users SET phone = 18382088888 where email = '1@qq.com'`)
if err != nil {
log.Println(err)
} else {
log.Println("Successfully update a user")
}
//查一个用户
_, err = DB.Query(`SELECT phone FROM users WHERE email = '1@qq.com' offset 0 limit 3`)
if err != nil {
log.Println(err)
} else {
if result.Next() {
var phone string
result.Scan(&phone)
log.Println("phone:", phone)
}
log.Println("Successfully find a user")
}
}
GORM的学习
这一段是官方示例,先连接到PostgreSQL的数据库,再引入gorm
import (
"gorm.io/driver/postgres"
"gorm.io/gorm" )
dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
使用GORM创建表
func Connect() {
dsn := fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname,
)
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatalln(err)
}
DB = db //放到全局变量里面。同一个包可以用的
if err != nil {
log.Fatalln(err)
} else {
log.Println("Successfully connect to db")
}
}
type User struct {
ID int
Email string
CreatedAt time.Time
UpdatedAt time.Time
}
func CreateTables() {
u1 := User{Email: "fy@qq.com"}
// 创建 users 表
err := DB.Migrator().CreateTable(&u1)
if err != nil {
log.Fatalln(err)
} else {
log.Println("Successfully create users table")
}
}
创建多个表
type User struct {
ID int
Email string
Phone string
CreatedAt time.Time
UpdatedAt time.Time
}
type item struct{
ID int
UserID int
Amount int
HappenedAt time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
type Tag struct{
ID int
}
var models = []any{&User{}, &item{}, &Tag{}}
func CreateTables() {
for _, model := range models {
err := DB.Migrator().CreateTable(model)
if err != nil {
log.Fatalln(err)
}
}
log.Println("Successfully create users table")
}
func Migreate() {
DB.AutoMigrate(models...)
}
使用GORM迁移数据库
如何给user加一个字段,简单来讲在gorm中使用AutoMigrate就行,但是要删除一个字段要曲线救国
例如给user添加一个phone字段
type User struct {
ID int
Email string 'gorm:"uniqueIndex"'
Phone string
CreatedAt time.Time
UpdatedAt time.Time
}
func CreateTables() {
// 创建 users 表 ,有字段 但是都为零值
err := DB.Migrator().CreateTable(&User{})
if err != nil {
log.Fatalln(err)
} else {
log.Println("Successfully create users table")
}
}
func Migreate() {
DB.AutoMigrate(&User{})
}
使用GORM进行增删改查
增删改查有两种类型,一种是类型安全的,另一种是类型不安全的