2015-02-16 10 views
5

Tôi đang cố gắng tìm trình điều khiển MySql mà tôi có thể sử dụng với Go hỗ trợ phát hành nhiều câu lệnh SQL trong một cuộc gọi. Ví dụ tôi có thể muốn tạo một cơ sở dữ liệu bằng cách sử dụng SQL sau:Trình điều khiển Go Mysql có tồn tại hỗ trợ nhiều câu lệnh trong một chuỗi không?

DROP SCHEMA IF EXISTS foo; 
CREATE SCHEMA IF NOT EXISTS foo; 

Trong các ngôn ngữ như PHP bạn chỉ có thể đặt cả hai câu lệnh SQL trong một chuỗi và thực hiện nó trong một đi, như thế này:

$db = new PDO(...); 
$db->query("DROP SCHEMA IF EXISTS foo; CREATE SCHEMA IF NOT EXISTS foo;"); 

Lý do tôi cần điều này là vì tôi có các bãi chứa SQL (từ mysqldump) tôi muốn áp dụng lập trình cho các cơ sở dữ liệu khác nhau.

Tôi đang tìm các chức năng tương tự trong Go nhưng có vẻ như tất cả các trình điều khiển khác nhau không hỗ trợ nó, mà, thẳng thắn, gây sốc cho tôi.

Go-MySQL-Driver
https://github.com/go-sql-driver/mysql
này có vẻ là người lái xe sử dụng nhiều nhất cho Go.

package main 

import "database/sql" 
import "log" 
import _ "github.com/go-sql-driver/mysql" 

func main() { 

    db, err := sql.Open("mysql", "user:[email protected](127.0.0.1:3306)/") 
    if err != nil { 
     log.Println(err) 
    } 

    sql := "DROP SCHEMA IF EXISTS foo; CREATE SCHEMA IF NOT EXISTS foo;" 
    _, err = db.Exec(sql) 
    if err != nil { 
     log.Println(err) 
    } 

    db.Close() 
} 

đầu ra:

2015/02/16 18:58:08 Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE SCHEMA IF NOT EXISTS foo' at line 1 

MyMySQL
https://github.com/ziutek/mymysql
Đây là một tài xế phổ biến.

package main 

import "database/sql" 
import "log" 
import _ "github.com/ziutek/mymysql/godrv" 

func main() { 

    db, err := sql.Open("mymysql", "database/user/password") 
    if err != nil { 
     log.Println(err) 
    } 

    sql := "DROP SCHEMA IF EXISTS foo; CREATE SCHEMA IF NOT EXISTS foo;" 
    _, err = db.Exec(sql) 
    if err != nil { 
     log.Println(err) 
    } 

    sql = "USE DATABASE foo;" 
    _, err = db.Exec(sql) // <-- error 
    if err != nil { 
     log.Println(err) 
    } 

    db.Close() 
} 

đầu ra:

2015/02/16 18:58:08 packet sequence error 

Có ai biết về bất kỳ trình điều khiển tương thích với MySql Go có thể xử lý nhiều lệnh trong một chuỗi như thế này?

+1

Đi Trình điều khiển MySQL hiện có hỗ trợ đa câu lệnh: https://github.com/go-sql-driver/mysql/pull/411 –

Trả lời

0

https://github.com/ziutek/mymysql

Có thể làm điều đó. Mặc dù bạn phải sử dụng giao diện của nó so với giao diện được xác định. Giao diện chính thức đi không xử lý hoặc nhiều giá trị trả về.

package main 

import (
    "flag" 
    "fmt" 

    "github.com/ziutek/mymysql/autorc" 
    "github.com/ziutek/mymysql/mysql" 
    _ "github.com/ziutek/mymysql/thrsafe" 
) 

type ScanFun func(int, []mysql.Row, mysql.Result) error 

func RunSQL(hostport, user, pass, db, cmd string, scan ScanFun) error { 
    conn := autorc.New("tcp", "", hostport, user, pass, db) 

    err := conn.Reconnect() 
    if err != nil { 
     return err 
    } 

    res, err := conn.Raw.Start(cmd) 
    if err != nil { 
     return err 
    } 

    rows, err := res.GetRows() 
    if err != nil { 
     return err 
    } 

    RScount := 0 
    scanErr := error(nil) 

    for { 
     if scanErr == nil { 
      func() { 
       defer func() { 
        if x := recover(); x != nil { 
         scanErr = fmt.Errorf("%v", x) 
        } 
       }() 
       scanErr = scan(RScount, rows, res) 
      }() 
     } 

     if res.MoreResults() { 
      res, err = res.NextResult() 
      if err != nil { 
       return err 
      } 
      rows, err = res.GetRows() 
      if err != nil { 
       return err 
      } 
     } else { 
      break 
     } 

     RScount++ 
    } 
    return scanErr 
} 

func main() { 
    host := flag.String("host", "localhost:3306", "define the host where the db is") 
    user := flag.String("user", "root", "define the user to connect as") 
    pass := flag.String("pass", "", "define the pass to use") 
    db := flag.String("db", "information_schema", "what db to default to") 

    sql := flag.String("sql", "select count(*) from columns; select * from columns limit 1;", "Query to run") 

    flag.Parse() 

    scan := func(rcount int, rows []mysql.Row, res mysql.Result) error { 
     if res.StatusOnly() { 
      return nil 
     } 

     for idx, row := range rows { 
      fmt.Print(rcount, "-", idx, ") ") 
      for i, _ := range row { 
       fmt.Print(row.Str(i)) 
       fmt.Print(" ") 
      } 
      fmt.Println("") 
     } 
     return nil 
    } 

    fmt.Println("Host - ", *host) 
    fmt.Println("Db - ", *db) 
    fmt.Println("User - ", *user) 

    if err := RunSQL(*host, *user, *pass, *db, *sql, scan); err != nil { 
     fmt.Println(err) 
    } 
} 
+0

Điều này thực sự dường như hoạt động! Cảm ơn. –

-3

Đặt thẳng, làm không phát hành nhiều câu lệnh trong một cuộc gọi. Đó là một vấn đề an ninh. Nếu một hacker có thể nhận được một chút, anh ta có thể tiếp quản máy của bạn. (Đọc về "SQL Injection".)

Các thói quen đã lưu trữ cung cấp cho bạn một cách an toàn để kết hợp các câu lệnh (với một số hạn chế).

+3

Đây không phải là vấn đề bảo mật và rõ ràng là bạn chưa đọc câu hỏi. Tôi không phải đối phó với các truy vấn parametrized, tôi đang cố gắng áp dụng DDLs nội bộ crafted để lược đồ hiện có. SQL Injection thậm chí không phải là một mối quan tâm ở đây. –

+0

có thể xuất hiện câu trả lời không liên quan nhưng xem xét các trình điều khiển sẽ hỗ trợ nhiều câu lệnh nếu multiStatements = true được thêm vào các tham số kết nối và các tài liệu nói 'Cho phép nhiều câu lệnh trong một truy vấn. Trong khi điều này cho phép truy vấn hàng loạt, nó cũng làm tăng đáng kể nguy cơ tiêm SQL. Chỉ kết quả của truy vấn đầu tiên được trả về, tất cả các kết quả khác đều bị loại bỏ âm thầm.' đó là một nhận xét có liên quan mặc dù có lẽ không được viết đúng. – ithkuil

1

Tôi khuyên bạn chỉ cần thực hiện 2 cuộc gọi. Tại sao không? Nó làm cho các mã dễ dàng hơn để grok và cải thiện xử lý lỗi.

Tùy chọn khác, nếu bạn có một tệp SQL lớn từ kết xuất là loại bỏ và thực hiện toàn bộ điều trong một lần.

+1

Thực hiện nhiều cuộc gọi không phải là một lựa chọn thực tế bởi vì tôi sẽ cần phải phân tích cú pháp SQL dump để chia nhỏ các câu lệnh. Sử dụng trình bao sẽ có thể nhưng sau đó chương trình không phải là nền tảng chéo. –

10

có thể định cấu hình github.com/go-sql-driver/mysql để chấp nhận nhiều câu lệnh với thông số kết nối multiStatements=true.

Tài liệu nêu rõ lý do tại sao bạn nên cẩn thận thực hiện. Xem https://github.com/go-sql-driver/mysql

+0

Bạn có biết mã ví dụ nào về cú pháp sử dụng câu lệnh đa không? – Sir

0

Thêm ví dụ cho câu trả lời từ @ithkuil liên quan đến multiStatements cho gói go-sql-driver để tham khảo. (Tôi không có đủ đại diện để thêm làm nhận xét).

Tham số cho multiStatements được thêm vào chuỗi dataSourceName cho lệnh gọi sql.Open của bạn. ví dụ.

db, err := sql.Open("mysql", "user:[email protected](localhost:3306)/dbname?multiStatements=true") 

Bạn không nên sử dụng trình xử lý db này để xử lý dữ liệu người dùng, nhưng nó hoạt động tốt để xử lý các tệp sql đã biết.

Các vấn đề liên quan