引言 - 环境搭建

  首先开始环境搭建. 主要在Window 10 + Visual Studio 2015 上构建使用 mariadb connector/c api 进行数据操作开发.

为什么选择在window上搭建开发环境呢? 最核考虑是 更 方便 看源码!!!

  记得以前也写过一个在ubuntu上mariadb api开发教程, 有兴趣也可以参照看一下, 数据库层api是一样的.

   c基础 mariadb处理简单案例 http://www.cnblogs.com/life2refuel/p/5574544.html

本文重点讲解

  1. MariaDB在window 环境上搭建.

  2. MariaDB Connector/C API 的 HelloWorld

  3. Blob数据的insert 和 select

OK, 那开始吧, 先介绍需要下载的资源种子
  1. MaraDB window  : https://mariadb.com/my_portal/download/mariadb-enterprise#windows


  2. MariaDB Connector/C Download https://mariadb.com/kb/en/mariadb/mariadb-connector-c/

  

有了这些资源, 开始解压和安装, 先弄mariadb的压缩包, 解压完毕之后是下面这样 . 我放在了E盘下.

再设置一下 Path变量 (window 10 Path变量设置如下图)

环境变量设置好了之后安装 Conector/C 库的安装包 , 安装完毕后在C盘, MaeiaDB文件夹路径下会遇到以下文件目录

现在基本软件和驱动都已经安装完毕了. 后面任务是让mariadb 服务启动起来, 打开管理员模式下的cmd窗口, 执行

:: 开启mariadb 服务, 需要管理员权限
mysqld.exe --install mariadb
net start mariadb

扩充一点, 对于暂停, 卸载, 删除 命令如下

:: 下面是停止,卸载,删除服务命令
net stop mariadb
mysqld.exe --remove mariadb
sc delete mariadb

是不是很简单, 按照上面做了之后, 基本上mariadb 服务就已经启动起来了(前提脸不黑, O(∩_∩)O哈哈~).

开始执行下面, sql脚本, 创建用户和构建测试数据表

mysql -uroot -p

-- 开始使用test数据库, 进行数据测试
use test;
create table tb_user (
id int unsigned not null auto_increment comment '员工编号',
name varchar(20) not null comment '员工姓名',
sex tinyint not null comment '员工性别, 0女士, 1男士, 其它扩展',
email varchar(30) not null comment '员工邮箱',
department varchar(50) not null comment '员工所在部门',
employtime int unsigned not null default 0 comment '入职时间',
salary int not null default 0 comment '员工工资',
ext blob comment '后期使用, 扩展数据', primary key(id)
) engine = innodb default charset = latin1; -- 为用户创建权限
-- 为 seluser 查询权限
-- 为 noruser 所用权限 -- 开始创建用户, 并刷新
create user 'seluser'@'localhost' identified by '7seluser';
create user 'noruser'@'localhost' identified by '7noruser';
flush privileges; -- 设置不同用户权限
grant select on test.* to 'seluser'@'localhost';
grant all on test.* to 'noruser'@'localhost';

创建了两个用户, seluser和noruser, 分别具有test数据库下面读权限和所有权限. 扯一点, 权限管理其实是软件开发中一个共性, 哪里都需要.

因为权限它是权力在虚拟系统中缩影. 后面说一下 ,为什么用 latin1不用 utf-8. 这也是个''坑'', 推荐看看下面资料.

  编码ascii latin1 utf8 简介 http://blog.sina.com.cn/s/blog_5edf2a9f0100sicm.html

这步完成后, 就能通过mariadb命令进行操作了, 如同下面操作内容. 最终软件环境就搭建完毕了.

前言 - 环境测试, 搭建HelloWorld Demo

目前可以开始着手编程开发了, 主要依赖的圣经是下面官网API Functions 说明.  我们所需要的一切都可以从下面内容中找见.

  MariaDB Connector/C API Functions  https://mariadb.com/kb/en/mariadb/mariadb-connectorc-api-functions/

那行, 打开VS, 创建控制台程序. 开始添加库目录, 头文件目录等.  参照下面流程先在项目中添加 引用目录

再添加静态库目录

再为此项目指定导入静态库文件

其实VS 项目管理最核心文件就是*.sln 和 *. vcxproj 文件.  例如打开其中一个文件, 看见下面的XML组织管理结构. 很清晰的看出VS 项目是如何管理引用, 资源等公有内容的.

以上完成后, 现在先写一个 HelloWorld的Demo  mariadb_heoo.c

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h> #define _STR_MHOST "localhost"
#define _STR_MUSER "seluser"
#define _STR_MPASSWD "7seluser"
#define _STR_MDB "test" static inline void _mysql_check(MYSQL * con) {
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(EXIT_FAILURE);
} /*
* 这里测试从mariadb 数据中拉取数据
* ip : localhost
* name : seluser
* passwd : 7seluser
*/
int main(int argc, char * argv[]) { // 创建数据连接对象, 需要和 mysql_close成对出现
MYSQL * con = mysql_init(NULL);
if (NULL == con) {
fputs("main mysql_init NULL == con! error !\n", stderr);
exit(EXIT_FAILURE);
} if (!mysql_real_connect(con, _STR_MHOST, _STR_MUSER, _STR_MPASSWD, _STR_MDB, , NULL, ))
_mysql_check(con); if (mysql_query(con, "show tables;"))
_mysql_check(con); puts("mariadb is connect and run succesed!"); /*
* 这里拉取数据
*/
MYSQL_RES * res = mysql_store_result(con);
if (NULL == res)
_mysql_check(con); MYSQL_ROW row;
unsigned rlen = mysql_num_fields(res);
printf("mariadb now row length = %u\n", rlen); // 打印行数据
while ((row = mysql_fetch_row(res))) {
for (unsigned i = ; i < rlen; ++i)
printf("%s ", row[i]);
putchar('\n');
} // 释放结果内存
mysql_free_result(res);
// 释放mysql客户端链接对象
mysql_close(con); getchar();
return ;
}

这个演示Demo 主要是拉取 show tables; 返回数据. 上面都是开发中套路, 参照注释, 代码容易明爱. 主要流程包括 初始化, 链接, 请求查询, 解析结果, 关闭.

当我们运行的时候, 还需要添加上动态库 libmariadb.dll

运行最终结果如下, 到这里基础Hello World就大功告成了.

正文 - 实战blob数据的insert and select

  很恭喜到了这里, 以上前戏基本完毕了. 这里先把前面一个关于 latin1一个坑补上. 这个坑造成原因是, 传统C/C++ 使用的是ascii码,

对于汉字转utf-8麻烦, 而latin1是对ascii码扩充, 所以汉字也能正常显示. 这也是很多老系统或框架在和DB交互的时候, 使用latin1编码的原因.

此刻开始blob 练习演示. 先简单回顾一下 mariadb中常用的数据类型, 了解blob是啥.

类  型         占用字节数     无符号数的取值范围         有符号数的取值范围
tinyint 1 0-255 -128-127
int 4 0-(2^32-1) -(2^32/2)-(2^32/2-1)
bigint 8 0-(2^64-1) -(2^64/2)-(2^64/2-1)
varchar 1-65535 类型的长度是可变,其取值范围为0-65535。
blob 65k 保存二进制数据

对于mariadb 的二进制blob类型 需要使用下面api构建 ,

unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql,
char *to,const char *from,
unsigned long length);

内部序列化成其内部保存的''串''. 那我们依赖test.workers表插入数据 . 首先定义对映的一种数据结构如下

#define _INT_WNAME        (63)
#define _INT_WEMAIL (127)
#define _INT_WDEPAR (255) // workers 扩展信息, 当做其另一半吧
struct workers_ext {
unsigned int id; // 唯一标识id
char name[_INT_WNAME + ]; // 姓名信息
}; // 对应数据库 test.workers 表内容
struct workers {
unsigned int id; // 唯一标识id
char name[_INT_WNAME + ]; // 姓名信息
char sex; // 0 女士, 1男士
char email[_INT_WEMAIL + ]; // 邮箱
char department[_INT_WDEPAR + ]; // 部门介绍
int salary; // 基本工资
struct workers_ext ext; // 扩展数据
};

这里struct workers_ext 结构就是对映test.workers 中 ext blob字段.  项目的业务例子参照 mariadb_insert.c

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <mysql.h> #define LEN(arr) (sizeof(arr) / sizeof(*(arr))) #define _STR_MHOST "localhost"
#define _STR_MUSER "noruser"
#define _STR_MPASSWD "7noruser"
#define _STR_MDB "test" static inline void _mysql_check(MYSQL * con) {
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(EXIT_FAILURE);
} #define _INT_WNAME (63)
#define _INT_WEMAIL (127)
#define _INT_WDEPAR (255) // workers 扩展信息, 当做其另一半吧
struct workers_ext {
unsigned int id; // 唯一标识id
char name[_INT_WNAME + ]; // 姓名信息
}; // 对应数据库 test.workers 表内容
struct workers {
unsigned int id; // 唯一标识id
char name[_INT_WNAME + ]; // 姓名信息
char sex; // 0 女士, 1男士
char email[_INT_WEMAIL + ]; // 邮箱
char department[_INT_WDEPAR + ]; // 部门介绍
int salary; // 基本工资
struct workers_ext ext; // 扩展数据
}; #define _INT_WINSERTSQL (6*1024) // 默认最大6k, 程序决定, 不是线程安全
// 得到最终insert 拼接的字符串
static void _workers_get_insertsql(MYSQL * con, struct workers * worker) {
char query[_INT_WINSERTSQL + ];
assert(con && worker); // 保存扩展数据, 2 * size + 1 是api规定的, 返回最终编码长度
char chunk[ * sizeof(struct workers_ext) + ];
mysql_real_escape_string(con, chunk, (const char *)&worker->ext, sizeof(struct workers_ext)); int len = snprintf(query, LEN(query),
"insert into workers(name, sex, email, department, salary, ext) "
"values('%s', %d, '%s', '%s', %d, '%s');",
worker->name,
worker->sex,
worker->email,
worker->department,
worker->salary,
chunk);
if (len > _INT_WINSERTSQL) {
fprintf(stderr, "_workers_get_insertsql snprintf len = %d is too long!\n", len);
return;
} // 这里可以插入到数据库
if (mysql_real_query(con, query, len))
_mysql_check(con);
} /*
* 这里测试写入复杂数据到mariadb中, 例如插入blob数据
*/
int mariadb_insert(int argc, char * argv[]) { // 创建数据连接对象, 需要和 mysql_close成对出现
MYSQL * con = mysql_init(NULL);
if (NULL == con) {
fputs("main mysql_init NULL == con! error !\n", stderr);
exit(EXIT_FAILURE);
}
// 开始创建TCP常连接对象
if (!mysql_real_connect(con, _STR_MHOST, _STR_MUSER, _STR_MPASSWD, _STR_MDB, , NULL, ))
_mysql_check(con); // 每次插入就只重置2条数据
if (mysql_query(con, "truncate table workers;"))
_mysql_check(con); struct workers workers[] = {
{ , "09.09 毛无敌诞辰", , "666666@666.com", "帝王大厦,长江口", -, { , "09.10 教师节快乐" } },
{ , "09.10 教师节快乐", , "55555@555.com", "各大地毯,松花江", , { , "09.09 毛无敌诞辰" } },
}; // 开始插入数据
for (int i = ; i < LEN(workers); ++i)
_workers_get_insertsql(con, workers + i); puts("mariadb localhost test.workers reset is succesed!"); // 释放mysql客户端链接对象
mysql_close(con); getchar();
return ;
}

上面演示中主要执行插入代码见 _workers_get_insertsql 函数, 完成sql语句的拼接, 和query查询操作. 最终的插入结果

一些正常, 通过上面例子学习, 觉得应该对于mariadb 的 connector/c 驱动 api 有点头绪了. 还是很容易理解的, 因为没有转弯的地方, 很直白.

O(∩_∩)O哈哈~

数据构建好了, 自然数据的查询也要有呢.  参照 mariadb_select.c

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <mysql.h> #define _STR_MHOST "localhost"
#define _STR_MUSER "seluser"
#define _STR_MPASSWD "7seluser"
#define _STR_MDB "test" static inline void _mysql_check(MYSQL * con) {
fprintf(stderr, "%s\n", mysql_error(con));
mysql_close(con);
exit(EXIT_FAILURE);
} #define _INT_WNAME (63)
#define _INT_WEMAIL (127)
#define _INT_WDEPAR (255) // workers 扩展信息, 当做其另一半吧
struct workers_ext {
unsigned id; // 唯一标识id
char name[_INT_WNAME + ]; // 姓名信息
}; // 对应数据库 test.workers 表内容
struct workers {
unsigned id; // 唯一标识id
char name[_INT_WNAME + ]; // 姓名信息
char sex; // 0 女士, 1男士
char email[_INT_WEMAIL + ]; // 邮箱
char department[_INT_WDEPAR + ]; // 部门介绍
unsigned employtime; // 入职时间
int salary; // 基本工资
struct workers_ext ext; // 扩展数据
}; /*
* 这里测试写入复杂数据到mariadb中, 例如插入blob数据
*/
int mariadb_select(int argc, char * argv[]) { // 创建数据连接对象, 需要和 mysql_close成对出现
MYSQL * con = mysql_init(NULL);
if (NULL == con) {
fputs("main mysql_init NULL == con! error !\n", stderr);
exit(EXIT_FAILURE);
}
// 开始创建TCP常连接对象
if (!mysql_real_connect(con, _STR_MHOST, _STR_MUSER, _STR_MPASSWD, _STR_MDB, , NULL, ))
_mysql_check(con); // 这里读取数据
if (mysql_query(con, "select * from workers;"))
_mysql_check(con); /*
* 这里拉取数据
*/
MYSQL_RES * res = mysql_store_result(con);
if (NULL == res)
_mysql_check(con); MYSQL_ROW row; // 打印行数据
while ((row = mysql_fetch_row(res))) {
// 得到各个列长度
unsigned long * clens = mysql_fetch_lengths(res);
if(NULL == clens)
_mysql_check(con); // 得到最后一个数据返回
struct workers worker;
worker.id = (unsigned)strtoul(row[], NULL, );
strcpy(worker.name, row[]);
worker.sex = (char)atoi(row[]);
strcpy(worker.email, row[]);
strcpy(worker.department, row[]);
worker.employtime = (unsigned)strtoul(row[], NULL, );
worker.salary = atoi(row[]);
memcpy(&worker.ext, row[], clens[]); // 简单打印数据
printf("{ %u, '%s', %d, '%s', '%s', %u, %d, { %u, '%s' } }\n",
worker.id, worker.name, worker.sex, worker.email,
worker.department, worker.employtime, worker.salary,
worker.ext.id, worker.ext.name);
} // 释放结果内存
mysql_free_result(res); // 释放mysql客户端链接对象
mysql_close(con); getchar();
return ;
}

简单说明一下 worker.id = (unsigned)strtoul(row[0], NULL, 0); 这行代码,  我们先看一下 strtoul 原型

_Check_return_
_ACRTIMP unsigned long __cdecl strtoul(
_In_z_ char const* _String,
_Out_opt_ _Deref_post_z_ char** _EndPtr,
_In_ int _Radix
);

返回值存在 unsigned, 这个很重要. 因为有符号和无符号数值之间转换存在符号位问题. 上面做法采用高精度的无符号转过来, 精度不损失.符号位不参与影响.

最终的效果如下

oh Yeah!

一切都搞定了, 通过这些步骤练习, 关于mariadb connector/c api funciton 基本操作, 还有如何打渔已经都有些眉目了.  以后那就看以后的复杂业务了.

遇到, 只需要多查查官网API说明就能迎刃而解. 当然最重要的还是勤思考, 多动手.

后记 - 如果还有明天, 你要怎样装扮你的脸

  错误是难免的,  发现会及时更正....

      Here We Are Again http://music.163.com/#/song?id=27876900

C中级 MariaDB Connector/C API 编程教程的更多相关文章

  1. 黑客编程教程(二)Win API编程简介

    第二节 Win API编程简介 下面介绍一下WIN API. 我们需要自己编写一个工具时,必然会用到很多操作windows和控制windows的函数,这些函数就是windows API. API是Ap ...

  2. DirectX API 编程起步 #01 项目设置

    =========================================================== 目录: DirectX API 编程起步 #02 窗口的诞生 DirectX A ...

  3. Flink Program Guide (2) -- 综述 (DataStream API编程指导 -- For Java)

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...

  4. 超全面的.NET GDI+图形图像编程教程

    本篇主题内容是.NET GDI+图形图像编程系列的教程,不要被这个滚动条吓到,为了查找方便,我没有分开写,上面加了目录了,而且很多都是源码和图片~ (*^_^*) 本人也为了学习深刻,另一方面也是为了 ...

  5. ASP.NET Web API系列教程目录

    ASP.NET Web API系列教程目录 Introduction:What's This New Web API?引子:新的Web API是什么? Chapter 1: Getting Start ...

  6. mariadb connector bug

    为了解决http://www.cnblogs.com/zhjh256/p/5807086.html的问题测试mariadb connector,常规的增删改查没有问题. 这货本来是为了解决存储过程bu ...

  7. Team Foundation API - 编程访问 WorkItem

    Team Foundation Server (TFS)工具的亮点之一是管理日常工作项, 工作项如Bug, Task,Task Case等. 使用TFS API编程访问TFS服务器中的工作项, 步骤如 ...

  8. IOS编程教程(八):在你的应用程序添加启动画面

    IOS编程教程(八):在你的应用程序添加启动画面   虽然你可能认为你需要编写闪屏的代码,苹果已经可以非常轻松地把它做在Xcode中.不需要任何编码.你只需要做的是设置一些配置. 什么是闪屏 对于那些 ...

  9. The MySQL C API 编程实例

    在网上找了一些MYSQL C API编程的文章,看了后认为还是写的不够充分,依据自己经验写了这篇<The MySQL C API 编程实例>,希望对须要调用到MYSQL的C的API的朋友有 ...

随机推荐

  1. 【bzoj2272】[Usaco2011 Feb]Cowlphabet 奶牛文字 dp

    题目描述 Like all bovines, Farmer John's cows speak the peculiar 'Cow'language. Like so many languages, ...

  2. WIN7系统插入蓝牙适配器经常断开问题

    WIN7 ACER笔记本一台,蓝牙耳机一个,10块钱的蓝牙适配器一个 目的:可以在笔记本上用适配器与蓝牙耳机匹配 出现问题:1.有2个图标,一会左边感叹号,一会右边感叹号,必须有个存在感叹号 解决:第 ...

  3. 如何区别java中的public,protected,default,private

    ================Public====================== 1>首先我们介绍public关键字,从字面意义上出发,public意为公共的,可见它的访问权限是很宽松的 ...

  4. maven打包jar源码至私服

    1. setting文件 配置私服中设置的用户和密码 <servers> <server> <id>releases</id> <username ...

  5. bnuoj25660 Two Famous Companies

    题目链接:https://www.bnuoj.com/v3/problem_show.php?pid=25660 这个二分真的是烧脑QAQ,想了一晚上才懂了一个大概. 首先,整体思路是二分,直观上感受 ...

  6. ssm项目,web容器无法初始化项目

    在web.xml中配置加载spring时,发现项目无法运行:而去掉spring的配置时,项目可以被初始化. 此时应考虑到spring的配置文件中存在错误,以至于web容器无法对项目成功初始化,在web ...

  7. [技巧篇]01.Servlet的优化模版代码

    Servlet.java的模版 #---------------------------------------------# # <aw:description>Template for ...

  8. defer与async的区别

    当浏览器碰到 script 脚本的时候: <script src="script.js"></script> 没有 defer 或 async,浏览器会立即 ...

  9. 常见一个新的maven web工程

    使用Eclipse创建一个新的maven Web应用工程,步骤如下: 1.在Elipse中新建一个maven工程,点击next: 2.选择工程路径(此处使用默认的),点击next: 3.选择Arche ...

  10. 数据结构:Rope

    以BZOJ1507为例,这里仅仅展示动态区间问题的一些典型操作,包括插入删除和修改,查询的话不支持按顺序查询 使用起来很简单很方便 #include<cstdio> #include< ...