Connector/C的使用
首先需要在mysql官网下载C接口库
解压指令
tar -zxvf 压缩包名
下载并解压好后
但是还有比这更优的做法。
这样子手动安装不仅麻烦,还可能存在兼容性的问题。
其实在我们使用yum安装mysql时,大概率会自动帮我们把其他的环境都安装下来并配置好
sudo yum install -y mysql-community-server
如果没有安装好,那么我们也可以单独安装
yum install myslq-devel
安装好后,查看
ls /usr/include/mysql
可以看到头文件就都在默认的搜索目录下了
那么我们就可以开始写代码了,注意包含头文件的方式
简单使用
#include <iostream>
#include <mysql/mysql.h>int main()
{printf("mysql client Version: %s\n", mysql_get_client_info());return 0;
}
makefile
test:test.ccg++ -o $@ $^ -std=c++11 -L/lib64/mysql -lmysqlclient.PHONY:cleanclean:rm -f test
编译指令记得指明库所在的位置以及指明需要链接哪个库
-I(大写的i),在编译时可以告诉g++我们的头文件位置在哪里,这样的话我们包头文件可以直接包。
运行结果
ldd ./test
可以查看这个程序链接了那些库
用C_C++进行增删改
首先我们需要创建一个MYSQL对象,并对它进行初始化,并在不用的时候记得释放。
然后因为mysql是网络服务(基于TCP/IP的)。因此我们需要先链接
链接接口的使用:
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 clientflag);//后两个字段可以设置为nullptr和0//建立好链接之后,获取英文没有问题,如果获取中文是乱码:
//设置链接的默认字符集是utf8,原始默认是latin1
mysql_set_character_set(myfd, "utf8");
示例:
#include <iostream>
#include <string>
#include <mysql/mysql.h>
#include <unistd.h>const std::string host = "127.0.0.1";
const std::string user = "chika";
const std::string password = "3412741074";
const std::string db = "test_db";
const int port = 3306;int main()
{//printf("mysql client Version: %s\n", mysql_get_client_info());MYSQL* my = mysql_init(nullptr);if(nullptr == my){std::cerr << "init MYSQL error" << std::endl;return 1;}if(mysql_real_connect(my,host.c_str(),user.c_str(),password.c_str(),db.c_str(),port,nullptr,0) == nullptr){std::cerr << "mysql connect error" << std::endl;return 2;}std::cout<< "mysql connect success" << std::endl;sleep(5);mysql_close(my);return 0;
}
记得事先将自己的mysql服务启动。另外ip地址我们用的是本地环回地址,如果是本地链接,也可以改为 "localhost" 。
在mysql这边,我们可以用
show processlist;
来查看当前mysql的链接情况。
首先我们先在本地mysql上创建一张测试表
create table test(id int primary key auto_increment,name varchar(25) not null,qq varchar(30));
mysql_query()可以向mysql使其执行增删改查操作。
int mysql_query(MYSQL *mysql, const char *query);
第一个参数就是我们创建的mysql对象,第二个参数就是我们将要执行的命令。并且,这个命名是可以不带 ; 的。
成功返回0,失败返回非0值。
比如我们插入一条数据
#include <iostream>
#include <string>
#include <mysql/mysql.h>
#include <unistd.h>const std::string host = "127.0.0.1";
const std::string user = "chika";
const std::string password = "3412741074";
const std::string db = "test_db";
const int port = 3306;int main()
{//printf("mysql client Version: %s\n", mysql_get_client_info());MYSQL* my = mysql_init(nullptr);if(nullptr == my){std::cerr << "init MYSQL error" << std::endl;return 1;}if(mysql_real_connect(my,host.c_str(),user.c_str(),password.c_str(),db.c_str(),port,nullptr,0) == nullptr){std::cerr << "mysql connect error" << std::endl;return 2;}//设置好utf8编码,防止中文乱码mysql_set_character_set(my, "utf8");std::string sql = "insert into test1 (name,qq) values('李三光','123456')";int n = mysql_query(my,sql.c_str());if(n == 0) std::cout << "success" << std::endl;else std::cout << "sql error" << std::endl;mysql_close(my);return 0;
}
makefile
test:test.ccg++ -o $@ $^ -std=c++11 -L/lib64/mysql -lmysqlclient.PHONY:clean
clean:rm -f test
编译并执行后
此时看看表中的数据
发现成功的插入进来了。
那么删除和修改也是同一个道理,就不重复演示了。
另外增删改是最简单的,因为我们只需要看到执行结果就可以了。但是查询是最复杂的,我们不仅要确保执行成功,还要将结果打印出来,处理比较麻烦。
查询的细节
前面说了,我们查询的话,还需要将结果打印出来,那么这个结果其实是保存在第一个参数,也就是那个结构体里面的。
此时还需要用到一个函数
mysql_store_result()
MYSQL_RES *mysql_store_result(MYSQL *mysql);
获取结果行数mysql_num_rows
my_ulonglong mysql_num_rows(MYSQL_RES *res);
获取结果列数mysql_num_fields
unsigned int mysql_num_fields(MYSQL_RES *res);
获取列名mysql_fetch_fields
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);
示例:
int fields = mysql_num_fields(res);
MYSQL_FIELD *field = mysql_fetch_fields(res);
int i = 0;
for(; i < fields; i++){
cout<<field[i].name<<" ";
}
cout<<endl;
接着就是要获取表的内容信息,并打印出来
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
它会返回一个MYSQL_ROW变量,MYSQL_ROW其实就是char **.就当成一个二维数组来用吧。
示例:
i = 0;
MYSQL_ROW line;
for(; i < nums; i++){
line = mysql_fetch_row(res);
int j = 0;
for(; j < fields; j++){
cout<<line[j]<<" ";
}
cout<<endl;
}
在mysql中,我们每次查询出来的结果都是一个表结构,但这其实是被处理过后的结果。每次查询,mysql会先将所有的数据读取出来后,转化成字符串。
所以MYSQL_RES可以想象成一个三维数组,没一行代表的是表中的每一行信息。
每一个元素就是一个char**,它们又指向了char*,char*则最终指向了该表中某行某列的结果。
这个是跟表的内容相关的。
MYSQL_FIELD跟表的属性相关,它也是一个结构体。
在我们使用完了这个结果集之后,记得将其free掉。
mysql_free_result()
函数就是这些API函数之一,其主要用途是释放一个MYSQL_RES
结构所占用的内存。
void mysql_free_result(MYSQL_RES *result);
浅谈一下mysql连接池
我们知道mysql是网络服务,那么其他客户端想让mysql执行命令时需要先进行链接,为了提高效率,我们可以创建一个连接池,连接池里面有多个线程,每一个线程管理着一个mysql对象(已连接好mysqld的),然后循环等待任务。然后用户想进行操作时,就只需要打包一个task任务结构体,交给连接池,连接池把这个任务放在队列里面,让空闲的线程取走,把里面的sql交给musql执行。就是生产者消费者模型。这样就避免了每次sql都要重新建立链接的操作。
另外关于查询,在task结构体里面可以设置一个回调函数,如果这是一个查询sql,那么可以通过这个回调函数把结果拿回来,这个回调函数是由用户这边设置好的。