2016-10-16 123 views
6

aşağıdaki şeylerden üç yapmak bazı örnekler bulmakta sorun yaşıyorum hazırladı.Ham sql işlemleri ifadeleri

2) Hazırlanan ifadeleri kullanın.

3) Sorgu hatalarında geri alma.

Böyle bir şey yapmak istiyorum, ancak hazırlanmış ifadelerle. Ne verir pq: cannot insert multiple commands into a prepared statement

: Bu çalıştırdığınızda

stmt, stmt_err := db.Prepare(` 
      BEGIN TRANSACTION; 

      -- Insert record into first table. 

      INSERT INTO table_1 (
        thing_1, 
        whatever) 
      VALUES($1,$2); 

      -- Inert record into second table. 

      INSERT INTO table_2 (
        thing_2, 
        whatever) 
      VALUES($3,$4); 

      END TRANSACTION; 
      `) 
    if stmt_err != nil { 
      return stmt_err 
    } 
    res, res_err := stmt.Exec(
      thing_1, 
      whatever, 
      thing_2, 
      whatever) 

, bu hatayı alıyorum? ACID uyumlu işlemler golang'da bile mümkün mü? Bir örnek bulamıyorum.

EDIT örnek yok here.

cevap

8

Evet Git, sql transactions'un mükemmel bir uygulamasına sahiptir. İşlemi db.Begin ile başlatırız ve hata durumunda tx.Rollback ile her şey yolunda giderse tx.Commit ile bitirebiliriz.

type Tx struct { }

Tx is an in-progress database transaction.

A transaction must end with a call to Commit or Rollback.

After a call to Commit or Rollback, all operations on the transaction fail with ErrTxDone.

The statements prepared for a transaction by calling the transaction's Prepare or Stmt methods are closed by the call to Commit or Rollback.

Ayrıca işlem değişkeni tx.Prepare (...)

İşleviniz böyle görünüyor olabilir sorguları hazırlamak unutmayın:

func doubleInsert(db *sql.DB) error { 

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

    { 
     stmt, err := tx.Prepare(`INSERT INTO table_1 (thing_1, whatever) 
        VALUES($1,$2);`) 
     if err != nil { 
      return err 
     } 
     defer stmt.Close() 

     if _, err := stmt.Exec(thing_1, whatever); err != nil { 
      tx.Rollback() // return an error too, we may want to wrap them 
      return err 
     } 
    } 

    { 
     stmt, err := tx.Prepare(`INSERT INTO table_2 (thing_2, whatever) 
        VALUES($1, $2);`) 
     if err != nil { 
      return err 
     } 
     defer stmt.Close() 

     if _, err := stmt.Exec(thing_2, whatever); err != nil { 
      tx.Rollback() // return an error too, we may want to wrap them 
      return err 
     } 
    } 

    return tx.Commit() 
} 

Ben tam bir örnek var here

+1

Mükemmel çalışır. Teşekkürler dostum. – 1N5818

+1

Gerçekten yararlı yazı, teşekkürler. Ama ne anlamadım ki, 'Bir işlemin bir Commit veya Rollback çağrısı ile bitmesi gerekir.', Tx.Prepare (bazı sql ..) 'nin neden olduğu bir hatayı döndürdüğünüzde, bir Commit veya Rollback yapmıyorsunuz . Neden? Söz konusu işlem bu senaryoda uygun şekilde kapatılmış mı? Temel Veritabanında herhangi bir değişiklik yapılmamasına rağmen, işlemi düzgün bir şekilde kapatmamız gerekmiyor mu? – BARJ

+0

Bu kod, Go1.4 veya önceki sürüm için doğru değil, tx.Commit(), stmt.Close() 'dan önce gerçekleşecek olan havuza ilişkilendirilen bağlantıyı serbest bırakacak, bu da alttaki eşzamanlı erişime neden olabilir bağlantı, bağlantı durumunu tutarsız hale getirir. Burada belirtildiği gibi: http://go-database-sql.org/prepared.html –

0

Herhangi bir önemli dezavantaj olmaksızın herhangi bir hata durumunda geri dönüş için olası bir çözüm buldum. Golang'a oldukça yeni geldim, yanılıyor olabilirim.

func CloseTransaction(tx *sql.Tx, commit *bool) { 
    if *commit { 
    log.Println("Commit sql transaction") 
    if err := tx.Commit(); err != nil { 
     log.Panic(err) 
    } 
    } else { 
    log.Println("Rollback sql transcation") 
    if err := tx.Rollback(); err != nil { 
     log.Panic(err) 
    } 
    } 
} 

func MultipleSqlQuriesWithTx(db *sql.DB, .. /* some parameter(s) */) (.. .. /* some named return parameter(s) */, err error) { 
    tx, err := db.Begin() 
    if err != nil { 
    return 
    } 
    commitTx := false 
    defer CloseTransaction(tx, &commitTx) 

    // First sql query 
    stmt, err := tx.Prepare(..) // some raw sql 
    if err != nil { 
    return 
    } 
    defer stmt.Close() 

    res, err := stmt.Exec(..) // some var args 
    if err != nil { 
    return 
    } 

    // Second sql query 
    stmt, err := tx.Prepare(..) // some raw sql 
    if err != nil { 
    return 
    } 
    defer stmt.Close() 

    res, err := stmt.Exec(..) // some var args 
    if err != nil { 
    return 
    } 

    /* 
    more tx sql statements and queries here 
    */ 

    // success, commit and return result 
    commitTx = true 
    return 
} 
İlgili konular