📄 mysqlconnection.cpp
字号:
/* * MysqlConnection object defines the needed connection functions for the dbConnect MySQL driver * Copyright (C) 2002 Johnathan Ingram, jingram@rogueware.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 US * */#include "mysqlConnection.h"#include "mysqlBindParam.h"#include "mysqlQuery.h"// -----------------------------------------------------------------------------// PRIVATE:// -----------------------------------------------------------------------------// -----------------------------------------------------------------------------// MysqlConnection::_mysqlConnect// -----------------------------------------------------------------------------void MysqlConnection::_mysqlConnect( int index){
// Make sure the handle is valid and we are not already connected. if (index > _numHandles || index < 0) throw Error("_mysqlConnect(): Invalid index to database handle."); if (_handles[index]->status != BaseHandle::DISCONNECTED) throw AlreadyConnected("_mysqlConnect(): " "The database connection is already connected to the database."); // Connect to the MySQL database. mysql_init(&_handles[index]->__mysql__); // Enable Mysql compression for the connection if specified. if (_mysqlOptions.mysqlOptCompress) { mysql_options(&_handles[index]->__mysql__, MYSQL_OPT_COMPRESS, 0); } // Connect to the mysql database. if (!mysql_real_connect(&_handles[index]->__mysql__, host.c_str(), username.c_str(), password.c_str(), databaseName.c_str(), 0, NULL, 0)) { string err = "_mysqlConnect(): "; err += mysql_error(&_handles[index]->__mysql__); throw ErrorConnecting(err); } _handles[index]->status = BaseHandle::CONNECTED; _handles[index]->lastUsed = time(NULL);} // MysqlConnection::_mysqlConnect// -----------------------------------------------------------------------------// MysqlConnection::_mysqlDisconnect// -----------------------------------------------------------------------------void MysqlConnection::_mysqlDisconnect( int index){ // Make sure the handle is valid and we are not already connected. if (index > _numHandles || index < 0) throw Error("_mysqlDisconnect(): Invalid index to database handle."); if (_handles[index]->status == BaseHandle::DISCONNECTED || _handles[index]->status == BaseHandle::UNKNOWN) throw NotConnected("_mysqlDisconnect(): " "The database handle does not have a valid connection to the database."); // Disconnect from the server. mysql_close(&_handles[index]->__mysql__); _handles[index]->status = BaseHandle::DISCONNECTED; _handles[index]->lastUsed = time(NULL);} // MysqlConnection::_mysqlDisconnect// -----------------------------------------------------------------------------// MysqlConnection::_mysqlPing// -----------------------------------------------------------------------------void MysqlConnection::_mysqlPing( int index){ // Make sure the handle is valid. if (index > _numHandles || index < 0) throw Error("_mysqlPing(): Invalid index to database handle."); // Only ping the connection if the ping interval has expired since the // connection was last used. time_t currentTime = time(NULL); if (currentTime - _handles[index]->lastUsed >= pingInterval) { // Timeout, lets make sure we still have a connection to the database. // mysql_ping will try to reconnect if the connection is stale if (mysql_ping(&_handles[index]->__mysql__) != 0) { // Synchronize the function as we dont want this connection taken from us SimpleThread_Synchronize sync(classMutex); // Could not reconnect using the mysql_ping, so force a connect retry //1. Disconnect ingnoring errors try { _mysqlDisconnect(index); } catch(...) { } // Ignore any errors from the disconnect. //2. Try get a new connection try { _mysqlConnect(index); // Force the connection to be in use again _handles[index]->status = BaseHandle::CONNECTED_USED; } catch(...) { string err = "_mysqlPing(): Unable to establish new connection, "; throw ErrorPingingConnection(err); } } }} // MysqlConnection::_mysqlPing// -----------------------------------------------------------------------------// MysqlConnection::_mysqlQuery// -----------------------------------------------------------------------------void MysqlConnection::_mysqlQuery( int index, const string& sqlStatement){ // Make sure the handle is in the connected used state. if (_handles[index]->status != BaseHandle::CONNECTED_USED) throw ErrorQuerying("_mysqlQuery(): The database connection is not valid. May have been terminated by the connection object?"); //Execute the query if (mysql_real_query(&_handles[index]->__mysql__, sqlStatement.c_str(), sqlStatement.length()) != 0) { // Something went wrong while trying to execute the sql statement, so throw an exception. string err = "_mysqlQuery(): "; err += "SQL statement: "; err += sqlStatement; err += ", "; err += mysql_error(&_handles[index]->__mysql__); throw ErrorQuerying(err); } // Set the last used _handles[index]->lastUsed = time(NULL);} // MysqlConnection::_mysqlQuery //------------------------------------------------------------------------------// MysqlConnection::_freeCollection//------------------------------------------------------------------------------void MysqlConnection::_freeCollection( CollectionType type){ int i; switch (type) { case CONNECTION_HANDLES: if (_handles) { for (i=0; i<_numHandles; i++) { if (_handles[i]) { delete _handles[i]; _handles[i] = NULL; } } free(_handles); _handles = NULL; _numHandles = 0; } break; }} // MysqlConnection::_freeCollection// -----------------------------------------------------------------------------// PUBLIC:// -----------------------------------------------------------------------------// -----------------------------------------------------------------------------// MysqlConnection::MysqlConnection// -----------------------------------------------------------------------------MysqlConnection::MysqlConnection( int argc, const char** argv): BaseConnection(MYSQL_DRIVERNAME), _numHandles(0), _handles(NULL){ // Store any arguments in a easy to use structure. (Must be even number) // All argument names will be in lowercase. if (argc % 2 == 0) for (int i=0; i<argc; i+=2) { // Check for compression been enabled (If no entry in config file, then use default) if (strcasecmp(argv[i], "mysql_opt_compress") ==0) if (strcasecmp(argv[i+1], "yes") == 0) _mysqlOptions.mysqlOptCompress = true; else _mysqlOptions.mysqlOptCompress = false; // Check for transaction support been enabled (Only supported for MYISAM tables) if (strcasecmp(argv[i], "mysql_opt_transaction") == 0) if (strcasecmp(argv[i+1], "yes") == 0) _mysqlOptions.mysqlOptTransaction = true; else _mysqlOptions.mysqlOptTransaction = false; }} // MysqlConnection::MysqlConnection// -----------------------------------------------------------------------------// MysqlConnection::~MysqlConnection// -----------------------------------------------------------------------------MysqlConnection::~MysqlConnection(){ // Make sure we disconnect from the database. if (isConnected) { disconnect(120); // 2 Minute timeout. } // Free any handles. _freeCollection(CONNECTION_HANDLES); } // MysqlConnection::~MysqlConnection// -----------------------------------------------------------------------------// MysqlConnection::connect// -----------------------------------------------------------------------------void MysqlConnection::connect( const string &username, const string &password, const string &databaseName, const string &host, int maxConnections, int minConnections, const string &optParam1, const string &optParam2){ // Synchronize the function. SimpleThread_Synchronize sync(classMutex); // Make sure we are not already connected. if (isConnected) throw ErrorConnecting("connect(): Already connected to the database."); // Check and set the parameters. (Use the base class for this) BaseConnection::connect(username, password, databaseName, host, maxConnections, minConnections, optParam1, optParam2); // Free any handles used before. _freeCollection(CONNECTION_HANDLES); // Create the collection to hold the needed handle information. _numHandles = maxConnections; _handles = (MysqlHandle**)malloc(_numHandles * sizeof(MysqlHandle*)); for (int i=0; i<_numHandles; i++) { _handles[i] = new MysqlHandle(); _handles[i]->status = BaseHandle::DISCONNECTED; } // Connect the required specified minimum connections. The rest will be on demand. for (int j=0; j<minConnections; j++) _mysqlConnect(j); isConnected = true;} // MysqlConnection::connect // -----------------------------------------------------------------------------// MysqlConnection::disconnect// -----------------------------------------------------------------------------voidMysqlConnection::disconnect( time_t timeout){ // Synchronize the function. SimpleThread_Synchronize sync(classMutex); bool doneTimeout = false; // Only disconnect if we are connected. if (!isConnected) throw NotConnected("disconnect(): Not connected to the database."); // Disconnect all the open connections. for (int i=0; i<_numHandles; i++) { // Free the query object if it is still attached. // TODO if (_handles[i]->status == BaseHandle::CONNECTED || _handles[i]->status == BaseHandle::CONNECTED_USED) { // If the handle is USED wait for the timeout. // Only wait once for the timeout for all connections. if (_handles[i]->status == BaseHandle::CONNECTED_USED && !doneTimeout) { SimpleThread::sleep(timeout * 1000); doneTimeout = true; } _mysqlDisconnect(i); } } isConnected = false;} // MysqlConnection::disconnect// -----------------------------------------------------------------------------// MysqlConnection::requestQueryConnection// -----------------------------------------------------------------------------void*MysqlConnection::requestQueryConnection(){ // This function must act as a fifo stack. The first thread in must get the first // available connection. // Synchronize the function. SimpleThread_Synchronize sync(classMutex); // Make sure we are connected. if (!isConnected) throw NotConnected("requestQueryConnection(): Not connected to the database."); // Flag that a request is occuring. isRequestQueryConnectionOccuring = true; // Loop until we have a valid connection or an error. // Built in timeout of 1 min per thread to retrieve a connection. int i; time_t now = time(NULL); while (time(NULL) <= now + 60) { // Try and obtain a connection for (i=0; i<_numHandles; i++) { // We have an available handle thats already connected. if (_handles[i]->status == BaseHandle::CONNECTED) { _handles[i]->queryObject = new MysqlQuery(this, i); _handles[i]->status = BaseHandle::CONNECTED_USED; isRequestQueryConnectionOccuring = false; return _handles[i]->queryObject; } // We have an available handle that needs to be connected. if (_handles[i]->status == BaseHandle::DISCONNECTED) { _mysqlConnect(i); _handles[i]->queryObject = new MysqlQuery(this, i); _handles[i]->status = BaseHandle::CONNECTED_USED; isRequestQueryConnectionOccuring = false; return _handles[i]->queryObject; } } // Sleep for a second to conserve resources SimpleThread::sleep(1000); } // If we got this far a timeout occured. isRequestQueryConnectionOccuring = false; throw QueryConnectionTimeout("requestQueryConnection(): A timout occured " "while trying to obtain a query connection.");} // MysqlConnection::requestQueryConnection// -----------------------------------------------------------------------------// MysqlConnection::releaseQueryConnection// -----------------------------------------------------------------------------voidMysqlConnection::releaseQueryConnection( void* queryObject){ // Don't synchronize as we may need to release a connection to allow // requestQueryConnection to get an available one // Find the handle that has the query connection instance int i; for (i=0; i<_numHandles; i++) { if (_handles[i]->queryObject == queryObject) { _handles[i]->queryObject = NULL; _handles[i]->status = BaseHandle::CONNECTED; // Check if we need to release the connection. // We release the connection if the connection is outside of the minimum // connections and there is no current request for a connection waiting. if (i >= minConnections && !isRequestQueryConnectionOccuring) { _mysqlDisconnect(i); } break; } }} // MysqlConnection::releaseQueryConnection
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -