Chinaunix首页 | 论坛 | 博客
  • 博客访问: 111905
  • 博文数量: 27
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 360
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-07 00:14
文章分类

全部博文(27)

文章存档

2015年(1)

2014年(20)

2013年(6)

我的朋友

分类: C/C++

2014-01-19 11:22:10

 一、认识mysql客户端可以使用的库

libmysqlclient.so.主版本号.次版本号        ====  通过网络连接到一个独立运行的数据库服务程序

libmysqld.so.主版本号.次版本号             ====   客户端本身内嵌mysql服务代码                    


当这些库的主版本号改变时,都需要重新编译程序。因为当一个库的主版本号改变,其所提供的api可能会发生改变,例如函数的调用参数个数发生改变。


二、客户端和服务端的缓存分配方式

   默认,客户端所能使用的最大缓存为16MB,对应的服务端为1MB。并不是一开始就分配最大缓存,而是在现有缓存不满足需求下才分配更大的缓存。
  通过修改max_allowed_packet 来修改最大缓存配置值。


  在服务端,当一个查询会话结束后,缓存大小自动缩减到net_buffer_lenght, 而客户端的缓存到程序结束之后才会被回收。


三、mysql 编译帮助工具

gcc `mysql_config --cflags` `mysql_config --include` `mysql_config --libs` progname.c

当出现类似下面的错误:            
          mf_format.o(.text+0x201): undefined reference to `__lxstat'
说明当前的编译环境和库文件的编译环境不一样。解决这个问题的方法是,在官网下载库的源代码,自己编译。


四、mysql 客户客户端程序编写要点

                1 需要为 SIGPIPE 信号安装处理函数,方法为
                                    mysql_library_init
                                    sigaction(SIGPIPE, &act, NULL);

                 2 对于多线程客户端程序, 一个connection就是一个临界区,因此在mysql_query() 和 mysql_store_result() 之间需要使用锁。例如pthread_mutex_lock 和 pthread_mutex_unlock


                            在所有线程被创建之前调用mysql_library_init(), 在线程的函数内首先 要mysql_thread_init() 作为开始。 在线程结束之前要调用mysql_thread_end()。



                  3 API 详解
                      1) int mysql_library_init(int argc, char **argv, char **groups)
                                    当使用内嵌数据库时才使用 argv, groups 参数,这样可以向数据库服务传递配置参数;如果只是单纯客户端程序,可以这样调用
                         int cal_ret = mysql_library_init(0, NULL, NULL);
                         if (cal_ret == 0) // call success

                     2)  void mysql_library_end() 
                                     当使用完数据库,调用这个函数来释放资源。

                     3)  MYSQL *mysql_init(MYSQL *mysql)
                                      初始化connection handler。
                              MYSQL *mysql = mysql_init(NULL);
                              if(mysql == NULL) // failed, call mysql_error

                      4) MYSQL * mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db,  unsigned int port, const char *unix_socket, unsigned long client_flag);
                                     与数据库建立连接
                          if (mysql_real_connect("127.0.0.1", "root", "hantele", "information_schema", 3306, NULL, 0) == NULL) // failed, call mysql_error

                       5) int mysql_real_query(MYSQL *mysql, const char *stmt_str, unsigned long length);
                                  执行sql语句
                            #define sql_command "select table_schema, table_name from tables;"
                            if(mysql_real_query(mysql,  sql_command, sizeof(sql_command)) // failed, call mysql_error

                       6) my_ulonglong mysql_affected_rows(MYSQL *mysql)
                                   对于非查询类的sql语句(例如 insert,update, delete), 查询有多少行受到影响。                           
         

点击(此处)折叠或打开

  1. #include <mysql.h>
  2. #include <iostream>
  3. #include <sstream>
  4. #include <map>
  5. #include <string>
  6. #include <list>
  7. #include <cstdlib>
  8. #include <unistd.h>
  9. #include <cstring>
  10. #include <errno.h>
  11. #include <sys/statvfs.h> /* for statvfs */
  12. using namespace std;


  13. int GetFreeSpaceSize(const char *ib_data_dir)
  14. {
  15.     struct statvfs buf;
  16.     if (statvfs(ib_data_dir, &buf) != 0)
  17.     {
  18.         cerr << "[ERROR] ############# Failed to get file system informations, error message is " << strerror(errno) << endl;
  19.         return (-1);
  20.     }
  21.     typedef unsigned long long int guint64; // 64 bits
  22.     guint64 free_size = ((guint64)buf.f_bsize * buf.f_bavail) / 1024/1024/1024;
  23.     return (free_size);
  24. }
  25. int main(int argc, char *argv[])
  26. {
  27.     int keep_space = 500; // G
  28.     const char *ib_data_dir = "/opt/mysql";
  29.     const char * host = "127.0.0.1";
  30.     const char * user = "root";
  31.     const char * passwd = "hantele";
  32.     const char * db = "information_schema";
  33.     unsigned int port = 3306;
  34.     const char *unix_socket = NULL;
  35.     unsigned long client_flag = 0;
  36.     MYSQL *mysql = NULL;
  37.     MYSQL_RES *sql_results = NULL;
  38.     MYSQL_ROW sql_row = NULL;
  39.     my_ulonglong sql_rows_count = 0;
  40.     unsigned int sql_field_count = 0;
  41.     map<string, list<string> > mmap;

  42.     try
  43.     {
  44.         if (mysql_library_init(0, NULL, NULL))
  45.         {
  46.             cerr << "[ERROR] ########## Could not initialize MYSQL library .!" << endl;
  47.             throw (1);
  48.         }

  49.         mysql = mysql_init(NULL);
  50.         if (mysql == NULL)
  51.         {
  52.             cerr << "[ERROR] ######### Can not initialize MYSQL connection, error message: %s .!" << mysql_error(mysql) << endl;
  53.             throw (2);
  54.         }

  55.         if (!mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, client_flag))
  56.         {
  57.             cerr << "[ERROR] ######### Failed to connect to database, error message: %s .!" << mysql_error(mysql) << endl;
  58.             throw (3);
  59.         }

  60.         cout << "[INFO] ############ connect to database ok .!" << endl;

  61.         char stmt_str[] = "select concat(table_schema, '.', table_name) from tables where table_name like \"%common_xdr%\";";
  62.         if (mysql_real_query(mysql, stmt_str, sizeof(stmt_str)- 1))
  63.         {
  64.             cerr << "[ERROR] ########### Faield to execute statement, error message: %s .!" << mysql_error(mysql) << endl;
  65.             throw (4);
  66.         }

  67.         sql_results = mysql_store_result(mysql);
  68.         if (sql_results == NULL)
  69.         {
  70.             cerr << "[ERROR] ############# Failed to get results, error message: %s .!" << mysql_error(mysql) << endl;
  71.             throw (5);
  72.         }

  73.         // 处理结果集
  74.         sql_rows_count = mysql_num_rows(sql_results);
  75.         sql_row = mysql_fetch_row(sql_results);
  76. #ifndef NDEBUG
  77.         cout << "************************************************************************ " << endl;
  78. #endif
  79.         while (sql_row)
  80.         {
  81.             string table_name = sql_row[0];
  82. #ifndef NDEBUG // 打印每一行记录
  83.             cout << "[INFO] ############ table_name: " << table_name << endl;
  84. #endif
  85.             string::size_type timestamp_p = table_name.find_last_of('_');
  86.             if (timestamp_p == string::npos)
  87.             {

  88.                 cerr << "[ERROR] ############ Find a table name which is not a valid common_xdr table name ===> " << table_name << endl;
  89.                 continue;
  90.             }
  91.             string timestamp = table_name.substr(timestamp_p+1);
  92. #ifndef NDEBUG
  93.             cout << "[INFO] ############ timestamp " << timestamp << endl;
  94. #endif
  95.             list<string>& table_list = mmap[timestamp];
  96.             table_list.push_back(table_name);

  97.             sql_row = mysql_fetch_row(sql_results);
  98.         }
  99. #ifndef NDEBUG
  100.         cout << "************************************************************************ " << endl;
  101. #endif


  102.         mysql_free_result(sql_results);



  103. #ifndef NDEBUG
  104.         cout << "######################################################################## " << endl;
  105.         for (map<string, list<string> >::iterator it = mmap.begin(); it != mmap.end(); ++it)
  106.         {
  107.             cout << "timestamp: " << it->first << endl;
  108.             list<string>& table_list = it->second;

  109.             for (list<string>::iterator it_list = table_list.begin(); it_list != table_list.end(); ++it_list)
  110.             {
  111.                 cout << "\t " << *it_list << endl;
  112.             }
  113.         }
  114.         cout << "######################################################################## " << endl;
  115. #endif

  116.         // 删除最老的表,直到磁盘空间剩余足够用的空间
  117.         map<string, list<string> >::iterator it_map;
  118.         for (it_map = mmap.begin(); it_map != mmap.end(); ++it_map)
  119.         {
  120.             int space_size = GetFreeSpaceSize(ib_data_dir);
  121.             if (space_size < keep_space)
  122.             {
  123. #ifndef NDEBUG
  124.                 cout << "[INFO] ############ Current space size: " << space_size << "G less then " << keep_space << "G, so delete tables in old day .!" << endl;
  125. #endif

  126.                 // 删除表
  127.                 list<string>& table_list = it_map->second;
  128.                 for (list<string>::iterator it_list = table_list.begin(); it_list != table_list.end(); ++it_list)
  129.                 {
  130.                     ostringstream del_str;
  131.                     del_str << "drop table " << *it_list << ";";
  132.                     string stmt_str = del_str.str();

  133. #ifndef NDEBUG
  134.                     cout << "[INFO] ############# try to drop table ========> " << *it_list << endl ;
  135. #endif
  136.                     if (mysql_real_query(mysql, stmt_str.c_str(), stmt_str.size()))
  137.                     {
  138.                         cerr << "[ERROR] ########### Faield to execute statement, error message: %s .!" << mysql_error(mysql) << endl;
  139.                         throw (5);
  140.                     }
  141. #ifndef NDEBUG
  142.                     cout << "[INFO] ############# drop table ========> " << *it_list << " ok.!" << endl ;
  143. #endif
  144.                 }
  145.             }
  146.             else
  147.             {
  148.                 cout << "[INFO] ########### There are " << space_size << "G in the partion, larger then " << keep_space << "G, so do nothing .!" << endl;
  149.                 exit(0);
  150.             }
  151.         }
  152.     }
  153.     catch (int exp_code)
  154.     {
  155.         switch (exp_code)
  156.         {
  157.             case 2:
  158.             case 3:
  159.             case 4:
  160.             case 5:
  161.             case 6:
  162.                 mysql_close(mysql);
  163.             case 1:
  164.                 mysql_library_end();
  165.                 return 0;
  166.                 break;
  167.         }
  168.     }

  169.     mysql_close(mysql);
  170.     mysql_library_end();
  171.     return 0;
  172. }

                                  
                    

                     

To prepare and execute a statement, an application follows these steps:

  1. Create a prepared statement handle with . To prepare the statement on the server, call and pass it a string containing the SQL statement.

  2. If the statement will produce a result set, call to obtain the result set metadata. This metadata is itself in the form of result set, albeit a separate one from the one that contains the rows returned by the query. The metadata result set indicates how many columns are in the result and contains information about each column.

  3. Set the values of any parameters using . All parameters must be set. Otherwise, statement execution returns an error or produces unexpected results.

  4. Call mysql_stmt_execute() to execute the statement.

  5. If the statement produces a result set, bind the data buffers to use for retrieving the row values by calling .

  6. Fetch the data into the buffers row by row by calling repeatedly until no more rows are found.

  7. Repeat steps 3 through 6 as necessary, by changing the parameter values and re-executing the statement.

When is called, the MySQL client/server protocol performs these actions:

  • The server parses the statement and sends the okay status back to the client by assigning a statement ID. It also sends total number of parameters, a column count, and its metadata if it is a result set oriented statement. All syntax and semantics of the statement are checked by the server during this call.

  • The client uses this statement ID for the further operations, so that the server can identify the statement from among its pool of statements.

When mysql_stmt_execute() is called, the MySQL client/server protocol performs these actions:

  • The client uses the statement handle and sends the parameter data to the server.

  • The server identifies the statement using the ID provided by the client, replaces the parameter markers with the newly supplied data, and executes the statement. If the statement produces a result set, the server sends the data back to the client. Otherwise, it sends an okay status and the number of rows changed, deleted, or inserted.

When is called, the MySQL client/server protocol performs these actions:

  • The client reads the data from the current row of the result set and places it into the application data buffers by doing the necessary conversions. If the application buffer type is same as that of the field type returned from the server, the conversions are straightforward.

If an error occurs, you can get the statement error number, error message, and SQLSTATE code using , , and , respectively.

Prepared Statement Logging

For prepared statements that are executed with the and mysql_stmt_execute() C API functions, the server writes Prepare and Execute lines to the general query log so that you can tell when statements are prepared and executed.

Suppose that you prepare and execute a statement as follows:

  1. Call to prepare the statement string "SELECT ?".

  2. Call to bind the value 3 to the parameter in the prepared statement.

  3. Call mysql_stmt_execute() to execute the prepared statement.

As a result of the preceding calls, the server writes the following lines to the general query log:

Prepare  [1] SELECT ?
Execute  [1] SELECT 3

Each Prepare and Execute line in the log is tagged with a [N] statement identifier so that you can keep track of which prepared statement is being logged. N is a positive integer. If there are multiple prepared statements active simultaneously for the client, N may be greater than 1. Each Execute lines shows a prepared statement after substitution of data values for ? parameters.



点击(此处)折叠或打开

  1. #include <mysql.h>
  2. #include <iostream>
  3. #include <sstream>
  4. #include <map>
  5. #include <string>
  6. #include <list>
  7. #include <cstdlib>
  8. #include <unistd.h>
  9. #include <cstring>
  10. #include <errno.h>
  11. #include <sys/statvfs.h> /* for statvfs */
  12. using namespace std;


  13. int GetFreeSpaceSize(const char *ib_data_dir)
  14. {
  15.     struct statvfs buf;
  16.     if (statvfs(ib_data_dir, &buf) != 0)
  17.     {
  18.         cerr << "[ERROR] ############# Failed to get file system informations, error message is " << strerror(errno) << endl;
  19.         return (-1);
  20.     }
  21.     typedef unsigned long long int guint64; // 64 bits
  22.     guint64 free_size = ((guint64)buf.f_bsize * buf.f_bavail) / 1024/1024/1024;
  23.     return (free_size);
  24. }
  25. int main(int argc, char *argv[])
  26. {
  27.     int keep_space = 500; // G
  28.     const char *ib_data_dir = "/opt/mysql";
  29.     const char * host = "127.0.0.1";
  30.     const char * user = "root";
  31.     const char * passwd = "hantele";
  32.     const char * db = "test";
  33.     unsigned int port = 3306;
  34.     const char *unix_socket = NULL;
  35.     unsigned long client_flag = 0;
  36.     MYSQL *mysql = NULL;
  37.     MYSQL_RES *sql_results = NULL;
  38.     MYSQL_ROW sql_row = NULL;
  39.     my_ulonglong sql_rows_count = 0;
  40.     unsigned int sql_field_count = 0;
  41.     map<string, list<string> > mmap;

  42.     try
  43.     {
  44.         if (mysql_library_init(0, NULL, NULL))
  45.         {
  46.             cerr << "[ERROR] ########## Could not initialize MYSQL library .!" << endl;
  47.             throw (1);
  48.         }

  49.         mysql = mysql_init(NULL);
  50.         if (mysql == NULL)
  51.         {
  52.             cerr << "[ERROR] ######### Can not initialize MYSQL connection, error message: %s .!" << mysql_error(mysql) << endl;
  53.             throw (2);
  54.         }

  55.         if (!mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket, client_flag))
  56.         {
  57.             cerr << "[ERROR] ######### Failed to connect to database, error message: %s .!" << mysql_error(mysql) << endl;
  58.             throw (3);
  59.         }

  60.         MYSQL_STMT * mysql_stmt = mysql_stmt_init(mysql);
  61.         if (mysql_stmt == NULL)
  62.         {
  63.             cerr << "[ERROR] ########## Failed to call mysql_stmt_init, error message:" << mysql_error(mysql) << endl;
  64.             throw (3);
  65.         }
  66.         cout << "[INFO] ############ connect to database ok .!" << endl;


  67.         const char stmt_str[] = "insert into test_table values(?,?,?)";
  68.         if (mysql_stmt_prepare(mysql_stmt, stmt_str, sizeof(stmt_str)) != 0)
  69.         {
  70.             cerr << "[ERROR] ########## failed to call mysql_stmt_prepare, error message: " << mysql_stmt_error(mysql_stmt) << endl;
  71.             throw (3);
  72.         }
  73.         cout << "call mysql_stmt_prepare ok .!" << endl;

  74.         /* MYSQL_BIND
  75.          * This structure is used both for statment input(data values sent to the server) and output (result values returned from server):
  76.          * To use a MYSQL_BIND structure, zero its contents to initialize it, then set its members appropriately.
  77.          */

  78.      
  79.         MYSQL_BIND bind[3];
  80.         memset(bind, 0, sizeof(bind));

  81.         /*
  82.          * The MYSQL_BIND structure contains the following memebers for use by application programs. For serveral of the members, the manner of use depends on whether the structure is used for input or output.
  83.          *            Input Variable C Type        | buffer_type value        SQL Type of Destination Value
  84.          *            signed char                        MYSQL_TYPE_TINY        TINYINT
  85.          *            short int                        MYSQL_TYPE_SHORT    SMALLINT
  86.          *            int                                MYSQL_TYPE_LONG        INT
  87.          *            long long int                    MYSQL_TYPE_LONGLONG    BIGINT
  88.          *            float                            MYSQL_TYPE_FLOAT    FLOAT
  89.          *            double                            MYSQL_TYPE_DOUBLE    DOUBLE
  90.          *            MYSQL_TIME                        MYSQL_TYPE_TIME        TIME
  91.          *            MYSQL_TIME                        MYSQL_TYPE_DATE        DATE
  92.          *            MYSQL_TIME                        MYSQL_TYPE_DATETIME    DATETIME
  93.          *            MYSQL_TIME                        MYSQL_TYPE_TIMESTAMP    TIMESTAMP
  94.          *            char []                            MYSQL_TYPE_STRING    TEXT,CHAR,VARCHAR
  95.          *            char []                            MYSQL_TYPE_BLOB        BLOB,BINARY,VARBINARY
  96.          *                                            MYSQL_TYPE_NULL        NULL
  97.          */

  98.         bind[0].buffer_type = MYSQL_TYPE_STRING;
  99.         bind[1].buffer_type = MYSQL_TYPE_STRING;
  100.         bind[2].buffer_type = MYSQL_TYPE_NULL;
  101.         
  102.         /* void *buffer
  103.          * A pointer to ther buffer to be used for data transfer.This is the address of a C language variable.
  104.          * For input, buffer is a pointer to the variable in which you store the data value for a statment parameter. When you call mysql_stmt_execute, MySQL use the value stored in the variable in place of the corresponding parameter marker in the statment
  105.          * For output, buffer is a pointer to variable in which to return a result set column value. When you call mysql_stmt_fetch(), MySQL stores a column value from the current row of the result set in this variable. You can access the value when the call returns.
  106.          */

  107. #define CONTENTS "hello,world"
  108.         bind[0].buffer = (void*)CONTENTS;
  109.         bind[1].buffer = (void*)CONTENTS;
  110.         bind[2].buffer = (void*)CONTENTS;


  111.         /* unsigned long buffer_length
  112.          * The actual size of *buffer in bytes.This indiactes the maximum amount of data that can be stored in the buffer. For character and binary C data, the buffer_length value specifies the length of *buffer when used with mysql_stmt_bind_param() to specify input values, or the maximum number of output data bytes that can be fetched into the buffer when used with mysql_stmt_bind_result().
  113.          */
  114.         bind[0].buffer_length = sizeof(CONTENTS);
  115.         bind[1].buffer_length = sizeof(CONTENTS);
  116.         bind[2].buffer_length = sizeof(CONTENTS);
  117.         /* unsigned long *length
  118.          * A pointer to an unsigned long variable that indicates the actual number of bytes data stored in *buffer. length is used for character or binary C data.
  119.          * For input parameter data binding, set *length to indiacte the actual length of the parameter value stored in *buffer. This is used by mysql_stmt_execute().
  120.          * For output value bingding, MySql sets *length when you call mysql_stmt_fetch(). The mysql_stmt_fetch() return value determines how to interpret the lenght:
  121.          *        if the return value is 0, *length indicates the actual length of the parameter value.
  122.          *        if the value is MYSQL_DATA_TRUNCATED, *length indicates the nontruncated length of the parameter value. In this case, the minimum of *length and buffer_length indicates the actual length of the value.
  123.          *    length is ignored for numeric and temporal data types because the buffer_type value determines the length of the data value.
  124.          */
  125.         bind[0].length = &bind[0].buffer_length;
  126.         bind[1].length = &bind[1].buffer_length;
  127.         bind[2].length = &bind[2].buffer_length;

  128.         /*
  129.          * mysql_stmt_bind_param is used to bind input data for the parameter markers in the SQL statement that was passed to mysql_stmt_prepare().
  130.          * It uses MYSQL_BIND structures to supply the data. bind is the address of an array of MYSQL_bIND structures. The client library expects the array to contain one element for each ? parameter marker that is present in the query.
  131.          * Suppose that you prepare the following statement:
  132.          * INSERT INTO mytbl VALUES(?,?,?)
  133.          *
  134.          * When you bind the parameters, the array of MYSQL_BIND structures must contain three elements, and can be declared like this:
  135.          * MYSQL_BIND bind[3];
  136.          */
  137.         /*
  138.          *    For input, use MYSQL_BIND structures with mysql_stmt_bind_param() to bind parameter data values to buffers for use by mysql_stmt_execute().
  139.          *
  140.          *    For output, use MYSQL_BIND structures with mysql_stmt_bind_result() to bind buffers to result set columns,for use in fetching rows with mysql_stmt_fetch().
  141.          */
  142.         if (mysql_stmt_bind_param(mysql_stmt, bind) != 0)
  143.         {
  144.             cerr << "[ERROR] ########### failed to call mysql_stmt_bind_param, error message: " << mysql_stmt_error(mysql_stmt) << endl;
  145.             throw (3);
  146.         }


  147.         /*
  148.          * mysql_stmt_execute() executes the prepared query associated with the statement handle. The currentl bound parameter marker values are sent to server during this call, and the server replaces the markers with this newly supplied data.
  149.          */
  150.         if (mysql_stmt_execute(mysql_stmt) != 0)
  151.         {
  152.             cerr << "[ERROR] ####### failed to call mysql_stmt_execute, error message: " << mysql_stmt_error(mysql_stmt) << endl;
  153.         }


  154.         /*
  155.          * For an update, delete, or insert, the number of changed, delete, or inserted rows can be found by call mysql_stmt_affected_rows(). It may be called immediately after executing a statement with mysql_stmt_execute.
  156.          *
  157.          */
  158.         cout << "[INFO] ############## call mysql_stmt_execute ok, there are " << mysql_stmt_affected_rows(mysql_stmt) << " rows affacted .!





                
阅读(933) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~