引言 - 环境搭建

  首先开始环境搭建. 主要在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. Python数据定义

    数据类型: 什么是数据? 在计算机科学中,数据是指所有能输入到计算机并被计算机程序处理的符号的介质的总称,是用于输入电子计算机进行处理,具有一定意义的数字字母.符号和模拟量等的统称.现在计算机存储和处 ...

  2. html的body内标签之input系列1

    1. Form的作用:提交当前的表单. 类似于去了银行提交的纸质单子,递到后台去办理相关业务. text,password只有输入的功能:button,submit只有点击的功能.想要把这些信息提交, ...

  3. POJ3421:X-factor Chains——题解

    http://poj.org/problem?id=3421 题目大意:一个数列,起始为1,终止为一给定数X,满足Xi < Xi+1 并且Xi | Xi+1. 求出数列最大长度和该长度下的情况数 ...

  4. HDOJ.1257 最少拦截系统 (贪心)

    最少拦截系统 点我挑战题目 题意分析 一开始理解错了这道题.这么多个导弹排好序不只需要1个拦截系统吗.后来发现自己真傻.那出这个题还有啥意思,反正都需要一个.(:′⌒`) 给出n个导弹,这n个导弹的顺 ...

  5. maven打包jar源码至私服

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

  6. 如何使用Navicat连接Oracle

    1.Navicat连接Oracle,需要使用OCI库.因此先要安装Oracle提供的客户端instantclient-basic, 请注意,32位的Navicat需要下载配置32位的instantcl ...

  7. 工作中常用的Linux命令(不断更新中)

    最近工作中用到linux命令,简单总结如下: 1. pwd 查看当前所在的文件路径 2. cd 切换目录 cd .. 切换到上一级目录 3. ls 列出当前文件路径下的所有文件和文件夹 4. ll 是 ...

  8. Java Zip压缩

    1.压缩文件或整个目录 // ZipCompression.java import java.io.File;import java.io.FileInputStream;import java.io ...

  9. [技巧篇]07.JSON.parse() 和 JSON.stringify()

    JSON.parse() 用于从一个字符串中解析出json对象,如 var str = '{"name":"huangxiaojian","age&q ...

  10. 详解ListView加载网络图片的优化

    我们来了解一些ListView在加载大量网络图片的时候存在的常见问题: 1.性能问题,ListView的滑动有卡顿,不流畅,造成非常糟糕的用户体验. 2.图片的错位问题. 3.图片太大,加载Bitma ...