在我正在处理的XMLRPC服务器中(基于xmlrpc-c),线程可能希望使用以下函数建立MySQL连接以检索某些数据:
Distribution getEntitySetFromMysql( int id ) {
Distribution result;
try {
sql::Driver *driver = get_driver_instance();
sql::Connection *con = driver->connect( (std::string)DBHOST, (std::string)USER, (std::string)PASSWORD);
con->setSchema( (std::string)DATABASE );
sql::Statement *stmt = con->createStatement();
std::stringstream query;
query << "SELECT concept_id, weight FROM entity_set_lines WHERE entity_set_id = " << id;
sql::ResultSet *res = stmt->executeQuery ( query.str() );
while (res->next()) {
result[ res->getInt("concept_id") ] = res->getDouble("weight");
}
delete res;
delete stmt;
con->close();
delete con;
} catch (sql::SQLException &e) {
std::cout << "ERROR: SQLException in " << __FILE__;
std::cout << " (" << __func__<< ") on line " << __LINE__ << std::endl;
std::cout << "ERROR: " << e.what();
std::cout << " (MySQL error code: " << e.getErrorCode();
std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;
if (e.getErrorCode() == 1047) {
std::cout << "\nYour server does not seem to support Prepared Statements at all. ";
std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
}
} catch (std::runtime_error &e) {
std::cout << "ERROR: runtime_error in " << __FILE__;
std::cout << " (" << __func__ << ") on line " << __LINE__ << std::endl;
std::cout << "ERROR: " << e.what() << std::endl;
}
return result;
}
一切正常,但在一个线程运行此代码并成功返回其结果后,该线程仍然挂起并且不会退出。这种方法有什么问题?这有多基本错误? MySQL连接器线程安全吗?
答案 0 :(得分:4)
在谷歌搜索解决方案时,我遇到了sql::Driver::threadInit()
和sql::Driver::threadEnd()
的提及。但是,正如我在C ++连接器的1.0.5版本上所做的那样,我无法使用这些功能。在获取驱动程序实例后添加driver->threadInit();
并在函数结束时添加driver->threadEnd();
,此问题已得到解决。
以下是MySQL's 1.1.0 change history中的这个线程init和end功能的提及:
添加了Driver :: threadInit()和Driver :: threadEnd()方法。一切 线程客户端的线程必须调用Driver :: threadInit() 在使用Connector / C ++执行任何其他操作之前启动该线程 并且每个线程在完成时必须调用Driver :: threadEnd()。您 可以找到一个示例来演示examples / pthreads.cpp中的用法。它 强烈建议不要在线程之间共享连接。它是 理论上可行,如果你设置某些(未记录的)互斥锁,但是 它根本不受支持。每个线程使用一个连接。没有 两个线程同时使用相同的连接。请检查 关于MySQL手册中的线程的C API说明。 Connector / C ++包装 C API。 (劳伦,安德烈,乌尔夫)
TL; DR:如果您遇到此问题,请确保您的C ++ MySQL Connector版本是&gt; = 1.1.0并使用sql::Driver::threadInit()
和sql::Driver::threadEnd()
方法围绕您的连接代码。
答案 1 :(得分:0)
两个想法:
由于您没有显示任何主叫或周围代码,因此很难说出实际发生了什么。你应该完成后检查线程的退出代码吗?你可以在调试器中附加它以查看它正在做什么而不是关闭吗?
答案 2 :(得分:0)
实际上:
请勿使用:sql::Driver::threadInit()
或sql::Driver::threadEnd()
因为:您已经在使用try()
你忘了:
res->close();
stmt->close();
con->close();
delete res;
delete stmt;
delete con;
示例:
int connection_and_query_func()
{
/*connection and query variables*/
sql::Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
int err_exception_getErrorCode=0;
/*results variables*/
int my_int_from_column_1 = 0;
double my_double_from_column_2 = 0;
....
std:string my_string_from_column_p = "";
try
{
/* Create a connection */
driver = get_driver_instance();
con = driver->connect("address_name", "user_name", "password");
/* Connect to the MySQL database */
con->setSchema("schema_name");
/* Execute MySQL Query*/
stmt = con->createStatement();
res = stmt->executeQuery("your query statement here");
/* Read MySQL Query results per column*/
my_int_from_column_1 = res->getInt(1);
my_double_from_column_2 = res->getDouble(2);
....
my_string_from_column_p = res->getString(p);
/* Close MySQL Connection*/
res->close();
stmt->close();
con->close();
delete res;
delete stmt;
delete con;
};
/* Get last error*/
catch (sql::SQLException &exception)
{
err_exception_getErrorCode = exception.getErrorCode();
};
return(0);
};
结论:这可以根据需要执行多次。函数示例(connection_and_query_func())将在完成后正确关闭MySQL连接 - 无需向MySQL服务器添加进程!!!
FURTHERMORE:阅读官方手册https://docs.oracle.com/cd/E17952_01/connector-cpp-en/connector-cpp-en.pdf
替代方法:如果您无法正确关闭程序/功能端的连接和查询(从而将进程添加到MySQL服务器),请考虑以下两个选项:
1 /将所有MySQL超时参数设置为10秒。或更少(例如); 2 /编写SHOW PROCESSLIST的脚本并删除SLEEP中的进程太长时间。
干杯。