Golang实现高效的批量SQL更新操作

Golang实现高效的批量SQL更新操作 我有一个表,想将具有某个ID的行复制到同一表中的其他行。关于最佳实践有什么建议吗?如何进行批量更新?

示例:

id foreign_key_id param_a param_b created_at updated_at
1 23 23 44 2022-05-30 2022-05-30
2 35 32 22 2022-05-30 2022-05-30
3 13 12 33 2022-05-30 2022-05-30
4 12 33 11 2022-05-30 2022-05-30
5 55 18 22 2022-05-30 2022-05-30

我想用 param_aparam_b 的值为 23 来更新 foreign_key_id1213 的行。


更多关于Golang实现高效的批量SQL更新操作的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

我正在寻找一种性能更好的模式来进行批量更新,你的回答完全正确,我的问题确实很蠢。

更多关于Golang实现高效的批量SQL更新操作的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


说实话,这个问题与 Go 语言毫无关系;这是一个“纯 SQL”查询。

UPDATE <table_name>
SET
    param_a = 23
    param_b = 23
WHERE foreign_key_id IN (12, 13);

我是不是遗漏了什么?

是的,是我的错,我会删除它。

在Golang中实现高效的批量SQL更新操作,推荐使用预处理语句和事务处理。以下是具体实现方案:

package main

import (
    "database/sql"
    "fmt"
    "log"
)

func batchUpdate(db *sql.DB, sourceID int, targetIDs []int) error {
    // 开启事务
    tx, err := db.Begin()
    if err != nil {
        return fmt.Errorf("开启事务失败: %v", err)
    }
    defer tx.Rollback()

    // 查询源数据
    var paramA, paramB int
    err = tx.QueryRow(
        "SELECT param_a, param_b FROM your_table WHERE id = ?", 
        sourceID,
    ).Scan(&paramA, &paramB)
    if err != nil {
        return fmt.Errorf("查询源数据失败: %v", err)
    }

    // 准备批量更新语句
    stmt, err := tx.Prepare(`
        UPDATE your_table 
        SET param_a = ?, param_b = ?, updated_at = CURRENT_TIMESTAMP 
        WHERE foreign_key_id = ?
    `)
    if err != nil {
        return fmt.Errorf("准备语句失败: %v", err)
    }
    defer stmt.Close()

    // 批量执行更新
    for _, targetID := range targetIDs {
        _, err := stmt.Exec(paramA, paramB, targetID)
        if err != nil {
            return fmt.Errorf("更新ID %d 失败: %v", targetID, err)
        }
    }

    // 提交事务
    if err := tx.Commit(); err != nil {
        return fmt.Errorf("提交事务失败: %v", err)
    }

    return nil
}

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

    // 示例:将ID=1的数据复制到foreign_key_id为12和13的行
    targetIDs := []int{12, 13}
    if err := batchUpdate(db, 1, targetIDs); err != nil {
        log.Fatal(err)
    }
    
    fmt.Println("批量更新完成")
}

对于更大批量的更新,可以使用 IN 子句的变体:

func batchUpdateOptimized(db *sql.DB, sourceID int, targetIDs []int) error {
    // 查询源数据
    var paramA, paramB int
    err := db.QueryRow(
        "SELECT param_a, param_b FROM your_table WHERE id = ?", 
        sourceID,
    ).Scan(&paramA, &paramB)
    if err != nil {
        return fmt.Errorf("查询源数据失败: %v", err)
    }

    // 构建IN子句参数
    query := `
        UPDATE your_table 
        SET param_a = ?, param_b = ?, updated_at = CURRENT_TIMESTAMP 
        WHERE foreign_key_id IN (`
    
    args := []interface{}{paramA, paramB}
    for i, id := range targetIDs {
        if i > 0 {
            query += ","
        }
        query += "?"
        args = append(args, id)
    }
    query += ")"

    // 执行批量更新
    _, err = db.Exec(query, args...)
    if err != nil {
        return fmt.Errorf("批量更新失败: %v", err)
    }

    return nil
}

使用 sqlx 库可以进一步简化操作:

import "github.com/jmoiron/sqlx"

func batchUpdateWithSqlx(db *sqlx.DB, sourceID int, targetIDs []int) error {
    // 查询源数据
    var sourceRow struct {
        ParamA int `db:"param_a"`
        ParamB int `db:"param_b"`
    }
    
    err := db.Get(&sourceRow, 
        "SELECT param_a, param_b FROM your_table WHERE id = ?", 
        sourceID,
    )
    if err != nil {
        return err
    }

    // 构建批量更新
    query, args, err := sqlx.In(`
        UPDATE your_table 
        SET param_a = ?, param_b = ?, updated_at = CURRENT_TIMESTAMP 
        WHERE foreign_key_id IN (?)`,
        sourceRow.ParamA, sourceRow.ParamB, targetIDs,
    )
    if err != nil {
        return err
    }

    query = db.Rebind(query)
    _, err = db.Exec(query, args...)
    return err
}

这些方法通过事务保证数据一致性,使用预处理语句提高性能,适合处理批量更新场景。

回到顶部