天天看點

docker環境linux ubuntu C/C++連接配接mysql資料庫 & docker容器連接配接主控端mysql

目錄

一、在ubuntu系統中C/C++連接配接mysql

二、在docker容器ubuntu系統内使用C/C++連接配接主控端的mysql

三、libmysqlclient-dev庫常用函數

一、在ubuntu系統中C/C++連接配接mysql

1. 更新并更新軟體源

apt-get update
apt-get upgrade
           

2. 安裝c/c++解釋器

apt-get install g++
           

     安裝後,執行 g++ --version  可顯示版本資訊

3. 安裝mysql伺服器(若不使用本地資料庫,而使用遠端資料庫,或docker環境下使用主控端mysql ,可跳過此步)

apt-get install mysql-client mysql-server
           

      安裝mysql時,中途會提示你設定使用者密碼等,請牢記!并在第6步的c++程式中,修改相應的資料庫配置變量!順便建立一個資料庫供後面測試:

mysql -u root -p       # 進入mysql資料庫互動

# 下面在mysql互動下執行
create database mydatabase;  # 建立資料庫
           

4. 安裝C/C++連接配接mysql驅動包

apt-get install libmysqlclient-dev
           

5. 編寫C++程式進行測試

vim test.cpp
           
#include<stdio.h>
#include<mysql/mysql.h>

const char *db_host="localhost";
const char *db_user="root";
const char *db_pass="rootroot";
const char *db_name="mydatabase";
const int   db_port=3306;

int main ()
{

    MYSQL *mysql=mysql_init(NULL);   //初始化資料庫連接配接變量
    if(mysql==NULL)
    {
        printf("Error:%s\n",mysql_error(mysql));
        exit(1);
    }
    mysql = mysql_real_connect(mysql,db_host,db_user,db_pass,db_name, db_port,NULL,0); //連接配接mysql
    if(mysql)
        printf("Success!\n");  //連接配接成功
    else printf("Failed!\n");
    return 0;
}
           

6. 編譯C++程式并執行

g++ test.cpp -o test -lmysqlclient
           

      注:末尾務必加上  -lmysqlclient  否則編譯時找不到mysql庫

./test
           

      這是執行程式,如果成功連接配接mysql,則會顯示  Success!   

二、在docker容器ubuntu系統内使用C/C++連接配接主控端的mysql

最新方法:在版本高于18.03的docker中直接通路 `host.docker.internal` 就可以通路到主控端!以下可以不看!

注意:請保證主控端已安裝mysql伺服器,并開啟服務。

1. 編寫makefile

FROM ubuntu:16.04

RUN echo "\
deb http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse\n\
deb http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse\n\
deb http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse\n\
deb http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse\n\
deb http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse\n\
deb-src http://mirrors.163.com/ubuntu/ bionic main restricted universe multiverse\n\
deb-src http://mirrors.163.com/ubuntu/ bionic-security main restricted universe multiverse\n\
deb-src http://mirrors.163.com/ubuntu/ bionic-updates main restricted universe multiverse\n\
deb-src http://mirrors.163.com/ubuntu/ bionic-proposed main restricted universe multiverse\n\
deb-src http://mirrors.163.com/ubuntu/ bionic-backports main restricted universe multiverse\n" > /etc/apt/sources.list \
	&& apt update\
	&& apt install -y g++ libmysqlclient-dev

EXPOSE 80
           

2. 運作makefile,生成鏡像(最後有個點。myimage是鏡像名字,tag是版本号)

$ docker build -t myimage:tag .
           

3. 生成容器并進入

docker run -it myimage:tag /bin/bash
           

4. 使主控端允許docker容器連接配接mysql服務

緣由分析: 容器内通路localhost是通路容器本身,通路不到主控端,故先查主控端ip。容器内執行 ifconfig 可以檢視ip:

docker環境linux ubuntu C/C++連接配接mysql資料庫 &amp; docker容器連接配接主要端mysql

圖中 172.17.0.2是指容器本身的ip,那麼主控端的ip就是172.17.0.1。是以在docker内通路主控端的mysql時,就是用這個ip。執行一下 ping 172.17.0.1 或 telnet 172.17.0.1 3306試試能不能通路到主控端。

若ifconfig和ping指令不識别,請安裝插件:

apt install net-tools            # ifconfig 
apt-get install inetutils-ping   # ping
apt-get install telnet           # telnet
           

但是預設情況下,主控端的mysql隻允許本地(localhost)通路,docker容器是拒絕通路的。是以需要修改主控端mysql使用者的權限。

①主控端是ubuntu系統(主控端操作)

兩步,1.建立允許外網通路的特權使用者,2.修改mysql配置檔案,使其接受外網連接配接。

# 第一步,增加特權使用者
mysql -u root -p     # 進入mysql,回車後需要輸入root密碼


# 下面在mysql互動裡修改root使用者的可通路位址
grant all privileges on *.* to 'testuser'@'%' identified by '123456';
flush privileges;
exit;

# testuser是建立的使用者名,其密碼是123456
# '%' 允許通路資料庫的IP位址,%意思是任意IP,也可以指定IP
# flush privileges 重新整理權限資訊


# 第二步,允許外網連接配接mysql伺服器
vim /etc/mysql/mysql.conf.d/mysqld.cnf
# 找到 bind-address = 127.0.0.1 這一行,注釋掉(行首加#)
           

②主控端是windows(主控端操作)

一步:建立允許外網通路的特權使用者。

# 請使用管理者權限運作cmd
# 進入到mysql的安裝目錄裡的/bin/目錄下,再執行:
.\mysql -uroot -p           #進入mysql互動


# 下面在mysql互動裡修改root使用者的可通路位址
grant all privileges on *.* to 'testuser'@'%' identified by '123456';
flush privileges;
exit;

# testuser是建立的使用者名,其密碼是123456
# '%' 允許通路資料庫的IP位址,%意思是任意IP,也可以指定IP
# flush privileges 重新整理權限資訊
           

【未解決的問題】:按說現在可以直接通過ip:172.17.0.1連接配接主控端了,但實際測試中總是不行,使用WIFI區域網路的ip都連通了,唯獨172.17.0.1拒絕通路。懇請知情的大神在評論區指點!

5. 在容器内編寫C++程式【關注ip與端口】

#include<stdio.h>
#include<mysql/mysql.h>

const char *db_host="172.17.0.1";
const char *db_user="root";
const char *db_pass="rootroot";
const char *db_name="mydatabase";
const int   db_port=3306;

int main ()
{

    MYSQL *mysql=mysql_init(NULL);   //初始化資料庫連接配接變量
    if(mysql==NULL)
    {
        printf("Error:%s\n",mysql_error(mysql));
        exit(1);
    }
    mysql = mysql_real_connect(mysql,db_host,db_user,db_pass,db_name, db_port,NULL,0); //連接配接mysql
    if(mysql)
        printf("Suucess!\n");  //連接配接成功
    else printf("Failed!\n");
    return 0;
}
           

6. 編譯C++程式并執行

g++ test.cpp -o test -lmysqlclient
           

      注:末尾務必加上  -lmysqlclient  否則編譯時找不到mysql庫

./test
           

      這是執行程式,如果成功連接配接mysql,則會顯示  Success!   

三、libmysqlclient-dev庫常用函數

示例1

#include <iostream>
#include <cstdlib>
#include <string>
#include <vector>
#include <mysql/mysql.h>
using namespace std;

int main(){

    const char *host = "localhost";
    const char *user = "root";
    const char *upwd = "root";
    const char *dbs = "test";
    unsigned int port = 3306;


    MYSQL mydata;

    if(0==mysql_library_init(0,NULL,NULL)){
        cout<<"mysql_library_init() successed!!"<<endl;
    }else{
        cout<<"mysql_library_init() failed!!"<<endl;
        return -1;
    }

    //初始化資料結構
    if(NULL != mysql_init(&mydata)){
        cout<<"初始化資料結構成功!"<<endl;
    }else{
        cout<<"初始化資料結構失敗"<<endl;
        return -1;
    }

    //設定資料庫編碼類型
    if(0==mysql_options(&mydata,MYSQL_SET_CHARSET_NAME,"utf8")){
        cout<<"設定資料庫編碼類型成功!"<<endl;
    }else{
        cout<<"設定資料庫編碼類型失敗!"<<endl;
        return -1;
    }

    //連接配接資料庫
    if(NULL != mysql_real_connect(&mydata,host,user,upwd,dbs,port,NULL,0)){
        cout<<"資料庫連接配接成功了!"<<endl;
    }else{
        cout<<"資料庫連接配接失敗了!!"<<endl;
        return -1;
    }

    //插入資料
    //string sqlstr;
    //sqlstr="INSERT INTO user(`username`, `password`) VALUES ('test', 'test123');";
    //if(0==mysql_query(&mydata,sqlstr.c_str())){
    //    cout<<"插入資料成功"<<endl;
    //}else{
    //    cout<<"插入資料失敗了!!"<<endl;
    //}

    string sqlstr_select = " select * from user;";
    //顯示查詢結果
    MYSQL_RES *result=NULL;
    if(0==mysql_query(&mydata,sqlstr_select.c_str())){
        cout<<"查詢成功!"<<endl;

        //一次性取得資料集 
        result =mysql_store_result(&mydata);

        //取得并列印行數 
        my_ulonglong rowcount = mysql_num_rows(result); 
        cout << "row count: " << rowcount << endl; 

        //取得并列印各字段的名稱 
        unsigned int fieldcount = mysql_num_fields(result); 
         MYSQL_FIELD *field = NULL;

         for (unsigned int i = 0; i < fieldcount; i++) { 
             field = mysql_fetch_field_direct(result, i); 
             cout << field->name << "\t\t"; 
         } 
         cout << endl; 

         列印各行 
         //MYSQL_ROW row = NULL; 
         //row = mysql_fetch_row(result); 
         //while (NULL != row) { 
            // for (int i = 0; i < fieldcount; i++) { 
            //     cout << row[i] << "\t\t"; 
            // } 
            // cout << endl; 
            // row = mysql_fetch_row(result); 
         //} 


    }else{
        cout << "mysql_query() select data failed" << endl; 
        mysql_close(&mydata); 
        return -1; 
    }

    


    mysql_close(&mydata);
    mysql_library_end();
    return 0;
}
           

示例2

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string.h>
#include<time.h>
#include<mysql/mysql.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

const char *db_host="192.168.31.16";
const char *db_user="testuser";
const char *db_pass="123456";
const char *db_name="woj";
const int   db_port=3306;



static MYSQL *mysql;    //資料庫連接配接對象
static MYSQL_RES *mysql_res;   //sql查詢結果
static MYSQL_ROW mysql_row;    //sql查詢到的單行資料
char sql[256];   //暫存sql語句


void get_wating_solution(int solution_queue[],int &queueing_cnt) //從solution表讀取max_running個待判編号
{
    queueing_cnt=0;
    sprintf(sql,"SELECT id FROM solution WHERE result<=%d ORDER BY id ASC limit %d",OJ_WT,max_running);
    if(mysql_real_query(mysql,sql,strlen(sql))!=0){
        printf("select failed!\n");
        exit(1);
    }
    mysql_res=mysql_store_result(mysql);    //儲存查詢結果
    char sid_str[max_running*11]="\0";
    while(mysql_row=mysql_fetch_row(mysql_res))  //将結果讀入判題隊列
    {
        solution_queue[queueing_cnt++]=atoi(mysql_row[0]);
        if(sid_str[0]!='\0')strcat(sid_str,",");
        strcat(sid_str,mysql_row[0]);
    }
    if(queueing_cnt>0)  //更新已讀入的solution的result
    {
        sprintf(sql,"UPDATE solution SET result=%d WHERE id in (%s)",OJ_QI,sid_str); //更新狀态
        mysql_real_query(mysql,sql,strlen(sql));
    }
}


int main ()
{
    mysql = mysql_init(NULL);   //初始化資料庫連接配接
    mysql = mysql_real_connect(mysql,db_host,db_user,db_pass,db_name, db_port,NULL,0);
    if(!mysql){
        printf("Error: Can't connect to database!\n\n");
        exit(1);
    }
    static int running_cnt=0,queueing_cnt;     //排隊數
    static int solution_queue[max_running];    //隊列
    get_wating_solution(solution_queue,queueing_cnt);
    mysql_close(mysql);
    return 0;
}
           

3.常用API

mysql_affected_rows() 傳回被最新的UPDATE, DELETE或INSERT查詢影響的行數。

mysql_close() 關閉一個伺服器連接配接。

mysql_connect() 連接配接一個MySQL伺服器。該函數不推薦;使用mysql_real_connect()代替。

mysql_change_user() 改變在一個打開的連接配接上的使用者和資料庫。

mysql_create_db() 建立一個資料庫。該函數不推薦;而使用SQL指令CREATE DATABASE。

mysql_data_seek() 在一個查詢結果集合中搜尋一任意行。

mysql_debug() 用給定字元串做一個DBUG_PUSH。

mysql_drop_db() 抛棄一個資料庫。該函數不推薦;而使用SQL指令DROP DATABASE。

mysql_dump_debug_info() 讓伺服器将調試資訊寫入日志檔案。

mysql_eof() 确定是否已經讀到一個結果集合的最後一行。這功能被反對; mysql_errno()或mysql_error()可以相反被使用。

mysql_errno() 傳回最近被調用的MySQL函數的出錯編号。

mysql_error() 傳回最近被調用的MySQL函數的出錯消息。

mysql_escape_string() 用在SQL語句中的字元串的轉義特殊字元。

mysql_fetch_field() 傳回下一個表字段的類型。

mysql_fetch_field_direct () 傳回一個表字段的類型,給出一個字段編号。

mysql_fetch_fields() 傳回一個所有字段結構的數組。

mysql_fetch_lengths() 傳回目前行中所有列的長度。

mysql_fetch_row() 從結果集合中取得下一行。

mysql_field_seek() 把列光标放在一個指定的列上。

mysql_field_count() 傳回最近查詢的結果列的數量。

mysql_field_tell() 傳回用于最後一個mysql_fetch_field()的字段光标的位置。

mysql_free_result() 釋放一個結果集合使用的記憶體。

mysql_get_client_info() 傳回客戶版本資訊。

mysql_get_host_info() 傳回一個描述連接配接的字元串。

mysql_get_proto_info() 傳回連接配接使用的協定版本。

mysql_get_server_info() 傳回伺服器版本号。

mysql_info() 傳回關于最近執行得查詢的資訊。

mysql_init() 獲得或初始化一個MYSQL結構。

mysql_insert_id() 傳回有前一個查詢為一個AUTO_INCREMENT列生成的ID。

mysql_kill() 殺死一個給定的線程。

mysql_list_dbs() 傳回比對一個簡單的正規表達式的資料庫名。

mysql_list_fields() 傳回比對一個簡單的正規表達式的列名。

mysql_list_processes() 傳回目前伺服器線程的一張表。

mysql_list_tables() 傳回比對一個簡單的正規表達式的表名。

mysql_num_fields() 傳回一個結果集合重的列的數量。

mysql_num_rows() 傳回一個結果集合中的行的數量。

mysql_options() 設定對mysql_connect()的連接配接選項。

mysql_ping() 檢查對伺服器的連接配接是否正在工作,必要時重新連接配接。

mysql_query() 執行指定為一個空結尾的字元串的SQL查詢。

mysql_real_connect() 連接配接一個MySQL伺服器。

mysql_real_query() 執行指定為帶計數的字元串的SQL查詢。

mysql_reload() 告訴伺服器重裝授權表。

mysql_row_seek() 搜尋在結果集合中的行,使用從mysql_row_tell()傳回的值。

mysql_row_tell() 傳回行光标位置。

mysql_select_db() 連接配接一個資料庫。

mysql_shutdown() 關掉資料庫伺服器。

mysql_stat() 傳回作為字元串的伺服器狀态。

mysql_store_result() 檢索一個完整的結果集合給客戶。

mysql_thread_id() 傳回目前線程的ID。

mysql_use_result() 初始化一個一行一行地結果集合的檢索。