你有没有试过在执行函数中执行存储函数过后立刻执行其他sql语句?
今天开发的时候遇到一个数据库操作error 2014的问题,后面不断找文档、看connector源码才解决和明白之。分享一下让后面遇到这个问题的人少走弯路。首先看一下问题的源码,本文只贴出c (采用Connector c)
和c++(采用connector c++)源码,其他语言道理相通。
数据库存储过程code:
CREATE DEFINER = `root`@`localhost` PROCEDURE `sp_test`()
BEGIN
select 1 as name;
END;
c code:
#include
#include "mysql.h"
int main(){
const char *host = "127.0.0.1";
const char *user = "uername";
const char *pass = "123456";
const char *db = "dbname";
/* 定义mysql变量 */
MYSQL mysql;
MYSQL_RES *rs;
MYSQL_ROW row;
if (mysql_init(&mysql) == 0) return -1;
/* 连接数据库 */
if (!mysql_real_connect(&mysql, host, user, pass, db,0 , NULL, 0))
{
return -1;
}
if (mysql_query(&mysql, "call sp_test()") == 0 &&
mysql_field_count(&mysql) > 0 )
{
rs = mysql_store_result(&mysql);
mysql_free_result(rs);
}
else
{
printf("操作1失败\n");
}
if (mysql_query(&mysql, "select 1 as name") == 0 && //这里会操作失败
mysql_field_count(&mysql) > 0 )
{
rs = mysql_store_result(&mysql);
mysql_free_result(rs);
}
else
{
printf("操作2失败\n");
}
mysql_close(&mysql);
return 0;
}
c++ code:
#include "mysql_connection.h"
#include "mysql_driver.h"
#include "cppconn/driver.h"
#include "cppconn/statement.h"
#include "cppconn/resultset.h"
#include "cppconn/exception.h"
using namespace sql;
#define DBHOST "tcp://127.0.0.1:3306"
#define USER "root"
#define PASSWORD "123456"
int main() {
Driver *driver;
Connection *con;
Statement *stmt;
ResultSet *res;
Connection *conn;
bool bResult;
driver = get_driver_instance();
conn = driver->connect(DBHOST, USER, PASSWORD);
stmt = conn->createStatement();
try
{
stmt->execute("use db_name; ");
if (stmt->execute("call sp_test(); "))
{
res = stmt->getResultSet();
if(res != NULL)
{
delete res;
}
}
stmt->execute("select 3 as address;") //注意,这里会抛出异常2014 Commands out of sync
{
res = stmt->getResultSet();
if(res != NULL)
{
delete res;
}
}
}
catch (SQLException& e)
{
//会捕获到异常
}
delete conn;
delete res;
delete stmt;
driver = NULL;
conn = NULL;
return 0;
}
CR_COMMANDS_OUT_OF_SYNC : Commands were executed in an improper order.
命令以不合理的顺序执行,意味着前面还有未执行的命令?
继续查阅文档,发现这里有说明其实平时一般的执行语句无论执行多少次都没问题,为什么执行带select的存储过程就会出问题?
http://dev.mysql.com/doc/refman/5.0/en/mysql-next-result.html
摘要 : If your program uses CALL statements to execute stored procedures,Because CALL can return multiple results, process them using a loop that calls mysql_next_result()
to determine whether there are more results.
就是说call执行存储过程后除了存储过程内的select会返回结果集外,另外还会返回一个
结果集用于标识存储过程执行的结果状态。刚才的"call sp_test"其实会返回两个 if (mysql_query(&mysql, "call sp_test()") == 0)
{
do
{
if (mysql_field_count(&mysql) > 0)
{
rs = mysql_store_result(&mysql);
mysql_free_result(rs);
}
}
while (mysql_next_result(&mysql) == 0);
}
if (stmt->execute("call sp_test(); "))
{
do
{
res = stmt->getResultSet();
if(res != NULL)
{
delete res;
res = NULL;
}
}
while (stmt->getMoreResults());
}
第一次循环 mysql_next_result会返回0 (说明有结果集,状态结果集),但是 stmt->getMoreResults() 却返回false(没有更多结果集?) ,那 c和c++不就是自相矛盾啦? 贴上Connector c++源码:
bool
MySQL_Statement::getMoreResults()
{
CPP_ENTER("MySQL_Statement::getMaxRows");
CPP_INFO_FMT("this=%p", this);
checkClosed();
last_update_count = UL64(~0);
if (proxy->more_results()) {
int next_result = proxy->next_result();
if (next_result > 0) {
//....
} else if (next_result == 0) {
return proxy->field_count() != 0; //这里是重点
} else if (next_result == -1) {
/.....
}
}
return false;
};
原来connnecotr c++的getMoreResults也是执行mysql_next_result(),只不过会自动过滤掉没有列的结果集,所以刚才上面对于存储过程返回的第二个结果集就返回false了。这里我也冒出了几个问题:
1、不带select 的 存储过程执行是否也需要mysql_next_result3、mysql_next_result 执行需要的条件?
与其不断乱猜,不如多看看源码,我将这几个函数实现的源码看了 一遍,整理出相关的流程图:
我们通过流程图可以看出,三个主要的api方法都严重依赖mysql->status, 和mysql->server_status去确定是否可以执行,这两个变量也为mysql的命令按顺序执行,按顺序获取结果集提供了保证。
表格中可以清晰地看出在执行后各种返回状态的基础上各个函数的执行情况,现在回答刚才的几个问题:
2、mysql_store_result 是否一定需要??
3、mysql_next_result 执行需要的条件?
--------------------------------------华丽的分割线-------------------------------------------------
告诉我们问题无处不在,平时要细心发现。
转载请标示文章出处:http://blog.csdn.net/luoti784600/article/details/21532279