zoukankan      html  css  js  c++  java
  • 学会使用ODBC API

    学会使用ODBC API

      虽说以前也接触过一些数据库的应用,但是由于当时只是抱着非常浅显的数据库知识,做了一些SQL语句上的操作,安装-配置-连接这一系列的流程全是自己照着例子实现的,大概记住的也就是ODBC、ADO之类,也简单的理解了一下,当共享使用数据库时最好使用ODBC的方式,而本地的数据库就可以使用ADO。

      具体区别这些连接方式倒是就可以好好学习一下了:

      简单的来说,ODBC和ADO都是微软提供的数据库访问方式,ADO是一个COM组件,而ODBC则是一种标准的访问方式,结束了数据库访问和数据库相关的局面,只不过两者实现的不同,所以在不同应用的表象上不同罢了(不对的话请指出,只看了Wiki上的一点介绍,没有系统学习)。

    使用

      通过分析考虑到将来可能会采用共享数据库的方式,此外对于COM自己也不是很熟悉,所以还是使用ODBC的方式比较好,使用ODBC的方式就很多了,但是由于我并不是程序开发人员,现在负责维护,不大敢做大手术,所以就选择了ODBC API,这就相当于使用WINDOS API和MFC一样,虽然API复杂,但是相对自由很多。

      首先要在程序中添加几个依赖项

    #include <sql.h>
    #include <sqlext.h>
    #include <odbcinst.h>
    
    #pragma comment(lib,"odbc32.lib")
    #pragma comment(lib,"odbccp32.lib")

      前两个头文件分别代表基本的ODBC API和高级的ODBC API,最后一个好像是包含了更高级的API(暂时这么理解吧),一般用到前两个即可,odbc32.lib对应sql.h和sqlext.h,odbccp32.lib对应odbcinst.h。

      所有使用数据库的过程无非是这样一个流程:

      1. 想办法建立数据库的连接

      2. 想办法执行SQL语句,并使用结果

      3. 不用时关闭连接,以免下次访问报错

      对于像我这样不常用数据库的菜鸟来说,这样的方式足够完成我所面临的问题了,诸如互斥访问、分布式之类的问题还是暂时留给高手们考虑吧。

    建立数据库连接

      在我们要连接数据库的类中,或者全局变量下建立相关的变量

        SQLHENV m_hEnviroment;//数据库环境句柄,属于老大级别的
        SQLHDBC m_hDatabaseConnection;//数据库连接句柄,老大以后就是他了,有了他数据库就连接上了
        SQLHSTMT m_hStatement;//执行语句句柄,最终执行SQL于句的句柄

      使用ODBC API建立数据库连接分为3部分:申请环境句柄,使用环境句柄申请连接句柄、使用连接句柄连接数据库。

       /* 申请环境变量 */
        SQLRETURN l_uiReturn = SQLAllocHandle(SQL_HANDLE_ENV,NULL,&m_hEnviroment);
      //申请各种句柄都靠这个函数,参数1是要申请句柄的类型,参数2为申请该句柄依靠的句柄(老大没依靠,所以是NULL),申请结果在参数3中保存
      //返回值代表着执行的意义,如下面判断,SUCCESS_WITH_INFO相当于是警告,虽然成功了,但是可能有问题
    
      if (l_uiReturn != SQL_SUCCESS && l_uiReturn != SQL_SUCCESS_WITH_INFO)
        {
            return false;
        }
        
        SQLSetEnvAttr(m_hEnviroment,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3,SQL_IS_INTEGER);
    
        l_uiReturn = SQLAllocHandle(SQL_HANDLE_DBC,m_hEnviroment,&m_hDatabaseConnection);
        if (l_uiReturn != SQL_SUCCESS && l_uiReturn != SQL_SUCCESS_WITH_INFO)
        {
            return false;
        }
    
        SQLWCHAR * l_swcaDsnName = _T("");//数据源名称
        SQLWCHAR * l_swcaUserName = _T("");//用户名称
        SQLWCHAR * l_swcaPassWord = _T("");//密码
    
        l_uiReturn = SQLConnect(m_hDatabaseConnection,l_swcaDsnName,SQL_NTS
                                    ,l_swcaUserName,SQL_NTS
                                    ,l_swcaPassWord,SQL_NTS);
    
           if (l_uiReturn != SQL_SUCCESS && l_uiReturn != SQL_SUCCESS_WITH_INFO)
        {
            return false;
        }

    使用SQL语句

      /* 申请于句句柄 */
        SQLRETURN l_uiReturn = SQLAllocHandle(SQL_HANDLE_STMT,m_hDatabaseConnection,&m_hStatement);
        if (l_uiReturn != SQL_SUCCESS && l_uiReturn != SQL_SUCCESS_WITH_INFO)
        {
            return 0;
        }
        
        /* 构造SQL语句 */
        CString l_cstrSql;
        l_cstrSql.Format(_T("SELECT * FROM 数据表 "));
    
        /* 执行SQL语句 */
        l_uiReturn = SQLExecDirect(m_hStatement,l_cstrSql.GetBuffer(),SQL_NTS);
    
        if (l_uiReturn != SQL_SUCCESS && l_uiReturn != SQL_SUCCESS_WITH_INFO)
        {
            return 0;
        }
    
        /* 获得返回结果的行数 */
        SQLINTEGER l_siIdCount = 0;
        l_uiReturn = SQLRowCount(m_hStatement,&l_siIdCount);
    
        /* 开始读取结果 *///读取第一行时要调用,以后依次调用就可以下移行数,直到不返回SQL_SUCCESS
        l_uiReturn = SQLFetch(m_hStatement);
    
        if (l_uiReturn != SQL_SUCCESS && l_uiReturn != SQL_SUCCESS_WITH_INFO)
        {
            return 0;
        }
    
        SQLINTEGER l_siID;
        SQLINTEGER l_siIDLength = 0;
    
        /* 获得数据 */
        SQLGetData(m_hStatement,1,SQL_C_ULONG,&l_siID,0,&l_siIDLength);
        //参数1为执行语句的句柄,参数2为所要得到的数据位于的列数(SQL语句中),参数3为数据类型,这个比较多,需要看一下MSDN
        //参数4为保存的位置(地址),参数5为参数4可用的位置,既然参数3已设定为长整型,所以这里可使用0
        //参数6为实际返回的长度
    
        /* 释放语句句柄 */
        SQLFreeHandle(SQL_HANDLE_STMT,m_hStatement);

    断开连接

        SQLFreeHandle(SQL_HANDLE_STMT,m_hStatement);
        SQLFreeHandle(SQL_HANDLE_DBC,m_hDatabaseConnection);
        SQLFreeHandle(SQL_HANDLE_ENV,m_hEnviroment);

    后记:客户需求与实现方式的思考  

      客户来了新的需求-交换:当时的原型为,他们那里有一套嵌入式的系统负责从传感器上获得数据,他们也有一套相应的管理程序,但是但是那套管理程序缺乏显示效果,所以需要利用我们所做的系统进行显示。

      根据这个需求,我们(其实只有我一个人)进行了分析,当时客户提出的最好使用SOCKET变成来实现,按说这也是一个不错的主意,自由且不是很复杂,但是带来的后果就可能是以后如果各种交互多了以后,极难维护。所以觉得使用一个共同的数据库比较好,他们负责生成数据,我们负责读取并显示,这种好处是可以最大的运用程序的效率,不用总是考虑SOCKET能不能及时的接收到,而且责任分明,也方便维护,但是现在考虑这种方式的缺点就是,我们的代码有一定的重复,他们的客户端就有一些根据数据条件进行“分类”的意思,我们这边则要根据数据进行不同的显示效果。

  • 相关阅读:
    CAAnimation动画相关文章
    [源代码]List的增加与删除
    [原创]c# 类中 Collection 字段初始化的特殊之处
    c# 多数值区间判断是否有重叠
    将M个客服随机分配给N个客户
    c# IList.ToList()后更改元素值会不会影响原列表的值
    java单元测试之Mock静态方法
    java的Spring学习2- junit和mock
    java mybatis学习二
    java8 方法引用与lambda
  • 原文地址:https://www.cnblogs.com/Dageking/p/2957800.html
Copyright © 2011-2022 走看看