通过ODBC连接数据库(C++
    C++连接数据库的方法有很多种,在Visual C++和SQL server的实际开发中,一般使用ODBC或ADO技术进行开发,相关技术和产品也最为成熟。我们这里根据课程需要采用ODBC的方法。
    我使用的平台的是VS2010和SQL server 2008,优点是VS2010支持一些比较新的特性,编程方便了很多,缺点是左侧的“服务器资源管理器”不支持SQL server 2000,但是没有关系,在SQL server 2008上是可以连上的,大家如果和我的平台不一样的话在编程细节上可能有些问题要注意下。
有同学表示安装了SQL server 2008之后只能通过“windows 身份验证”登陆本地数据库,无法通过“SQL server 身份验证”登陆,这是由于安装的时候是通过“windows 身份验证”安装的,改一下配置即可:
1. 使用“windows 身份验证”登陆数据库,点击“登录名”,右击sa,选择属性,点击状
态,确保设置如左侧图所示。
2. 右击本地服务器名选择属性,更改安全性中的服务器身份验证如下图所示
3. 右击地服务器名选择重新启动(这一部很重要)
4. 如何还有问题的话查看目录D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Log 下的 ERRORLOG 文件,到错误代码,google
打开SQL server 2008 连接一个我们测试用的数据库,使用的10.214.6.98上的数据库db27,用户名和密码都是user277,执行以下命令:
use db27
CREATE Table book (
    bno        char(8) ,
    category    char(10) ,
    title        varchar(40) not null,
    press        varchar(30) not null,
    byear        int CHECK(byear > 0),
    author        varchar(20) not null,
    price        decimal(7,2) CHECK(price > 0),
    total        int CHECK(total >= 0),
    stock        int CHECK(stock >= 0),
    CONSTRAINT ck CHECK(stock <= total)
)
INSERT INTO book db2数据库sql语句VALUES
    ('12345678','数据库','数据库系统原理教程','清华大学出版社',1998,'王珊',27.9,3,0)
INSERT INTO book VALUES
    ('12342378','数据库','数据库','清华大学出版社',1998,'王珊',27.9,3,0)
INSERT INTO book VALUES
    ('12341278','数据库','数据库','清华大学出版社',1998,'王珊',27.9,3,0)
INSERT INTO book VALUES
    ('14345678','数据库','数据库','清华大学出版社',1998,'王珊',27.9,3,0)
    上面SQL语句执行的结果是在db27数据库中创建了一个名为book的表,里面有9列,随后添加了4个测试数据,现在将该数据源添加到ODBC数据源管理器中,打开路径“控制面板\所有控制面板项\管理工具”下的数据源(ODBC),添加新的数据源,选择SQL Server
名称设置为db27,服务器在10.214.6.98,使用user277用户登录,完成后点击测试数据源看能不能连上,显示测试成功后,在用户数据源中会看到刚刚添加的DSN:
我们编写一个简单的图形化界面,打开VS2010,新建项目,选择“MFC应用程序”,建立一个名为“DataBaseODBC”的项目,弹出的向导中更改应用程序类型为“基于对话框”,大家在实际编程中可以需要选择,这里只是为了做个示例,其他保持默认。点击工具箱中“List Control”空间,拖到面板中,完成之后应该是下图这个样子:
    调整控件的view属性为Report,如下图所示,控件的样式会有相应的改变。
    右击ListControl,添加变量,在对话框中输入名称,如m_ListCtrl
将这个ListControl设置成9列,并设置一些格式:
CRect rc;
m_ListCtrl.GetWindowRect(&rc);    //获取控件大小
//设置了9列,大小是一样的
m_ListCtrl.InsertColumn(0, _T("书号"), LVCFMT_CENTER, rc.Size().cx/9, 0);
m_ListCtrl.InsertColumn(1, _T("类别"), LVCFMT_CENTER, rc.Size().cx/9, 1);
m_ListCtrl.InsertColumn(2, _T("书名"), LVCFMT_CENTER, rc.Size().cx/9, 2);
m_ListCtrl.InsertColumn(3, _T("出版社"), LVCFMT_CENTER, rc.Size().cx/9, 3);
m_ListCtrl.InsertColumn(4, _T("出版年份"), LVCFMT_CENTER, rc.Size().cx/9, 4);
m_ListCtrl.InsertColumn(5, _T("作者"), LVCFMT_CENTER, rc.Size().cx/9, 5);
m_ListCtrl.InsertColumn(6, _T("价格"), LVCFMT_CENTER, rc.Size().cx/9, 6);
m_ListCtrl.InsertColumn(7, _T("总藏书量"), LVCFMT_CENTER, rc.Size().cx/9, 7);
m_ListCtrl.InsertColumn(8, _T("目前库存数"), LVCFMT_CENTER, rc.Size().cx/9, 8);
//LVS_EX_GRIDLINES是希望显示网格;
//LVS_EX_FULLROWSELECT是希望被选中时整行反显示;
//LVS_EX_HEADERDRAGDROP是让其支持点击表头排序;
//LVS_EX_TWOCLICKACTIVATE是希望有鼠标在未被选中的行上移动的时候有一些效果
m_ListCtrl.SetExtendedStyle(m_ListCtrl.GetExtendedStyle() | LVS_EX_GRIDLINES |
    LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_TWOCLICKACTIVATE);
把这些代码放在BOOL CDataBaseODBCDlg::OnInitDialog()函数的return前,运行就有相应的效果。
在头文件DataBaseODBCDlg.h中添加#include "afxdb.h""afxdb.h"即MFC的ODBC类包括以下要用到的类:
CDatabase类:主要功能是建立与数据源的连接。
CRecordset类:该类代表从数据源选择的一组记录(记录集),程序可以选择数据源中的某个表作为一个记录集,也可以通过对表的查询得到记录集,还可以合并同一数据源中多个表的列到一个记录集中.通过该类可对记录集中的记录进行滚动、修改、增加和删除等操作。
CDBException类:代表ODBC类产生的异常。
概括地讲,CDatabase针对某个数据库,它负责连接数据源;CRecordset针对数据源中的记录集,它负责对记录的操作。
在头文件中添加一些定义,其中CDBVariant对象表示用于MFC ODBC类的可变数据类型。
private:
    CDatabase m_db;
public:
    // CDBVariant转化成字符串
    CString VariantToCString(CDBVariant* var);
为了方便,我就不添加新的按钮,双击对话框的“确定”按钮,进入函数,注释掉里面的OnOK函数,添加如下代码:
//连接数据库,打开数据源,这里的DSN就是之前在ODBC中设置的DSN
if(!m_db.IsOpen() && !m_db.OpenEx(_T("DSN=db27;UID=user277;PWD=user277"),
        CDatabase::openReadOnly | CDatabase::noOdbcDialog))
{
    MessageBox(L"连接错误!");
    return;
}
//CRecordset类:代表从数据源选择一组记录(记录集)
CRecordset m_set(&m_db);
//Open方法打开记录集
m_set.Open(CRecordset::forwardOnly,_T("SELECT * from book"),
CRecordset::readOnly);
CDBVariant var; // 记录有数据的类型和数据的值,它封闭了VARIANT数据类型
m_ListCtrl.DeleteAllItems();    //删除所有的项目
short nFields = m_set.GetODBCFieldCount(); //得到列的数目
int i = 0;
//添加所有内容到控件
while(!m_set.IsEOF())
{
    for(short index = 0; index < nFields; index++)
    {
        m_set.GetFieldValue(index, var);
            // do something with varValue
        //添加一行记录
        if(index == 0)
            m_ListCtrl.InsertItem(i, VariantToCString(&var));
        //继续增加记录的其他项
        else
            m_ListCtrl.SetItemText(i, index, VariantToCString(&var));
    }
    m_set.MoveNext();
    i++;
}
m_set.Close();//凡打开
m_db.Close(); //皆关闭
VariantToCSting函数将CDBVariant对象转成CString,用以显示。
CString CDataBaseODBCDlg::VariantToCString(CDBVariant* var)
{
    CString str; //转换以后的字符串
    if(!var)
    {
        str = "NULL Var Parameter";
        return str;
    }
    switch(var->m_dwType)
    {
    case DBVT_SHORT:
        str.Format(L"%d",(int)var->m_iVal);
        break;
    case DBVT_LONG:
        str.Format(L"%d",var->m_lVal);
        break;
    case DBVT_SINGLE:
        str.Format(L"%10.6f",(double)var->m_fltVal);
        break;
    case DBVT_DOUBLE:
        str.Format(L"%10.6f",var->m_dblVal);
        break;
    case DBVT_BOOL:
        str = (var->m_boolVal==0) ?L"FALSE": L"TRUE";
        break;
    case DBVT_STRING:
        str = var->m_pstring->GetBuffer();
        break;
    case DBVT_ASTRING:
        str = var->m_pstringA->GetBuffer();
        break;
    case DBVT_WSTRING:
        str = var->m_pstringW->GetBuffer();
        break;
    case DBVT_DATE:        str.Format(L"%d-%d-%d",(var->m_pdate)->year,(var->m_pdate)->month,(var->m_pdate)->day);
        break;
    default:
        str.Format(L"Unk type %d\n",var->m_dwType);
        TRACE(L"Unknown type %d\n",var->m_dwType);
    }
    return str;
}
根据CDBVariant里的m_dwType属性可以知道里面的内容是什么类型的,然后对应的显示就OK了,其中DBVT_DATA属性可以根据需要自己更改格式。
至此,运行程序,点击“确定”按钮就能看到图示结果,可以完成查询工作了。
不妨再添加一个“button”控件用以添加记录,从工具集中拖一个button控件,双击标记代码:
void CDataBaseODBCDlg::OnBnClickedBtnadd()
{
    // TODO: 在此添加控件通知处理程序代码
    if(!m_db.IsOpen() && !m_db.OpenEx(_T("DSN=db27;UID=user277;PWD=user277"),
            CDatabase::openReadOnly | CDatabase::noOdbcDialog))
    {
        MessageBox(L"连接错误!");
        return;
    }
    try
    {
      m_db.ExecuteSQL(
          _T("INSERT INTO book VALUES")
          _T("('87654321','其他','其他1','浙江大学出版社',1984,'韩寒',12.9,4,2)"));
    }
    catch(CDBException* pe)
    {
      // The error code is in pe->m_nRetCode
      pe->ReportError();
      pe->Delete();
    }
    m_db.Close();
}
运行后,点击新添加的按钮可以增加一条记录。
再添加一个可以实现删除的button,双击之后添加代码如下。
POSITION pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (pos == NULL)
{
    TRACE(_T("No items were selected!\n"));
}
else
{
    while (pos)
    {
        //得到选中的item
        int nItem = m_ListCtrl.GetNextSelectedItem(pos);
        TRACE(_T("Item %d was selected!\n"), nItem);
        // you could do your own processing on nItem here
        // get item string
        CString bno = m_ListCtrl.GetItemText(nItem, 0);
        if(!m_db.IsOpen() && !m_db.OpenEx(_T("DSN=db27;UID=user277;PWD=user277"),
            CDatabase::openReadOnly | CDatabase::noOdbcDialog))
        {
            MessageBox(L"连接错误!");
            return;
        }
        try
        {
            CString sql;
            sql.Format(_T("DELETE FROM book WHERE bno = '%s'"),bno);
            m_db.ExecuteSQL(sql);
        }
        catch(CDBException* pe)
        {
            // The error code is in pe->m_nRetCode
            pe->ReportError();
            pe->Delete();
        }
        m_db.Close();
        //ListCtrl中删去所选item
        m_ListCtrl.DeleteItem(nItem);
    }
}
运行后,可以删除所选择的行,更新的操作类似。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。