How do I batch sql statements with package database/sql

前端 未结 12 2666
深忆病人
深忆病人 2020-12-04 16:46

How do I batch sql statements with Go\'s database/sql package?

In Java I would do it like this :

// Create a prepared statement
String sql = \"INSERT         


        
12条回答
  •  借酒劲吻你
    2020-12-04 17:36

    Expanding on Avi Flax's answer, I needed an ON CONFLICT DO UPDATE clause in my INSERT.

    The solution to this is to COPY to a temporary table (set to delete at the end of the transaction) then INSERT from the temporary table to the permanent table.

    Here's the code I settled on:

    func (fdata *FDataStore) saveToDBBulk(items map[fdataKey][]byte) (err error) {
        tx, err := fdata.db.Begin()
        if err != nil {
            return errors.Wrap(err, "begin transaction")
        }
        txOK := false
        defer func() {
            if !txOK {
                tx.Rollback()
            }
        }()
    
        // The ON COMMIT DROP clause at the end makes sure that the table
        // is cleaned up at the end of the transaction.
        // While the "for{..} state machine" goroutine in charge of delayed
        // saving ensures this function is not running twice at any given time.
        _, err = tx.Exec(sqlFDataMakeTempTable)
        // CREATE TEMPORARY TABLE fstore_data_load
        // (map text NOT NULL, key text NOT NULL, data json)
        // ON COMMIT DROP
        if err != nil {
            return errors.Wrap(err, "create temporary table")
        }
    
        stmt, err := tx.Prepare(pq.CopyIn(_sqlFDataTempTableName, "map", "key", "data"))
        for key, val := range items {
            _, err = stmt.Exec(string(key.Map), string(key.Key), string(val))
            if err != nil {
                return errors.Wrap(err, "loading COPY data")
            }
        }
    
        _, err = stmt.Exec()
        if err != nil {
            return errors.Wrap(err, "flush COPY data")
        }
        err = stmt.Close()
        if err != nil {
            return errors.Wrap(err, "close COPY stmt")
        }
    
        _, err = tx.Exec(sqlFDataSetFromTemp)
        // INSERT INTO fstore_data (map, key, data)
        // SELECT map, key, data FROM fstore_data_load
        // ON CONFLICT DO UPDATE SET data = EXCLUDED.data
        if err != nil {
            return errors.Wrap(err, "move from temporary to real table")
        }
    
        err = tx.Commit()
        if err != nil {
            return errors.Wrap(err, "commit transaction")
        }
        txOK = true
        return nil
    }
    

提交回复
热议问题