linux下使用mysq Connector/C连接mysql服务端过程

2 篇文章 0 订阅
1 篇文章 0 订阅

写在前面:在网上找了很多资料,大部分都是直接安装mysql库,隐式的调用mysql的lib库和mysql.h头文件。当遇到服务器不能安装mysql时,但需要与安装有Mysql的服务器通信时,可以采用如下方法。

  1. 下载mysql-connector-c-6.1.11-linux-glibc2.12-x86_64.tar.gz
    下载地址:https://dev.mysql.com/downloads/connector/c/ (根据自己系统选择对应版本)
    系统环境:centos7 64位

  2. 将解压后的文件复制到系统对应目录下
    tar -zvxf mysql-connector-c-6.1.11-linux-glibc2.12-x86_64.tar.gz
    cd mysql-connector-c-6.1.11-linux-glibc2.12-x86_64/
    cp lib/* /usr/lib64/mysql (如果mysql不存在,则事先建立)
    cp include/* /usr/include/mysql (如果mysql不存在,则事先建立)

  3. 在编译时添加lib库:
    LDLIBS += -L/usr/include/mysql -L/usr/lib64/mysql -lmysqlclient -lpthread -lm -lrt -ldl

  4. 主要数据结构

MYSQL 
mysql数据库连接句柄。在执行任何数据库操作之前首先就需要创建一个MYSQL结构。

MYSQL_RES 
执行查询语句(SELECT, SHOW, DESCRIBE, EXPLAIN)返回的结果。

MYSQL_ROW 
用来表示返回结果中的一行数据。由于每行数据格式不一致,因此使用此结构来统一表示。调用mysql_fetch_row()可从MYSQL_RES中返回一个MYSQL_ROW结构

MYSQL_FIELD 
	用来表示一个field信息的元数据(元数据,即描述数据的数据),包括field name,field type以及field size等。MYSQL_FIELD不包含field的值(MYSQL_ROW真正保存各field的值)

MYSQL_FIELD_OFFSET 
field在row中的索引值,从0开始。
  1. 主要API
  • mysql_init()

     ```
     MYSQL *mysql_init(MYSQL *mysql)`
     
     创建一个MYSQL对象。
     ```
    
    • mysql_real_connect()

      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) `
      
      连接到数据库服务器
      
    • mysql_real_query()

      int mysql_real_query(MYSQL *mysql, const char *stmt_str, unsigned long length);
      
      执行MySQL语句stmt_str,成功返回0
      
  • mysql_store_result()

     ```
     MYSQL_RES *mysql_store_result(MYSQL *mysql);
     
     在执行完查询语句(mysql_store_result() or mysql_use_result())后,调用此函数获得执行结果(result set)。如果执行正确且有结果返回,那么此函数返回非NULL的指针。
     ```
    
  • mysql_affected_rows()

     ```
     my_ulonglong mysql_affected_rows(MYSQL *mysql);
     ```
    
     如果执行的是UPDATE、INSERT和DELETE操作,那么MySQL会告诉你此操作影响了多少行(Rows)。调用此函数即能返回该值。有关在不同操作下此函数返回值的解释,详见官方文档。在以下几种情况下函数会返回0:
     1)带有WHERE的UPDATE操作没有匹配任何行;
     2)调用之前没有执行任何query操作;
     3)对于SELECT操作,在调用mysql_store_reuslt()之前调用此函数。
    
     在三种情况下会返回NULL:
     1)执行的语句不是查询语句,例如INSERT/UPDATE等;
     2)有result set但读取出错(到server的连接出问题);
     3)调用malloc为result set分配空间出错(result set太大)。
     
     第一种情况可通过mysql_field_count()是否返回0来判断;后两种情况可通过 mysql_error()返回非空字符串或者 mysql_errno() 返回大于0来判断。
     
     因此,一般情况下执行SQL语句的流程如下所示:
    
    	MYSQL_RES *result;
    	unsigned int num_fields;
    	unsigned int num_rows;
    	
    	if (mysql_real_query(&mysql,query_string, srlen(query_string)))
    	{
    	    // error
    	}
    	else // query succeeded, process any data returned by it
    	{
    	    result = mysql_store_result(&mysql);
    	    if (result)  // there are rows
    	    {
    	        num_fields = mysql_num_fields(result);
    	        // retrieve rows, then call mysql_free_result(result)
    	    }
    	    else  // mysql_store_result() returned nothing; should it have?
    	    {
    	        if(mysql_field_count(&mysql) == 0)
    	        {
    	            // query does not return data
    	            // (it was not a SELECT)
    	            num_rows = mysql_affected_rows(&mysql);
    	        }
    	        else // mysql_store_result() should have returned data
    	        {
    	            fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
    	        }
    	    }
    	}
    
     6.解析返回结果
    
     在上一节,假定我们成功地执行了语句,并获得了结果(MYSQL_RES结构)。那么怎么从MYSQL_RES中解析出我们想要的东西呢?
    
     先来看一个示例:
    
     ```
     #include <mysql.h>
     #include <string>
     #include <stdio.h>
     using namespace std;
     
     int main()
     {
         if (argc != 2)
         {
             printf("Usage: ./test \"SQL Statement\"\n");
             return -1;
         }
         MYSQL mysql;
         mysql_init(&mysql);
         if (!mysql_real_connect(&mysql,"localhost","mysql","mysql","mytest",3306,NULL,0))//连接到本地数据库
         {
             fprintf(stderr, "Failed to connect to database: Error: %s\n",
             mysql_error(&mysql));
         }
     
         printf("connect to %s:%d success...\n", "localhost", 3306);
     
         string sql(argv[1]);
         if (mysql_real_query(&mysql, sql.c_str(), sql.length()))
         {
             //error
         }
         else 
         { // 成功执行SQL语句
             MYSQL_RES* res = mysql_store_result(&mysql);//获得结果
             if (res) // sucess
             {
                 printf("\"%s\" success\n", sql.c_str());
                 int num_fields = mysql_num_fields(res);
                 int num_rows = mysql_num_rows(res);
                 printf("result: %d rows  %d fields\n", num_rows, num_fields);
                 printf("----------------------------\n");
     
                 //1. 获得列属性(名称)
                 MYSQL_FIELD* fields;//数组,包含所有field的元数据
                 fields = mysql_fetch_fields(res);
                 for (int i = 0; i < num_fields; ++i)
                 {
                     printf("%s\t", fields[i].name);
                 }
                 printf("\n");
     
                 //2. 获得每行的数据
                 MYSQL_ROW row;
                 while ((row = mysql_fetch_row(res)))
                 {
                     unsigned long *lengths;
                     lengths = mysql_fetch_lengths(res);
                     for (int i = 0; i < num_fields; ++i)
                     {
                         printf("%s\t",  row[i] ? row[i] : "NULL");
                     }
                     printf("\n");
                 }
                 printf("----------------------------\n");
                 mysql_free_result(res);
             }
             else
             {
                 //接下来就需要判断为什么res为NULL了
     
                 int ret = mysql_field_count(&mysql);
                 //printf("mysql_field_count %d\n", ret);
                 if (ret == 0)
                 {
                     // 说明执行的是UPDATE/INSERT等这类操作
                     int ret = mysql_affected_rows(&mysql);
                     printf("Query OK, %d rows affected\n", ret);
                 }
                 else
                 {
                     fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
                 }
             }
         }
         mysql_close(&mysql);
         return 0;
     }
     ```
     
     可以看到,从MYSQL_RES中获取结果依靠的是两个函数:
     
     mysql_fetch_fields() 获取field元数据
     mysql_fetch_rows() 获取每一行的数据。每调用一次,该MYSQL_RES的row offset自动增1,因此可以在while循环中调用此函数,直到返回NULL。
     以下是编译运行结果:
     
     首先写个简单的makefile:
     
     #Makefile 
     ```
     test:test.cpp
         g++ -c `mysql_config --cflags` test.cpp
         g++ -o test test.o `mysql_config --libs`
     
     .PHONY: clean
     
     clean:
         rm -f *.o test
     ```
     其中,可以使用mysql_config工具来获得安装Connector时候的头文件位置和库文件位置(详见官方文档)。
     
     编译运行结果:
     ```
     $ make
     g++ -c `mysql_config --cflags` test.cpp
     g++ -o test test.o `mysql_config --libs`
     ```
     ```
     $ ./test "SELECT * FROM table1"
     connect to localhost:3306 success...
     "SELECT * from table1" success
     ```
     ```
     result: 1 rows  3 fields
     ----------------------------
     tid sid     name    
     123 12345   haha
     ----------------------------
     ```
     ```
     $ ./test "UPDATE table1 set sid=12345 where tid=123"
     connect to localhost:3306 success...
     Query OK, 0 rows affected
     ```
     ```
     $ ./test "UPDATE table1 set sid=54321 where tid=123"
     connect to localhost:3306 success...
     Query OK, 1 rows affected
     ```
     ```
     $ ./test "SELECT * from table1"
     connect to localhost:3306 success...
     "SELECT * from table1" success
     ```
     ```
     result: 1 rows  3 fields
     ----------------------------
     tid sid     name    
     123 54321   haha
     ----------------------------
     ```
    

    总结:虽然文章也参考很多别人的内容,已经写法,但总归是第一篇捎带技术性质的博客了,有任何疑问可以给我留言!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值