2015-01-02 5 views
0

Я в настоящее время борется (мой второй день), чтобы найти лучший способ сделать несколько запросов и задавался вопросом, знаете ли вы решение.Идиоматический способ сделать несколько запросов в golang за одну транзакцию

У меня есть открытое * sql.DB соединение, названное MyDB и использовать гоу-SQL-драйвер

func TruncateGalleryImport() error { 

    s := make([]string, 0) 

    s = append(s, "TRUNCATE TABLE add_map") 
    s = append(s, "TRUNCATE TABLE album") 
    s = append(s, "TRUNCATE TABLE album_permission") 
    s = append(s, "TRUNCATE TABLE album_view") 
    s = append(s, "TRUNCATE TABLE album_watch") 
    s = append(s, "TRUNCATE TABLE media") 
    s = append(s, "TRUNCATE TABLE media_user_view") 
    s = append(s, "TRUNCATE TABLE media_view") 
    s = append(s, "TRUNCATE TABLE media_watch") 
    s = append(s, "TRUNCATE TABLE private_map") 
    s = append(s, "TRUNCATE TABLE attachment") 
    s = append(s, "TRUNCATE TABLE attachment_data") 

    for _, q := range s { 
     _, err := myDb.Exec(q) 
     if err != nil { 
      return err 
     } 
    } 

    return nil 
} 

Можно ли совершать все вышеперечисленные вопросы вместе, используя только одну транзакцию?

Приветствие

ответ

2

Используйте транзакции, как это (см комментариев в коде):

func TruncateGalleryImport() error { 
    s := make([]string, 0) 

    s = append(s, "TRUNCATE TABLE add_map") 
    s = append(s, "TRUNCATE TABLE album") 
    s = append(s, "TRUNCATE TABLE album_permission") 
    s = append(s, "TRUNCATE TABLE album_view") 
    s = append(s, "TRUNCATE TABLE album_watch") 
    s = append(s, "TRUNCATE TABLE media") 
    s = append(s, "TRUNCATE TABLE media_user_view") 
    s = append(s, "TRUNCATE TABLE media_view") 
    s = append(s, "TRUNCATE TABLE media_watch") 
    s = append(s, "TRUNCATE TABLE private_map") 
    s = append(s, "TRUNCATE TABLE attachment") 
    s = append(s, "TRUNCATE TABLE attachment_data") 

    // Get new Transaction. See http://golang.org/pkg/database/sql/#DB.Begin 
    txn, err := myDb.Begin() 

    if err != nil { 
     return err 
    } 

    defer func() { 
     // Rollback the transaction after the function returns. 
     // If the transaction was already commited, this will do nothing. 
     _ = txn.Rollback() 
    }() 

    for _, q := range s { 
     // Execute the query in the transaction. 
     _, err := txn.Exec(q) 

     if err != nil { 
      return err 
     } 
    } 

    // Commit the transaction. 
    return txn.Commit() 
} 
+0

Остерегайтесь: он работает только для двигателей баз данных, чья инструкция truncate является транзакционной. Для некоторых из них (Oracle, MySQL) это не так. Таблица усечений обычно реализуется как операция DDL, а не DML. –

+0

Отличная помощь! Благодарим за включение заявления о дефере! – Alex

+1

Чтобы быть понятным, некоторые MySQL-движки ('InnoDB') поддерживают транзакции, тогда как другие (' MyISAM') этого не делают. – carbocation

0

Вы можете использовать обернутую функцию, чтобы сделать коммит откат логику /, возможно, даже расширить ошибку обработка с использованием сопоставления строк.

// RDBTransaction is a function which abstracts a sql transaction 
// into a function with an isolation level (isolvl) parameter. 
// the following integers represent the available isolation levels (isolvl) 
// 1: SERIALIZABLE 
// 2: REPEATABLE READ 
// 3: READ COMMITTED 
// 4: READ UNCOMMITTED 
func RDBTransaction(db *sql.DB, isolvl int, fn func(*sql.Tx) error) (err error) { 
    var tx *sql.Tx 
    tx, err = db.Begin() 
    if err != nil { 
     return err 
    } 

    // transaction isolation level setting 
    switch isolvl { 
    case 1: 
     _, err = tx.Exec(`set transaction isolation level serializable`) 
    case 2: 
     _, err = tx.Exec(`set transaction isolation level repeatable read`) 
    case 3: 
     _, err = tx.Exec(`set transaction isolation level read committed`) 
    case 4: 
     _, err = tx.Exec(`set transaction isolation level read uncommitted`) 
    default: 
     _, err = tx.Exec(`set transaction isolation level serializable`) 
    } 
    if err != nil { 
     return err 
    } 

    // catch all, commit/rollback 
    defer func() { 
     if err != nil { 
      tx.Rollback() 
      return 
     } 
     err = tx.Commit() 
    }() 

    // run transaction 
    err = fn(tx) 

    return err 
} 
Смежные вопросы