Golang中如何从结构体插入数据库记录

Golang中如何从结构体插入数据库记录 你好,

我需要帮助,如何将一个与数据库表结构相似的Struct中的数据插入到表中。 我不想写冗长的插入脚本,比如: insert into <表名> values (?,?,?,?..) 然后从struct的每个字段中传递值。

3 回复

我强烈推荐 GORM:https://gorm.io/

基本上,你就不再需要编写任何 SQL 语句了 😊 我已经在好几个项目中使用了它,对于我那些(规模相当小的)项目来说,它运行得很好。

更多关于Golang中如何从结构体插入数据库记录的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我不想像这样写冗长的插入脚本。

ORM 是一种选择。我不喜欢它,因为所有的“魔法”会带来限制,而且你必须学习一个由较小群体支持的“新语言”。获取纯 SQL 问题的帮助比获取 ORM 问题的帮助更容易。

话虽如此,我也不喜欢编写看起来重复的代码。所以我使用 sqlx 的 .StructScan。不过,插入操作仍然很乏味。

似乎有一个工具——sqlc——可以自动生成所有乏味的东西。纯 SQL。https://www.youtube.com/watch?v=prh0hTyI1sU

在Golang中,可以使用结构体标签和反射来简化数据库插入操作。以下是使用database/sql包和结构体标签的示例:

package main

import (
    "database/sql"
    "fmt"
    "reflect"
    "strings"
    _ "github.com/go-sql-driver/mysql"
)

// 定义结构体标签
type User struct {
    ID       int    `db:"id"`
    Name     string `db:"name"`
    Email    string `db:"email"`
    Age      int    `db:"age"`
    Created  string `db:"created_at"`
}

// 插入记录的通用函数
func InsertRecord(db *sql.DB, table string, data interface{}) (sql.Result, error) {
    v := reflect.ValueOf(data).Elem()
    t := v.Type()
    
    var columns []string
    var placeholders []string
    var values []interface{}
    
    for i := 0; i < v.NumField(); i++ {
        field := t.Field(i)
        dbTag := field.Tag.Get("db")
        
        if dbTag != "" && dbTag != "id" && !strings.Contains(dbTag, "created_at") {
            columns = append(columns, dbTag)
            placeholders = append(placeholders, "?")
            values = append(values, v.Field(i).Interface())
        }
    }
    
    query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)",
        table,
        strings.Join(columns, ", "),
        strings.Join(placeholders, ", "))
    
    return db.Exec(query, values...)
}

func main() {
    db, err := sql.Open("mysql", "user:password@/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    user := &User{
        Name:    "张三",
        Email:   "zhangsan@example.com",
        Age:     25,
        Created: "2023-10-01",
    }
    
    result, err := InsertRecord(db, "users", user)
    if err != nil {
        panic(err)
    }
    
    id, _ := result.LastInsertId()
    fmt.Printf("插入成功,ID: %d\n", id)
}

对于更复杂的场景,可以使用ORM库如GORM:

package main

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

type Product struct {
    gorm.Model
    Code  string
    Price uint
}

func main() {
    dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
    db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        panic(err)
    }
    
    // 自动迁移
    db.AutoMigrate(&Product{})
    
    // 插入记录
    product := Product{Code: "D42", Price: 100}
    result := db.Create(&product)
    
    if result.Error != nil {
        panic(result.Error)
    }
    
    fmt.Printf("插入成功,ID: %d\n", product.ID)
}

使用sqlx库的示例:

package main

import (
    "github.com/jmoiron/sqlx"
    _ "github.com/go-sql-driver/mysql"
)

type User struct {
    ID    int    `db:"id"`
    Name  string `db:"name"`
    Email string `db:"email"`
}

func main() {
    db, err := sqlx.Connect("mysql", "user:password@/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()
    
    user := User{
        Name:  "李四",
        Email: "lisi@example.com",
    }
    
    query := `INSERT INTO users (name, email) VALUES (:name, :email)`
    result, err := db.NamedExec(query, user)
    if err != nil {
        panic(err)
    }
    
    id, _ := result.LastInsertId()
    fmt.Printf("插入成功,ID: %d\n", id)
}

这些方法都能避免手动编写冗长的插入语句,通过结构体自动生成SQL并绑定参数。

回到顶部