c/c++操作数据库:odbc和数据库API
一、Mysql
1.1 数据库安装和样本制造
环境:ubuntu18.04.6
镜像名:ubuntu-18.04.6-desktop-amd64.iso
使用:Vmware Workstation中搭建虚拟机
1.1.1 数据库安装
安装:https://www.bbsmax.com/A/B0zqqmMGzv/
sudo apt-get install mysql-server mysql-client
连接信息:root/123456,密码修改可参照下面。
查看版本,命令输入
mysql -V
结果:mysql Ver 14.14 Distrib 5.7.41, for Linux (x86_64) using EditLine wrapper
为mysql5.7版本
1.1.2 样本制造
数据库名:test
数据库表名:accounts
数据库表结构:name+passwd
终端登录:mysql -u root -p
创建数据库:create database test;
选择数据库:use test;
创建数据库表:create table accounts(name char(20) not null primary key,passwd char(20) not null);
退出:exit;
增加数据:
手动:
INSERT accounts values('fengxin','123');
INSERT accounts values('axin','456');
或用下面的函数
通过终端连接数据库查看内容:select * from accounts;
1.2 odbc连接配置
https://blog.csdn.net/u014257954/article/details/78525100
步骤:
1. 安装unixODBC和soci
2. 然后配置odbc manager和odbc driver
3. c++代码访问
1.2.1 unixodbc:apt-get
参考:
https://blog.csdn.net/TheThree_body/article/details/125011951
https://blog.csdn.net/MrTsai_cpp/article/details/116674570
https://www.cnblogs.com/yoyotl/p/9980269.html
1.安装unixodbc
# odbc管理工具
sudo apt-get install unixodbc
# odbc开发包
sudo apt-get install unixodbc-dev
2.查看安装信息
odbcinst -j
结果显示如下:
root@lym-virtual-machine:~# odbcinst -j
unixODBC 2.3.4
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /root/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8
# 查看版本信息
isql --v
odbc有两个配置文件:安装后在/etc底下
- odbc.ini : ODBC数据源的配置文件
- odbcinst.ini : ODBC的驱动配置文件
3.安装数据库
sudo apt-get install mysql-server mysql-client
4.安装mysql的odbc驱动
输入命令(apt-get install libmyodbc)--无用:软件包 libmyodbc 没有可安装候选
改为手动下载安装:
官网地址:https://dev.mysql.com/downloads/connector/odbc/
查看安装机器版本:
输入:uname -a
结果:Linux lym-virtual-machine 5.4.0-135-generic #152~18.04.2-Ubuntu SMP Tue Nov 29 08:23:49 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
根据系统版本选择odbc的ubuntu18.04,x86,64bit版本
四个deb包全部下载,通过以下命令依次安装(可能中途会安装有问题,不用管)
提示缺少依赖,需要提前安装以下包
# mysql-community-client-plugins,下载目录:https://dev.mysql.com/downloads/mysql/
# 下载mysql-community-client-plugins_8.0.32-1ubuntu18.04_amd64.deb,执行以下命令安装
dpkg -i mysql-community-client-plugins_8.0.32-1ubuntu18.04_amd64.deb
安装顺序如下
dpkg -i mysql-connector-odbc_8.0.32-1ubuntu18.04_amd64.deb
dpkg -i mysql-connector-odbc-setup_8.0.32-1ubuntu18.04_amd64.deb
dpkg -i mysql-connector-odbc-dbgsym_8.0.32-1ubuntu18.04_amd64.deb
dpkg -i mysql-connector-odbc-setup-dbgsym_8.0.32-1ubuntu18.04_amd64.deb
5.使用配置文件进行测试
vim /etc/odbc.ini,注意每个前后或中间不要有多余的空格或空白符,俺深受其害
[mysql]
Description=Data source MySQL
Driver=MySQL ODBC 8.0 Unicode Driver
Server=localhost
Host=localhost
Database=test
Port=3306
User=root
Password=123456
# 123456 #数据库登录密码
# CHARSET=UTF8
# OPTION=67108864
输入命令,出现以下内容为成功连接,至此安装和配置成功。
lym@lym-virtual-machine:/root$ isql mysql -v
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL>
若未成功连接,错误排查如下
root@lym-virtual-machine:~# isql mysql
[ISQL]ERROR: Could not SQLConnect
出现错误:无法连接
排查:
1、输入isql -v mysql,-v设置显示调试信息,mysql对应/etc/odbc.ini配置的[]中的信息,出现
[IM002][unixODBC][Driver Manager]Data source name not found, and no default driver specified
[ISQL]ERROR: Could not SQLConnect
解决:将/etc/odbc.ini中的空格注释掉之后,未出现驱动找不到,出现Access denied:
[S1000][unixODBC][MySQL][ODBC 8.0(w) Driver]Access denied for user 'root'@'localhost'
[ISQL]ERROR: Could not SQLConnect
注释:Data source name not found, and no default driver specified此报错一般是驱动Driver的值选项设置有问题
2、针对上面的访问被拒绝问题:
尝试:尝试在终端用普通用户登录,输入密码123456,依然是访问被拒绝,说明密码有误,需更改密码
lym@lym-virtual-machine:/root$ mysql -u root -p
Enter password:
ERROR 1698 (28000): Access denied for user 'root'@'localhost'
原因:安装新版本mysql,root密码是随机的,也不是空密码,所以要通过查看随机密码进入,再进行修改原来的密码
设置:参照https://blog.csdn.net/m0_70885101/article/details/127414184
普通用户修改修改密码见下部分
修改密码后;能够成功连接,如下
lym@lym-virtual-machine:/root$ isql mysql -v
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL>
【普通用户修改密码】
(1)使用其他用户登录MySQL终端
命令:sudo cat /etc/mysql/debian.cnf
结果:
# Automatically generated for Debian scripts. DO NOT TOUCH!
[client]
host = localhost
user = debian-sys-maint
password = adFIjhVxAoYeMWOJ
socket = /var/run/mysqld/mysqld.sock
[mysql_upgrade]
host = localhost
user = debian-sys-maint
password = adFIjhVxAoYeMWOJ
socket = /var/run/mysqld/mysqld.sock
登录:使用[mysql_upgrade]下的host和user登录,mysql -u debian-sys-maint -p,输入密码adFIjhVxAoYeMWOJ
(2)操作用户表
切换数据库:use mysql;
查看user表:select user,plugin from user;
结果:
Database changed
mysql> select user,plugin from user;
+------------------+-----------------------+
| user | plugin |
+------------------+-----------------------+
| root | auth_socket |
| mysql.session | mysql_native_password |
| mysql.sys | mysql_native_password |
| debian-sys-maint | mysql_native_password |
+------------------+-----------------------+
设置:此时root的plugin为auth_socket,需修改密码格式
(3)修改密码格式
update user set plugin='mysql_native_password' where user='root'; # 修改其密码格式
select user,plugin from user; # 查询其用户
flush privileges; #注意刷新权限
结果:
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select user,plugin from user;
+------------------+-----------------------+
| user | plugin |
+------------------+-----------------------+
| root | mysql_native_password |
| mysql.session | mysql_native_password |
| mysql.sys | mysql_native_password |
| debian-sys-maint | mysql_native_password |
+------------------+-----------------------+
(4)增加root密码
alter user 'root'@'localhost' identified by '123456'; #123456为我上设置的密码
flush privileges; #再次刷新权限
exit #退出登录
(5)重启mysql服务
service mysql restart
(6)root登录输入密码,成功
mysql -u root -p
6.C测试代码
代码参考:
https://blog.51cto.com/lhrbest/5110107?b=totalstatistic
使用:
①ODBCAPI中的常用数据类型与我们在 C 语言中使用的数据类型的对应关系
②相关API函数
/*************************************************************************
> File Name:odbctest.c
> Function:testing unixODBC
> Author:
> Mail:
> Created Time:2023年04月10日 星期一 14时08分01秒
************************************************************************/
#include <stdlib.h>
#include <stdio.h>
// #include <odbc/sql.h>
// #include <odbc/sqlext.h>
// #include <odbc/sqltypes.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
SQLHENV V_OD_Env; // Handle ODBC environment:odbc环境句柄,通过调用SQLAllocHandle获取有关的odbc环境信息
SQLHDBC V_OD_hdbc; // Handle connection:数据库连接句柄,存放数据库连接信息,调用SQLAllocHandle获得连接句柄
SQLHSTMT V_OD_hstmt; // Handle SQL:sql语句句柄,存放SQL语句信息,调用SQLAllocHandle获取句柄
long V_OD_erg; // result of functions:函数返回值
SQLLEN v_OD_len; // 数据库查询字段值返沪长度
char V_OD_name[32], V_OD_keyw[32]; // 存储查询结果
SQLSMALLINT V_OD_colanz; // 查询结果列数
SQLLEN V_OD_rowanz; // 查询结果条数
SQLINTEGER V_OD_err; //存放错误信息的编号
unsigned char V_OD_stat[10]; // Status SQL
SQLSMALLINT V_OD_mlen;
unsigned char V_OD_msg[200];
// 获取DNS信息
void OD_ListDSN()
{
unsigned char l_dsn[100], l_desc[100];
short int l_len1, l_len2, l_next;
l_next = SQL_FETCH_FIRST;
while(SQLDataSources(V_OD_Env, l_next, l_dsn, sizeof(l_dsn), &l_len1, l_desc, sizeof(l_desc), &l_len2) == SQL_SUCCESS)
{
printf("Server=(%s) Beschreibung=(%s)\n", l_dsn, l_desc);
l_next = SQL_FETCH_NEXT;
}
}
int main(int argc,char *argv[])
{
// 1. allocate Environment handle and register version:设置odbc环境句柄并设置参数
// 获取odbc环境变量句柄V_OD_Env
V_OD_erg = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &V_OD_Env);
if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
{
printf("Error AllocHandle\n");
exit(0);
}
// 对odbc环境句柄V_OD_Env设定所用的odbc版本:SQL_ATTR_ODBC_VERSION-版本号,SQL_OV_ODBC3-odbc3.0
V_OD_erg = SQLSetEnvAttr(V_OD_Env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
{
printf("Error SetEnv\n");
SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
exit(0);
}
// 获取DSN
printf("DSN_begin:\n");
OD_ListDSN();
printf("DSN_end :\n");
// 2. allocate connection handle, set timeout:设定连接句柄并设置超时参数
// 获取连接句柄V_OD_hdbc,入参环境变量句柄
V_OD_erg = SQLAllocHandle(SQL_HANDLE_DBC, V_OD_Env, &V_OD_hdbc);
if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
{
printf("Error AllocHDB %ld\n", V_OD_erg);
SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
exit(0);
}
// 对数据库连接句柄设置超时参数
SQLSetConnectAttr(V_OD_hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);
// 3. Connect to the datasource "test":连接数据库
// 连接数据库,需要设置数据库名称、用户名和密码,SQL_NTS-让SQLConnect决定参数长度,也可自定义,mysql需要提前在配置文件/etc/odbc.ini配置好
V_OD_erg = SQLConnect(V_OD_hdbc, (SQLCHAR*) "mysql", SQL_NTS,
(SQLCHAR*) "root", SQL_NTS,
(SQLCHAR*) "123456", SQL_NTS);
if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
{
printf("Error SQLConnect %ld\n", V_OD_erg);
// SQLRETURN SQLGetDiagRec(
// SQLSMALLINT HandleType,
// SQLHANDLE Handle,
// SQLSMALLINT RecNumber,
// SQLCHAR * SQLState,
// SQLINTEGER * NativeErrorPtr,
// SQLCHAR * MessageText,
// SQLSMALLINT BufferLength,
// SQLSMALLINT * TextLengthPtr);
// 返回包含错误、警告和状态信息的诊断记录的多个字段的当前值
SQLGetDiagRec(SQL_HANDLE_DBC, V_OD_hdbc, 1, V_OD_stat, &V_OD_err, V_OD_msg, 100, &V_OD_mlen);
printf("%s (%d)\n",V_OD_msg,V_OD_err);
SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
exit(0);
}
printf("Connected !\n");
// 4. 分配 SQL语句的句柄并进行查询
// 获取SQL语句句柄
V_OD_erg = SQLAllocHandle(SQL_HANDLE_STMT, V_OD_hdbc, &V_OD_hstmt);
if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
{
printf("Fehler im AllocStatement %ld\n", V_OD_erg);
SQLGetDiagRec(SQL_HANDLE_DBC, V_OD_hdbc,1, V_OD_stat, &V_OD_err, V_OD_msg, 100, &V_OD_mlen);
printf("%s (%d)\n", V_OD_msg, V_OD_err);
SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
exit(0);
}
// 把查询结果和我们定义的变量进行绑定,V_OD_err-存放错误信息编号的变量
SQLBindCol(V_OD_hstmt, 1, SQL_C_CHAR, &V_OD_name, 32, &v_OD_len);
SQLBindCol(V_OD_hstmt, 2, SQL_C_CHAR, &V_OD_keyw, 32, &v_OD_len);
// 查询
V_OD_erg = SQLExecDirect(V_OD_hstmt, (unsigned char *)"SELECT * from accounts;", SQL_NTS);
if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
{
printf("Error in Select %ld\n", V_OD_erg);
SQLGetDiagRec(SQL_HANDLE_DBC, V_OD_hdbc,1, V_OD_stat,&V_OD_err,V_OD_msg,100,&V_OD_mlen);
printf("%s (%d)\n",V_OD_msg,V_OD_err);
SQLFreeHandle(SQL_HANDLE_STMT,V_OD_hstmt);
SQLFreeHandle(SQL_HANDLE_DBC,V_OD_hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
exit(0);
}
// 获取列数,SQLSMALLINT
V_OD_erg = SQLNumResultCols(V_OD_hstmt, &V_OD_colanz);
if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
{
SQLFreeHandle(SQL_HANDLE_STMT, V_OD_hstmt);
SQLDisconnect(V_OD_hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, V_OD_hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
exit(0);
}
printf("Number of Columns %d\n",V_OD_colanz);
// 获取条数,SQLINTEGER
V_OD_erg = SQLRowCount(V_OD_hstmt, &V_OD_rowanz);
if ((V_OD_erg != SQL_SUCCESS) && (V_OD_erg != SQL_SUCCESS_WITH_INFO))
{
printf("Number of RowCount %ld\n", V_OD_erg);
SQLFreeHandle(SQL_HANDLE_STMT, V_OD_hstmt);
SQLDisconnect(V_OD_hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, V_OD_hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
exit(0);
}
printf("Number of Rows %ld\n", V_OD_rowanz);
// 获得第一条结果也可以用来都下一条
V_OD_erg = SQLFetch(V_OD_hstmt);
while(V_OD_erg != SQL_NO_DATA)
{
printf("Result: %s %s\n", V_OD_name, V_OD_keyw);
V_OD_erg=SQLFetch(V_OD_hstmt);
}
// 5. 关闭连接和释放句柄:具有一定的顺序性
// 5.1 释放SQL语句句柄
SQLFreeHandle(SQL_HANDLE_STMT, V_OD_hstmt);
// 5.2 关闭数据库连接
SQLDisconnect(V_OD_hdbc);
// 5.3 释放连接句柄和ODBC环境句柄
SQLFreeHandle(SQL_HANDLE_DBC, V_OD_hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, V_OD_Env);
return(0);
}
编译命令:
g++ odbctest.c -o odbctest -lodbc
1.3 mysql自己的C API
参考:
①连接:https://blog.csdn.net/m0_67391518/article/details/124290613
②API文档:https://dev.mysql.com/doc/refman/5.7/en/c-api-functions.html
1.3.1 安装和使用:apt-get
1.安装依赖
安装MYSQL数据库:mysql-client和mysql-server
安装MYSQL的开发包:mysql-devel
# 安装MYSQL:https://www.bbsmax.com/A/B0zqqmMGzv/
apt-get install mysql-server
apt-get install mysql-client
# 安装开发包
sudo yum install mysql-devel
sudo apt-get install libmysqld-dev
# 使用
加上<mysql/mysql.h>头文件
# 查看版本
mysql --version
2.使用
使用mysql_init()初始化连接
使用mysql_real_connect()建立一个到mysql数据库的连接
使用mysql_query()执行查询语句
result = mysql_store_result(mysql)获取结果集
mysql_num_fields(result)获取查询的列数,mysql_num_rows(result)获取结果集的行数
通过mysql_fetch_row(result)不断获取下一行,然后循环输出
释放结果集所占内存mysql_free_result(result)
mysql_close(conn)关闭连接
3.示例
代码参考:https://blog.csdn.net/m0_67391518/article/details/124290613
/*************************************************************************
> File Name: mydb.h
> Author:
> Mail:
> Created Time: 2017年07月21日 星期五 15时17分17秒
************************************************************************/
#ifndef _MYDB_H
#define _MYDB_H
#include<iostream>
#include<string>
#include<mysql/mysql.h>
using namespace std;
class MyDB
{
public:
MyDB();
~MyDB();
bool initDB(string host,string user,string pwd,string db_name); //连接mysql
bool exeSQL(string sql); //执行sql语句
private:
MYSQL *mysql; //连接mysql句柄指针
MYSQL_RES *result; //指向查询结果的指针
MYSQL_ROW row; //按行返回的查询信息
};
#endif
/*************************************************************************
> File Name: MyDB.cpp
> Author:
> Mail:
> Created Time: 2017年07月21日 星期五 16时02分51秒
************************************************************************/
#include<iostream>
#include<string>
#include "MyDB.h"
using namespace std;
MyDB::MyDB()
{
mysql=mysql_init(NULL); //初始化数据库连接变量
if(mysql==NULL)
{
cout<<"Error:"<<mysql_error(mysql);
exit(1);
}
}
MyDB::~MyDB()
{
if(mysql!=NULL) //关闭数据连接
{
mysql_close(mysql);
}
}
bool MyDB::initDB(string host,string user,string passwd,string db_name)
{
// 函数mysql_real_connect建立一个数据库连接
// 成功返回MYSQL*连接句柄,失败返回NULL
mysql = mysql_real_connect(mysql, host.c_str(), user.c_str(), passwd.c_str(), db_name.c_str(), 0, NULL, 0);
if(mysql == NULL)
{
cout << "Error: " << mysql_error(mysql);
exit(1);
}
return true;
}
bool MyDB::exeSQL(string sql)
{
//mysql_query()执行成功返回0,执行失败返回非0值。
if (mysql_query(mysql,sql.c_str()))
{
cout<<"Query Error: "<<mysql_error(mysql);
return false;
}
else // 查询成功
{
result = mysql_store_result(mysql); //获取结果集
if (result) // 返回了结果集
{
int num_fields = mysql_num_fields(result); //获取结果集中总共的字段数,即列数
int num_rows=mysql_num_rows(result); //获取结果集中总共的行数
for(int i=0;i<num_rows;i++) //输出每一行
{
//获取下一行数据
row=mysql_fetch_row(result);
if(row<0) break;
for(int j=0;j<num_fields;j++) //输出每一字段
{
cout<<row[j]<<" ";
}
cout<<endl;
}
}
else // result==NULL
{
if(mysql_field_count(mysql) == 0) //代表执行的是update,insert,delete类的非查询语句
{
// (it was not a SELECT)
int num_rows = mysql_affected_rows(mysql); //返回update,insert,delete影响的行数
}
else // error
{
cout<<"Get result error: "<<mysql_error(mysql);
return false;
}
}
}
return true;
}
test.cpp
/*************************************************************************
> File Name: test.cpp
> Author:
> Mail:
> Created Time: 2017年07月21日 星期五 16时43分55秒
************************************************************************/
#include<iostream>
#include"MyDB.h"
using namespace std;
int main()
{
MyDB db;
//连接数据库
db.initDB("localhost","root","fengxin","test");
//将用户信息添加到数据库
//db.exeSQL("INSERT accounts values('fengxin','123');");
//db.exeSQL("INSERT accounts values('axin','456');");
//将所有用户信息读出,并输出。
db.exeSQL("SELECT * from accounts;");
return 0;
}
命令行编译编译
g++ MyDB.cpp test.cpp -o test `mysql_config --cflags --libs`
或Makefile编译
test:test.cpp MyDB.cpp
g++ test.cpp MyDB.cpp -o test `mysql_config --cflags --libs`
本文来自博客园,作者:circlelll,转载请注明原文链接:https://www.cnblogs.com/circlelll/articles/17303131.html

浙公网安备 33010602011771号