
一、实验内容
以教科书第四章关于SQL语言相关内容为基础,课后查阅、自学ODBC接口有关内容,包括ODBC的体系结构、工作原理、数据访问过程、主要API接口的语法和使用方法等。
以实验二建立的学生数据库为基础,编写 C语言(或其它支持ODBC接口的高级程序设计语言) 数据库应用程序,按照如下步骤访问数据库
a)Step1. ODBC初始化,为ODBC分配环境句柄
b)Step2. 建立应用程序与ODBC数据源的连接
c)Step3. 利用SQLExecDirect语句,实现数据库应用程序对数据库的建立、查询、修改、删除等操作
d)Step4. 检索查询结果集
e)Step5. 结束数据库应用程序
二、实验要求
要求所编写的数据库访问应用程序中使用到以下主要的ODBC API函数:
(1)SQLALLocEnv:初始化ODBC环境,返回环境句柄
(2)SQLALLocConnect:为连接句柄分配内存并返回连接句柄
(3)SQLConnect:连接一个SQL数据资源
(4) SQLDriverConnect连接一个SQL数据资源,允许驱动器向用户询问信息
(5) SQLALLocStmt;为语句句柄分配内存, 并返回语句句柄
(6) SQLExecDirect 把SQL语句送到数据库服务器,请求执行由SQL语句定义的数据库访问
(7) SQLFetchAdvances将游标移动到到查询结果集的下一行(或第一行)
(8) SQLGetData 按照游标指向的位置,从查询结果集的特定的一列取回数据
(9) SQLFreeStmt释放与语句句柄相关的资源
(10) SQLDisconnect 切断连接
(11) SQLFreeConnect 释放与连接句柄相关的资源
(12) SQLFreeEnv ;释放与环境句柄相关的资源
三、实验环境
Windows 7系统
mysql数据库管理平台
visual studio C++编程平台(codeblocks或者devc++)
四、实验步骤
1、ODBC的体系结构、工作原理、数据访问过程、主要API接口的语法和使用方法等。
以实验二建立的学生数据库为基础,编写 C语言(或其它支持ODBC接口的高级程序设计语言) 数据库应用程序,按照如下步骤访问数据库。
a)Step1. ODBC初始化,为ODBC分配环境句柄
安装mysql-connector-odbc-5.3.4-winx
再转到系统DSN,点击“添加”,从“创建数据源”列表中选择刚安装的驱动。
b)Step2. 建立应用程序与ODBC数据源的连接。
DSN:数据源名称
用户DSN:对当前用户可见,只能用于当前计算机上的数据源。
系统DSN:对当前计算机上所有的用户可见,包括NT服务器。
文件DSN:可有安装了相同驱动程序的用户共享的数据源。
设置用户DSN,连接到本地mysql的数据库。
为了防止在程序运行后中文数据乱码,请将设置中的编码格式“character set”设置为gb2312.如下图:
连接成功。
c)Step3:配置VS环境:
1、新建一个工程,随便写一个helloworld,目的是就是让工程下的“debug”文件夹出现
2、把D:\\Program Files\\MySQL\\MySQL Server 5.6\\lib下面的libmysql.dll复制到工程的debug文件夹里面
3、接下来要设置一些引用文件的环境变量,首先,点击项目->属性->vc++目录。
然后“include目录”那把“C:\\Program Files\\MySQL\\MySQL Server 5.6 \\include”给加进来
再然后“lib目录”那里把“C:\\Program Files\\MySQL\\MySQL Server 5.6 \\lib”也一起加进来
d)Step4. 利用SQLExecDirect语句,实现数据库应用程序对数据库的建立、查询、修改、删除等操作、检索查询结果集。
实验代码:
#include #include #include"windows.h" #include"sql.h" #include"sqlext.h" #include"sqltypes.h" #include"odbcinst.h" #pragma comment(lib,"odbc32.lib") #pragma comment(lib, "libmysql.lib") struct course_cell { char cno[5]; char cname[20]; int lhour; int credit; char semester[5]; }; unsigned char sql_select[] = "select * from student.course"; //SQL查询语句 unsigned char sql_dolist[3][100] = { "insert into student.course values ('C06','数据库原理',48,3,'')", "update student.course set semester='#' where cno='C06'", "delete from student.course where cno='C06'" }; //插入、修改、删除语句 unsigned char do_name[3][10] = { "insert", "update", "delete" }; void show_course(HDBC hdbc) //显示course的内容 { HSTMT hstmt; RETCODE retcode; long lenOut1, lenOut2, lenOut3, lenOut4, lenOut5; struct course_cell* ccell; ccell = (struct course_cell*)malloc(sizeof(struct course_cell)); retcode = SQLAllocStmt(hdbc, &hstmt);//SQLALLocStmt;为语句句柄分配内存, 并返回语句句柄 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { //SQLBindCol将应用程序的数据缓冲绑定到结果集的各列 SQLBindCol(hstmt, 1, SQL_C_CHAR, ccell->cno, 5, &lenOut1);//将数 据缓冲绑定到结果集的列 SQLBindCol(hstmt, 2, SQL_C_CHAR, ccell->cname, 20, &lenOut2); SQLBindCol(hstmt, 3, SQL_C_SLONG, &ccell->lhour, sizeof(int), &lenOut3); SQLBindCol(hstmt, 4, SQL_C_SLONG, &ccell->credit, sizeof(int), &lenOut4); SQLBindCol(hstmt, 5, SQL_C_CHAR, ccell->semester, 5, &lenOut5); retcode = SQLExecDirect(hstmt,sql_select, SQL_NTS); //把SQL语句送到数据库服务器,请求执行由SQL语句定义的数据库访问 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { printf("student.course is as following:\\n"); printf ("************************************************************************\\n"); printf("cno cname lhour credit semester\\n"); retcode = SQLFetch(hstmt); /*SQLFetch fetches the next rowset of data from the result set and returns data for all bound columns. 相当与SQLFetchAdvances和SQLGetData两个函数*/ while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { printf("%-10s%-20s%-15d%-16d%-5s\\n", ccell->cno, ccell->cname, ccell->lhour, ccell->credit, ccell->semester); retcode = SQLFetch(hstmt); } printf ("*************************************************************************\\n \\n"); } } SQLFreeStmt(hstmt, SQL_DROP);//释放语句句柄 } int main() { HENV env; //定义环境句柄 HDBC hdbc; //定义链接句柄 HSTMT hstmt; //定义语句句柄 RETCODE retcode; retcode = SQLAllocEnv(&env); //初始化ODBC环境,返回环境句柄 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { retcode = SQLAllocConnect(env, &hdbc); //为连接句柄分配内存并返 回链接句柄 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { retcode = SQLConnect(hdbc, (SQLCHAR*)"mysql", SQL_NTS, (SQLCHAR*)"root", SQL_NTS, (SQLCHAR*)"", SQL_NTS); //连接一个SQL数据资料 if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { show_course(hdbc); //显示初始的course内容 for (int i = 0; i<3; i++) //依次执 行插入、修改、删除操作 { retcode = SQLAllocStmt(hdbc, &hstmt); //为语句句柄分配内存,并返回语句句柄 retcode = SQLExecDirect(hstmt, sql_dolist[i], SQL_NTS); //把SQL语句送到数据库服务器,请求执行由 SQL语句定义的数据库访问 printf("%s ", do_name[i]); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) printf("success!\\n"); else printf("fail!\\n"); SQLFreeStmt(hstmt, SQL_DROP); //释放与 语句句柄相关的资源 show_course(hdbc);//显示操作后的新course 内容 } SQLDisconnect(hdbc); //切断连接 } SQLFreeConnect(hdbc); //释放与连接句柄相关的资 } SQLFreeEnv(env); //释放与环境句柄相关的资源 } system("pause"); return 0; } 五、结果分析 对数据库的操作为: (1)"insert into student.course values('C06','数据库原理',48,3,'春')", (2)"update student.course set semester='#' where cno='C06'", (3)"delete from student.course where cno='C06" 代码中成功执行了查询、修改、删除等操作并打印了操作之后数据库的数据。 六、实验总结 遇到的错误1:“ error C26: “SQLBindCol”: 不能将参数 6 从“long *”转换为“SQLLEN *”。“ error C26: “SQLExecDirectW”: 不能将参数 2 从“unsigned char [100]”转换为“SQLWCHAR *””,解决的时候,可以直接将出错行的变量强制转换为“SQLLEN *”和“SQLWCHAR *”。 遇到的错误2:insert、delete、select全部failed。最后才发现,代码中的retcode = SQLConnect(hdbc, (SQLCHAR*)"mysql", SQL_NTS, (SQLCHAR*)"root", SQL_NTS, (SQLCHAR*)"", SQL_NTS); 连接数据库资料的时候,将数据源名“mysql”误写成了数据库的schema名“student”。 这次为了连接odbc,安装了mysql和VS2012,放弃了之前用的kingbase和codeblocks。因为在codeblocks中,我的配置一直有问题,连接不上mysql.h,各种方法尝试了,可是失败了(最后又成功了)。通过这次实验,我了解了通用数据库应用编程接口ODBC的基本原理和实现机制,并对MySQL中的ODBC的使用和ODBC接口的语法和函数等有了进一步的了解。使用odbc真的很方便,直接将要用的数据连接到程序中,增强了程序的可用性了呢。希望以后可以更加熟练地应用odbc到实践中。 附注:同样的实验,也可以在devc++里面做,直接把代码拷贝过去。像之前一样,配置用户dsn和系统dsn。Devc++配置只需要:tools->compiler->如下图。 完成之后,直接编译运行: 于是成功啦,就是这么简单!! 额,codeblocks也可以,也是和之前一样,配置好系统dsn和用户dsn。Codeblocks呢只要在settings->compiler->linker,如下图在link libraries添加include文件和lib文件的路径,并且在other linker options里面填写-lws2_32 –lodbc32. 把如上代码拷贝,运行: 所以,只要数据库连接成功,编译环境什么都可以的。
