存儲過程中就只有一句普通的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------
你的版本很新啊,呵呵。我來不及更新版本。
前邊的free_result是調用慣用法。意即在close之前,進行free,釋放掉不必要的cursor之類的東東。後邊的while是必須的。
一個連接當然不能多線程共享了。
可以每線程一個單獨的連接進行處理。多線程共享連接,那麼中間產生的許多資源就成了共享資源了,需要進行鎖定,處理極爲不便。
------Solutions------
這種做法解決了問題,不過或許可以算是預處理函數的一種bug,按常理mysql_stmt_close()或者mysql_stmt_free_result()應該會自動釋放掉產生的資源,只是沒想到還要使用非預處理函數來處理相關的資源。
至於多個線程用同一個連接,手冊上也介紹了相關介紹,可以使用,不過要自行加鎖處理。複雜度也就更高了。
------Solutions------
確實如此。
------Solutions------
問題解決了,可以結帖了。