mysql 出現 Commands out of sync; you can't run this command now

存儲過程中就只有一句普通的select * from ...;
第一次調用成功,
然後mysql_stmt_close()..
再調一次,結果mysql_stmt_prepare()這一句,就出現CR_COMMANDS_OUT_OF_SYNC錯誤。
鬱悶啊。。。 
------Solutions------
你的代碼是什麼? 
------Solutions------
void test() 
{     
//...
       int t1,t2;

       MYSQL_STMT *hStmt = mysql_stmt_init(m_hSql);
char sql[] = "call test(?)";
if ( mysql_stmt_prepare( hStmt,sql,static_cast<unsigned long>(strlen(sql))) != 0 )
    printf(mysql_stmt_error(hStmt);

ibind.buffer_type = MYSQL_TYPE_LONG;
ibind.buffer = t1;

if ( mysql_stmt_bind_param(hStmt,&ibind) != 0 )
     printf(mysql_stmt_error(hStmt));

if ( mysql_stmt_execute(hStmt) != 0 )
         printf(mysql_stmt_error(hStmt));

obind.buffer_type= MYSQL_TYPE_LONG;
obind.buffer= (char *)&t2;

       if (mysql_stmt_bind_result(hStmt, &obind) !=0 )
printf(mysql_stmt_error(hStmt));

if (mysql_stmt_store_result(hStmt) !=0 )
printf(mysql_stmt_error(hStmt)); 

        rows = mysql_stmt_num_rows(hStmt);
for( my_ulonglong i=0; i<rows; ++i )
{
     nRet = mysql_stmt_fetch(hStmt);
             //...
         }
        mysql_stmt_close(hStmt);
}

//存儲過程
CREATE DEFINER=`root`@`localhost` PROCEDURE test( in t1 int)
BEGIN
   select t2 from test from id=t1;
END

如果test()連着調兩次,就會報錯




------Solutions------
if ( mysql_stmt_execute(hStmt) != 0 )
  printf(mysql_stmt_error(hStmt));
 
在正確執行後,要釋放這個預處理。

DEALLOCATE PREPARE hStmt;

------Solutions------
直接調用sql code釋放?
hStmt是在c中的句柄呀,有對應的c api函數嗎? 
------Solutions------
mysql_stmt_close已經足夠了。
問題不在這兒,而是中間的調用順序出了問題:
應該是:
1. stmt_bind_param
2. stmt_execute
3. stmt_store_result
4. stmt_bind_result
5. stmt_close

你先按這個順序處理一遍試試吧。

------Solutions------
順序是對的,第二次再調用這個函數的時候,mysql_stmt_prepare這裏就出錯了。
如果不是調用存儲過程"call test(?)"的話,直接調用用"select t2 from test from id=?"命令的話,沒有發現問題。 
------Solutions------
你的mysql版本是多少?我可以拿到本地來試一下。

從錯誤來看,是由於函數調用順序不當造成的。 
------Solutions------
我在本地試了一下,使用的是版本:mysql-5.1.26-rc-win32。
你的代碼有一個地方確實有問題。
這可能也需要我們總結一下。
1. 使用存儲過程call test(?)返回結果集,需要創建CLIENT_MULTI_STATEMENTS的客戶端連接
2. 在兩次調用call test(?),要釋放中間產生的若干結果集。

具體做法如下:
在mysql_stmt_close之前,最好調用一次:mysql_stmt_free_result(hStmt);
在mysql_stmt_close()調用完以後,立即使用如下循環釋放其它我們不需要的MYSQL_RESULT:
    do
    {
        MYSQL_RES* res = mysql_store_result(mysql_);
          mysql_free_result(res);
    }
    while ( (0 == mysql_next_result(mysql_)) );

如果沒有這一段釋放,連續調用,則會出現樓主所說的錯誤。

總之,調用存儲過程產生結果集跟調用select查詢產生結果集,還是有一些不一樣。
前者可能產生多個結果集。



------Solutions------
很感謝iihero,我使用的是5.5.3版。
使用mysql_stmt_free_result(hStmt);沒有什麼作用。
不過:
do
  {
  MYSQL_RES* res = mysql_store_result(mysql_);
  mysql_free_result(res);
  }
  while ( (0 == mysql_next_result(mysql_)) );

確實能解決問題,呵呵!
留下個疑問,這樣一個連接就無法讓多線程共享數據了,因爲無法確定多線程是否安全。 
------Solutions------
引用 9 樓 ldhhp2003 的回覆:
很感謝iihero,我使用的是5.5.3版。
使用mysql_stmt_free_result(hStmt);沒有什麼作用。
不過:
do
  {
  MYSQL_RES* res = mysql_store_result(mysql_);
  mysql_free_result(res);
  }
  while ( (0 == mysql_next_result(mysql_)) );

確實能解決問題,呵呵!
留下個疑問,這樣一個連接就無法讓多線程共享數據了,因爲無法確定多線程是否安全。


你的版本很新啊,呵呵。我來不及更新版本。
前邊的free_result是調用慣用法。意即在close之前,進行free,釋放掉不必要的cursor之類的東東。後邊的while是必須的。
一個連接當然不能多線程共享了。
可以每線程一個單獨的連接進行處理。多線程共享連接,那麼中間產生的許多資源就成了共享資源了,需要進行鎖定,處理極爲不便。



------Solutions------
這種做法解決了問題,不過或許可以算是預處理函數的一種bug,按常理mysql_stmt_close()或者mysql_stmt_free_result()應該會自動釋放掉產生的資源,只是沒想到還要使用非預處理函數來處理相關的資源。
至於多個線程用同一個連接,手冊上也介紹了相關介紹,可以使用,不過要自行加鎖處理。複雜度也就更高了。

------Solutions------
引用 11 樓 ldhhp2003 的回覆:
至於多個線程用同一個連接,手冊上也介紹了相關介紹,可以使用,不過要自行加鎖處理。複雜度也就更高了。


確實如此。 
------Solutions------
問題解決了,可以結帖了。
發佈了67 篇原創文章 · 獲贊 19 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章