MySQL-python: Commands out of sync
MAR 13TH, 2012
在給 MySQL 資料庫訪問層增加新功能時遇到了這樣的錯誤:
1 |
ProgrammingError: (2014, "Commands out of sync; you can't run this command now") |
之前零星地見到過幾次,因為發生頻度很低,就沒有太在意,這次找了一下原因,MySQL 文檔對 Commands out of sync 錯誤的描述是這樣的:
If you get Commands out of sync; you can’t run this command now in your client code, you are calling client functions in the wrong order.
This can happen, for example, if you are using mysql_use_result() and try to execute a new query before you have called mysql_free_result(). It can also happen if you try to execute two queries that return data without calling mysql_use_result() or mysql_store_result() in between. Commands out of sync dev.mysql.com/doc/refman/5.1/en/…
MySQL 和用戶端通訊使用的是“半雙工”的應答協議,用戶端每發送一個查詢,伺服器“強行推送”結果給用戶端,用戶端需要執行 mysql_use_result() 或 mysql_store_result() 從伺服器端取回結果,這是一次完整的查詢互動,只提交查詢而不取回結果就會導致 Commands out of sync。
由於使用的是 MySQL-python,所以第一種情況所說的沒有調用 mysql_free_result() 的問題不大可能存在,並且 MySQLdb 的預設 cursor 使用的是 mysql_store_result() 而不是 mysql_use_result(),所以應該是第二種情況。
抓取了一些有可能會導致這個問題的查詢,發現了類似這樣的語句:
1 |
SELECT a, b FROM t LIMIT 1; -- some comments |
執行了這樣的查詢之後,再執行任何查詢都會遇到 Commands out of sync 問題。
因為這其實是由分號隔開的兩個獨立的查詢語句,使用 MySQLdb 執行時,作為一個語句發送給 MySQL server,之後 MySQLdb 執行了一次 mysql_store_result()。
之前需要自動地給每一個查詢增加註釋,而個別的查詢在末尾寫了分號,追加註釋之後就觸發了這個問題,那麼只需要在加註釋前 strip 掉分號就好了。
MySQLdb 有四種 cursor:
1234567891011121314151617181920212223242526 |
class Cursor(CursorStoreResultMixIn, CursorTupleRowsMixIn, BaseCursor): """This is the standard Cursor class that returns rows as tuples and stores the result set in the client.""" class DictCursor(CursorStoreResultMixIn, CursorDictRowsMixIn, BaseCursor): """This is a Cursor class that returns rows as dictionaries and stores the result set in the client.""" class SSCursor(CursorUseResultMixIn, CursorTupleRowsMixIn, BaseCursor): """This is a Cursor class that returns rows as tuples and stores the result set in the server.""" class SSDictCursor(CursorUseResultMixIn, CursorDictRowsMixIn, BaseCursor): """This is a Cursor class that returns rows as dictionaries and stores the result set in the server.""" |
預設使用的是 Cursor,在提交查詢之後執行 mysql_store_result(),將 MySQL Server 返回的所有資料都取回並緩衝在本地,SSCursor 則是使用 mysql_use_result(),將結果“緩衝”在伺服器端,用戶端逐行取回結果,好處是速度會比 mysql_store_result() 快,並且用戶端可以節省記憶體,但在高並發環境下,還是使用預設的