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:

图中 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() 初始化一个一行一行地结果集合的检索。
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪的期许

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值