Golang中如何执行多条更新语句

Golang中如何执行多条更新语句 如何使用Golang执行多个更新语句,例如:

UPDATE $userName SET P1 = '$p1MON' WHERE day = 'MON1';
        UPDATE $userName SET P1 = '$p1TUE' WHERE day = 'TUE1';
        UPDATE $userName SET P1 = '$p1WED' WHERE day = 'WED1'

我知道,我们可以使用 db.prepare 来处理多个插入语句,但对于更新语句感到疑惑。

4 回复

我也遇到了同样的问题。幸运的是看到了你的帖子,感谢分享。你真是太棒了。 表情

更多关于Golang中如何执行多条更新语句的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


uvaaram:

我们如何使用 Golang 执行多个像这样的更新语句?

使用原生 SQL

UPDATE users SET username =
CASE day
WHEN 'MON1' THEN '$p1MON'
WHEN 'TUE1' THEN '$p1TUE'
WHEN 'WED1' THEN '$p1WED'
ELSE '?' END;

DB Fiddle - SQL Database Playground

一个用于测试、调试和分享 SQL 片段的在线 SQL 数据库演练场。

你好 Kiran,

标准库并未提供ORM的高级功能或驱动库。你可以使用驱动库提供的批量更新功能。

我不知道你目前在使用哪种数据库,但我假设是PostgreSQL。通过驱动库,你可以轻松地进行批量更新。

我还找到了用于生成批量更新的原始SQL语句,如果你不希望使用驱动库,可以在 database/sql 中使用它。

补充说明:db.prepare 并不会让你直接拥有批量插入功能。它的唯一目的是为你的数据库开启一个事务。

请参考以下示例: https://pkg.go.dev/github.com/go-pg/pg#example-DB-Update-BulkUpdate

db := modelDB()

book1 := &Book{
	Id:        1,
	Title:     "updated book 1",
	UpdatedAt: time.Now(),
}
book2 := &Book{
	Id:        2,
	Title:     "updated book 2",
	UpdatedAt: time.Now(),
}

// UPDATE "books" AS "book"
// SET "title" = _data."title"
// FROM (VALUES ('updated book 1', 1), ('updated book 2', 2)) AS _data("title", "id")
// WHERE "book"."id" = _data."id"
_, err := db.Model(book1, book2).Column("title", "updated_at").Update()
if err != nil {
	panic(err)
}

var books []Book
err = db.Model(&books).Order("id").Select()
if err != nil {
	panic(err)
}

fmt.Println(books)

在Golang中执行多条更新语句,可以使用事务(Transaction)来确保原子性,或者使用预处理语句(Prepared Statement)批量执行。以下是两种方法的示例代码:

方法一:使用事务(推荐)

package main

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

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    userName := "users"
    updates := []struct {
        day string
        p1  string
    }{
        {"MON1", "value1"},
        {"TUE1", "value2"},
        {"WED1", "value3"},
    }

    tx, err := db.Begin()
    if err != nil {
        panic(err)
    }

    for _, update := range updates {
        query := fmt.Sprintf("UPDATE %s SET P1 = ? WHERE day = ?", userName)
        _, err := tx.Exec(query, update.p1, update.day)
        if err != nil {
            tx.Rollback()
            panic(err)
        }
    }

    err = tx.Commit()
    if err != nil {
        panic(err)
    }
}

方法二:使用预处理语句批量执行

package main

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

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    userName := "users"
    query := fmt.Sprintf("UPDATE %s SET P1 = ? WHERE day = ?", userName)
    stmt, err := db.Prepare(query)
    if err != nil {
        panic(err)
    }
    defer stmt.Close()

    updates := []struct {
        day string
        p1  string
    }{
        {"MON1", "value1"},
        {"TUE1", "value2"},
        {"WED1", "value3"},
    }

    for _, update := range updates {
        _, err := stmt.Exec(update.p1, update.day)
        if err != nil {
            panic(err)
        }
    }
}

方法三:使用SQL语句拼接(注意SQL注入风险)

package main

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

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    userName := "users"
    updates := map[string]string{
        "MON1": "value1",
        "TUE1": "value2",
        "WED1": "value3",
    }

    var queries []string
    for day, p1 := range updates {
        query := fmt.Sprintf("UPDATE %s SET P1 = '%s' WHERE day = '%s'", userName, p1, day)
        queries = append(queries, query)
    }

    fullQuery := strings.Join(queries, ";")
    _, err = db.Exec(fullQuery)
    if err != nil {
        panic(err)
    }
}

第一种方法使用事务,确保所有更新要么全部成功,要么全部失败。第二种方法使用预处理语句,可以重复使用SQL模板。第三种方法直接拼接SQL语句,但需要注意防止SQL注入,建议使用参数化查询。

回到顶部