使用golang批量插入复制sql表

时间:2018-10-19 15:03:49

标签: sql go

对于上下文,我是新手,我正在创建一个程序,可以将表从Oracle复制到MySQL。 我使用database/sql go软件包,因此我假设它可以用于迁移任何类型的数据库。 为了简化我的问题,我要处理同一个MySQL数据库表名称world.city至world.city_copy2。 使用下面的代码,我最终在表的所有行中使用了相同的最后一个值:-( 我是否需要以某种方式通读循环中的所有值?有效的方法是什么?

package main

import (
    "database/sql"
    "fmt"
    "strings"

    _ "github.com/go-sql-driver/mysql"
)

const (
    user   = "user"
    pass   = "testPass"
    server = "localhost"
)

func main() {
    fmt.Print("test")
    conStr := fmt.Sprintf("%s:%s@tcp(%s)/world", user, pass, server)
    db, err := sql.Open("mysql", conStr)
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()
    err = db.Ping()
    if err != nil {
        panic(err.Error())
    }

    rows, err := db.Query("SELECT * FROM city")
    if err != nil {
        panic(err.Error()) // proper error handling instead of panic in your app
    }

    columns, err := rows.Columns()
    if err != nil {
        panic(err.Error()) // proper error handling instead of panic in your app
    }

    // Make a slice for the values
    values := make([]sql.RawBytes, len(columns))

    // rows.Scan wants '[]interface{}' as an argument, so we must copy the
    // references into such a slice
    scanArgs := make([]interface{}, len(values))
    for i := range values {
        scanArgs[i] = &values[i]
    }
    // that string will be generated according to len of columns
    placeHolders := "( ?, ?, ?, ?, ? )"

    // slice will contain all the values at the end
    bulkValues := []interface{}{}

    valueStrings := make([]string, 0)

    for rows.Next() {
        // get RawBytes from data
        err = rows.Scan(scanArgs...)
        if err != nil {
            panic(err.Error()) // proper error handling instead of panic in your app
        }
        valueStrings = append(valueStrings, placeHolders)
        bulkValues = append(bulkValues, scanArgs...)
        //

    }
    stmStr := fmt.Sprintf("INSERT INTO city_copy2 VALUES %s", strings.Join(valueStrings, ","))
    _, err = db.Exec(stmStr, bulkValues...)
    if err != nil {
        panic(err.Error())
    }
}

1 个答案:

答案 0 :(得分:1)

我已经签出了库的文档,看来这里的问题是bulkValues保留了指针的地址,因此当scanArgs更改时,bulkValues也会更改为该scanArgs的最新值。

您需要使用values变量来获取如下所示的值:

func main() {
    fmt.Print("test")
    conStr := fmt.Sprintf("%s:%s@tcp(%s)/soverflow", user, pass, server)
    db, err := sql.Open("mysql", conStr)
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()
    err = db.Ping()
    if err != nil {
        panic(err.Error())
    }

    rows, err := db.Query("SELECT * FROM city")
    if err != nil {
        panic(err.Error()) // proper error handling instead of panic in your app
    }

    columns, err := rows.Columns()
    if err != nil {
        panic(err.Error()) // proper error handling instead of panic in your app
    }

    // Make a slice for the values
    values := make([]sql.RawBytes, len(columns))

    // rows.Scan wants '[]interface{}' as an argument, so we must copy the
    // references into such a slice
    scanArgs := make([]interface{}, len(values))
    for i := range values {
        scanArgs[i] = &values[i]
    }
    // that string will be generated according to len of columns
    placeHolders := "( ?, ?, ?, ?, ? )"

    // slice will contain all the values at the end
    bulkValues := []interface{}{}

    valueStrings := make([]string, 0)
    // make an interface to keep the record's value
    record := make([]interface{}, len(columns))
    for rows.Next() {
        // get RawBytes from data
        err = rows.Scan(scanArgs...)
        if err != nil {
            panic(err.Error()) // proper error handling instead of panic in your app
        }
        valueStrings = append(valueStrings, placeHolders)
        for i, col := range values {
            // you need to be carefull with the datatypes here
            // check out the docs for details on here
            record[i] = string(value)
        }
        bulkValues = append(bulkValues, record...)
    }
    stmStr := fmt.Sprintf("INSERT INTO city_copy2 VALUES %s", strings.Join(valueStrings, ","))
    _, err = db.Exec(stmStr, bulkValues...)
    if err != nil {
        panic(err.Error())
    }
}

您还可以找到文档here的示例。

注意:可能存在将数据库从psql复制到mysql的更有效的方法,但是此答案仅提供了针对您遇到的此特定问题的快速解决方案。