2 回答
TA貢獻1843條經驗 獲得超7個贊
除了@mkopriva 在關于客戶端的評論中所說的內容之外,使用準備好的語句還有服務器端的影響。
重要的是要注意 using*sql.DB使用連接池:
DB 是代表零個或多個底層連接池的數據庫句柄
為什么這很重要?那么并發訪問可能會觸發多個物理連接。并且當使用準備好的語句時——它們應該被重用——只有在同一個數據庫會話(即連接)上使用時才有效。
連接池(使用*sql.DB)本質上不能保證這一點。因此,如果有 100 個并發查詢 - 理論上可能會生成 100 個并發數據庫連接 -不是一個 - 但在服務器端最多有 100 個準備好的語句。
您可以通過sql.DB.Conn()獲得與數據庫的單個連接,其中:
在同一個 Conn 上運行的查詢將在同一個數據庫會話中運行。
這意味著任何先前生成的準備好的語句都將獲得重用的好處(因為它們使用相同的“會話”)。
總之,權衡準備好的語句對客戶端和服務器影響的好處,以及您是否真的通過并發使用獲得了這些好處。
TA貢獻1869條經驗 獲得超4個贊
我花了更多時間進行測試和分析,所以這是我的發現 - 也證實了@mkopriva 的評論。
如果使用SELECT語句,無論是否使用查詢占位符,您都應該更喜歡使用DB.Query和/或DB.QueryRow而不是DB.Prepare&STMT.Exec組合。DB.Query當我檢查 MySQL 查詢日志時,它看起來就像DB.QueryRow 它們用于DB.Exec沒有參數占位符的查詢一樣。這意味著只有一個( Query) 網絡往返而不是三個( Prepare,Execute和Close)!
那么為什么不直接使用DB.Exec呢?因為它用于不返回結果集的查詢。順便說一句,DB.Exec它直接釋放它的連接回池,但DB.Query它的連接保持在池之外,直到rows.Close()被調用。如果您忘記調用它,這可能會導致連接“泄漏”和連接不可用。因此,從技術上講,DB.Query如果您沒有正確地做事,就會有其自身的風險。
最后要注意的是,如果您的INSERT,UPDATE和DELETEquery 參數沒有 SQL 注入,那么請使用DB.Execelse 來DB.Prepare代替。對于手動準備查詢參數,您可以使用fmt.Sprintf()函數。
- 2 回答
- 0 關注
- 473 瀏覽
添加回答
舉報
