亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用 SET 變量進行 MySQL 查詢

使用 SET 變量進行 MySQL 查詢

Go
MMMHUHU 2023-02-06 19:03:16
我試圖通過設置一些變量來清理 Go 調用 MySQL 查詢的方式,然后再使用圍繞單個值的大量 case 語句運行查詢。我嘗試運行的查詢在控制臺上運行良好,但在SELECT通過 Go 運行它時因語法問題而失敗。這樣的事情可能嗎?func (d *DB) SelectByUserId(uid string, srt string, pg, lim int) ([]Inventory, error) {    query := `    SET @user_id := ?,        @orderBy := ?;    SELECT        *    FROM        inventory    WHERE        user_id = @user_id    ORDER BY        (CASE WHEN @orderBy = 'type,asc' THEN type END),        (CASE WHEN @orderBy = 'type,desc' THEN type END) DESC,        (CASE WHEN @orderBy = 'visible,asc' THEN visible END),        (CASE WHEN @orderBy = 'visible,desc' THEN visible END) DESC,        (CASE WHEN @orderBy = 'create_date,asc' THEN create_date END),        (CASE WHEN @orderBy = 'create_date,desc' THEN create_date END) DESC,        (CASE WHEN @orderBy = 'update_date,asc' THEN update_date END),        (CASE WHEN @orderBy = 'update_date,desc' THEN update_date END) DESC    LIMIT ?,?;    `        rows, err := d.Query(        query,        uid,        srt,        pg*lim,        lim,    )    if err != nil {        return nil, err    }    defer rows.Close()    result := make([]Inventory, 0)    for rows.Next() {        var inv Inventory        if err := rows.Scan(            &inv.Id,            &inv.UserId,            &inv.Type,            &inv.Name,            &inv.Description,            &inv.Visible,            &inv.CreateDate,            &inv.UpdateDate); err != nil {            return result, err        }        result = append(result, inv)    }    if err = rows.Err(); err != nil {        return result, err    }    return result, nil}現在,如果我取出 SET 部分并將所有@變量替換為?,然后srt像下面這樣多次傳遞變量,這一切都有效。但真的不想有查詢調用,例如:rows, err := d.Query(        query,        uid,        srt,        srt,        srt,        srt,        srt,        srt,        srt,        srt,        pg*lim,        lim)
查看完整描述

3 回答

?
PIPIONE

TA貢獻1829條經驗 獲得超9個贊

對于那些感興趣的人,我已經通過一些更新解決了我的問題。

  1. 連接時在DSN上有設置?...&multiStatements=true&interpolateParams=true

  2. 添加以上內容后,我開始收到有關排序規則的新錯誤 ( Illegal mix of collations (utf8mb4_0900_ai_ci,IMPLICIT) and (utf8mb4_general_ci,IMPLICIT) for operation '='。我檢查并轉換了數據庫和表utf8mb4_general_ci,一切都按預期工作。

感謝那些提供解決方案的人,但這是我們最終選擇的路線。


查看完整回答
反對 回復 2023-02-06
?
慕絲7291255

TA貢獻1859條經驗 獲得超6個贊

與大多數查詢接口一樣,該Query()函數一次只能執行一個 SQL 語句。MySQL 的準備語句不適用于多查詢。


SET您可以通過在一次調用中執行語句,然后在第二次調用中執行語句來解決此問題SELECT。但是您必須注意確保它們在同一個數據庫連接上執行,否則連接池很可能在不同的連接上運行它們。所以你需要做類似的事情:


conn, err := d.Conn(context.TODO())


conn.QueryContext(context.TODO(), "SET ...")

conn.QueryContext(context.TODO(), "SELECT ...")

或者,更改準備 ORDER BY 的方式,這樣就不需要用戶定義的變量。


我這樣做的方法是在 Go 代碼中而不是在 SQL 中構建 ORDER BY 語句,使用字符串映射來確保使用有效的列和方向。如果輸入不在地圖中,則將默認順序設置為主鍵。


validOrders := map[string]string{

    "type,asc":         "type ASC",

    "type,desc":        "type DESC",

    "visible,asc":      "visible ASC",

    "visible,desc":     "visible DESC",

    "create_date,asc":  "create_date ASC",

    "create_date,desc": "create_date DESC",

    "update_date,asc":  "update_date ASC",

    "update_date,desc": "update_date DESC",

}

orderBy, ok := validOrders[srt]

if !ok {

    orderBy = "id ASC"

}

query := fmt.Sprintf(`

    SELECT ...

    WHERE user_id = ?

    ORDER BY %s

    LIMIT ?, ?

`, orderBy)

這對于 SQL 注入是安全的,因為函數輸入不會插入到查詢中。它是從我的地圖中插入到查詢中的值,并且該值在我的控制之下。如果有人試圖輸入一些惡意值,它不會匹配我地圖中的任何鍵,所以它只會使用默認排序順序。


查看完整回答
反對 回復 2023-02-06
?
德瑪西亞99

TA貢獻1770條經驗 獲得超3個贊

除非驅動程序實現特殊接口,否則查詢在執行前首先在服務器上準備好。因此 Bindvars 是特定于數據庫的:

  • MySQL:使用?上面顯示的變體

  • PostgreSQL:使用枚舉的 $1、$2 等 bindvar 語法

  • SQLite:接受兩者?和 $1 語法

  • Oracle:使用 :name 語法

  • MsSQL:@(隨你用)

我想這就是為什么你不能用 query() 做你想做的事。


查看完整回答
反對 回復 2023-02-06
  • 3 回答
  • 0 關注
  • 327 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號