数据库编程技术

来源:互联网 发布:淘宝卖家云标签 编辑:程序博客网 时间:2024/05/23 10:45
★ODBC技术
ODBC驱动屏蔽了不同DBS的差异,提供统一的公共接口API来访问不同DB服务器上的数据。
其应用结构为:
      /ODBC应用程序(宿主语言+ODBC API)
 ODBC |  驱动程序管理器(上下桥梁)
 结构 |DBMS驱动程序
      \  数据源(上下桥梁)
       DBS


ODBC编程实例:
  Microsoft Developer Studio为大多数标准的数据库格式提供了32位ODBC驱动器。这些标准数据格式包括有:SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle以及Microsoft Text。如果用户希望使用其他数据格式,则需要安装相应的ODBC驱动器及DBMS。
  用户使用自己的DBMS数据库管理功能生成新的数据库模式后,就可以使用ODBC来登录数据源。对用户的应用程序来说,只要安装有驱动程序,就能注册很多不同的数据库。登录数据库的具体操作参见有关ODBC的联机帮助。 


  一、MFC提供的ODBC数据库类
  Visual C++的MFC基类库定义了几个数据库类。在利用ODBC编程时,经常要使用到 CDatabase(数据库类)、CRecordSet(记录集类)和CRecordView(可视记录集类)。
  CDatabase类对象提供了对数据源的连接,通过它可以对数据源进行操作。
  CRecordSet类对象提供了从数据源中提取出的记录集。CRecordSet对象通常用于两种形式:动态行集(dynasets)和快照集(snapshots)。动态行集能与其他用户所做的更改保持同步,快照集则是数据的一个静态视图。每种形式在记录集被打开时都提供一组记录,所不同的是,当在一个动态行集里滚动到一条记录时,由其他用户或应用程序中的其他记录集对该记录所做的更改会相应地显示出来。
  CRecordView类对象能以控件的形式显示数据库记录,这个视图是直接连到一个CRecordSet对象的表视图。
  二、应用ODBC编程
  应用Visual C++的AppWizard可以自动生成一个ODBC应用程序框架,步骤是:打开File菜单的New选项,选取Projects,填入工程名,选择MFC AppWizard (exe),然后按AppWizard的提示进行操作。
  当AppWizard询问是否包含数据库支持时,如果想读写数据库,那么选定Database view with file support;如果想访问数据库的信息而不想写回所做的改变,那么选定Database view without file support。
  选好数据库支持之后,Database Source 按钮会被激活,选中它去调用Data Options对话框。在Database Options对话框中会显示出已向ODBC注册的数据库资源,选定所要操作的数据库,如:Super_ES,单击OK后出现Select Database Tables对话框,其中列举了选中的数据库包含的全部表;选择要操作的表后,单击OK。在选定了数据库和数据表之后,就可以按照惯例继续进行AppWizard操作。
  特别需要指出的是:在生成的应用程序框架View类(如:CSuper_ESView)中,包含一个指向CSuper_ESSet对象的指针m_pSet,该指针由AppWizard建立,目的是在视表单和记录集之间建立联系,使得记录集中的查询结果能够很容易地在视表单上显示出来。
  要使程序与数据源建立联系,需用CDateBase::OpenEx()或CDatabase::Open()函数来进行初始化。数据库对象必须在使用它构造记录集对象之前初始化。
  三、实例
  1.查询记录
  查询记录使用CRecordSet::Open()和CRecordSet::Requery()成员函数。在使用CRecordSet类对象之前,必须使用CRecordSet::Open()函数来获得有效的记录集。一旦已经使用过CRecordSet::Open()函数,再次查询时就可以应用CRecordSet::Requery()函数。
  在调用CRecordSet::Open()函数时,如果将一个已经打开的CDatabase对象指针传给CRecordSet类对象的m_pDatabase成员变量,则使用该数据库对象建立ODBC连接;否则如果m_pDatabase为空指针,就新建一个CDatabase类对象,并使其与缺省的数据源相连,然后进行CRecordSet类对象的初始化。缺省数据源由GetDefaultConnect()函数获得。也可以提供所需要的SQL语句,并以它来调用CRecordSet::Open()函数,例如:Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);
  如果没有指定参数,程序则使用缺省的SQL语句,即对在GetDefaultSQL()函数中指定的SQL语句进行操作:
  CString CSuper_ESSet::GetDefaultSQL()
  {return _T("[BsicData],[MinSize]");}
  对于GetDefaultSQL()函数返回的表名,对应的缺省操作是SELECT语句,即:
  SELECT *FROM BasicData,MainSize
  在查询过程中,也可以利用CRecordSet的成员变量m_strFilter和m_strSort来执行条件查询和结果排序。m_strFilter为过滤字符串,存放着SQL语句中WHERE后的条件串;m_strSort为排序字符串,存放着SQL语句中ORDER BY后的字符串。如:
  Super_ESSet.m_strFilter="TYPE='电动机'";
  Super_ESSet.m_strSort="VOLTAGE";
  Super_ESSet.Requery();
  对应的SQL语句为:
  SELECT *FROM BasicData,MainSize
  WHERE TYPE='电动机'
  ORDER BY VOLTAGE
  除了直接赋值给m_strFilter以外,还可以使用参数化。利用参数化可以更直观、更方便地完成条件查询任务。使用参数化的步骤如下:
  S声明参变量:
  CString p1;
  float p2;
  S在构造函数中初始化参变量:
  p1=_T("");
  p2=0.0f;
  m_nParams=2;
  S将参变量与对应列绑定:
  pFX->SetFieldType(CFieldExchange::param)
  RFX_Text(pFX,_T("P1"),p1);
  RFX_Single(pFX,_T("P2"),p2);
  完成以上步骤后就可以利用参变量进行条件查询:
  m_pSet->m_strFilter="TYPE=? AND VOLTAGE=?";m_pSet->p1="电动机";
  m_pSet->p2=60.0;
  m_pSet->Requery();
  参变量的值按绑定的顺序替换查询字串中的“?”通配符。
  如果查询的结果是多条记录,可以用CRecordSet类的函数Move()、MoveNext()、MovePrev()、MoveFirst()和MoveLast()来移动光标。
  2.增加记录
  增加记录使用AddNew()函数,要求数据库必须是以允许增加的方式打开:
  m_pSet->AddNew(); //在表的末尾增加新记录
  m_pSet->SetFieldNull(&(m_pSet->m_type), FALSE);
  m_pSet->m_type="电动机";
  ……
  //输入新的字段值
  m_pSet->update();
  //将新记录存入数据库
  m_pSet->Requery();
  //重建记录集
  3.删除记录
  可以直接使用delete()函数来删除记录,并且在调用delete()函数之后不需调用update()函数:
  m_pSet->delete();
  if (!m_pSet->IsEOF())
  m_pSet->MoveNext();
  else
  m_pSet->MoveLast();
  4.修改记录
  修改记录使用Edit()函数:
  m_pSet->Edit();
  //修改当前记录
  m_pSet->m_type="发电机";
  //修改当前记录字段值
   ……
  m_pSet->update(); //将修改结果存入数据库
  m_pSet->Requery();
  5.撤消操作
  如果用户选择了增加或者修改记录后希望放弃当前操作,可以在调用update()函数之前调用:
  CRecordSet::Move(AFX_MOVE_REFRESH)来撤消增加或修改模式,并恢复在增加或修改模式之前的当前记录。其中,参数AFX_MOVE_REFRESH的值为零。
  6.数据库连接的复用
  在CRecordSet类中定义了一个成员变量m_pDatabase:
  CDatabase* m_pDatabase;
  它是指向对象数据库类的指针。如果在CRecordSet类对象调用Open()函数之前,将一个已经打开的CDatabase类对象指针传给m_pDatabase,就能共享相同的CDatabase类对象。如:
  CDatabase m_db;
  CRecordSet m_set1,m_set2;
  m_db.Open(_T("Super_ES")); //建立ODBC连接
  m_set1.m_pDatabase=&m_db;
  //m_set1复用m_db对象
  m_set2.m_pDatabse=&m_db;
  // m_set2复用m_db对象
  7.SQL语句的直接执行
  虽然我们可以通过CRecordSet类完成大多数的查询操作,而且在CRecordSet::Open()函数中也可以提供SQL语句,但是有时候我们还是希望进行一些其他操作,例如建立新表、删除表、建立新的字段等,这时就需要使用CDatabase类直接执行SQL语句的机制。通过调用CDatabase::ExecuteSQL()函数来完成SQL语句的直接执行:
  BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL)
  {TRY
  {m_pdb->ExecuteSQL(strSQL);
  //直接执行SQL语句}
  CATCH (CDBException,e)
  {CString strMsg;
  strMsg.LoadString(IDS_EXECUTE_SQL_FAILED);
  strMsg+=strSQL;
  return FALSE;}
  END_CATCH
  return TRUE;}
  应当指出的是,由于不同的DBMS提供的数据操作语句不尽相同,直接执行SQL语句可能会破坏软件的DBMS无关性,因此在应用中应当慎用此类操作。
  8.动态连接表
  表的动态连接可以利用在调用CRecordSet::Open()函数时指定SQL语句来实现。同一个记录集对象只能访问具有相同结构的表,否则查询结果将无法与变量相对应。
void CDB::ChangeTable()
{
 if (m_pSet->IsOpen()) m_pSet->Close();
 switch (m_id)
 {
  case 0:
   m_pSet->Open(AFX_DB_USE_DEFAULT_TYPE,"SELECT * FROM SLOT0");
   //连接表SLOT0
   m_id=1;
   break;
  case 1:
   m_pSet->Open(AFX_DB_USE_DEFAULT_TYPE,"SELECT * FROM SLOT1"); //连接表SLOT1
   m_id=0;
   break;
 }
}
  9.动态连接数据库
  可以通过赋与CRecordSet类对象参数m_pDatabase来连接不同数据库的CDatabase对象指针,从而实现动态连接数据库。
void CDB::ChangeConnect()
{
 CDatabase* pdb=m_pSet->m_pDatabase;
 pdb->Close();
 switch (m_id)
 {
  case 0:
   if (!pdb->Open(_T("Super_ES")))
    //连接数据源Super_ES
   {
    AfxMessageBox("数据源Super_ES打开失败","请检查相应的ODBC连接", MB_OK|MB_ICONWARNING);
    exit(0);
   }
   m_id=1;
   break;
  case 1:
   if (!pdb->Open(_T("Motor")))
   //连接数据源Motor
   {
    AfxMessageBox("数据源Motor打开失败","请检查相应的ODBC连接", MB_OK|MB_ICONWARNING);
    exit(0);
   }
   m_id=0;
   break;
 }
}
  总结:
  Visual C++中的ODBC类库可以帮助程序员完成绝大多数的数据库操作。利用ODBC技术使得程序员从具体的DBMS中解脱出来,从而可以减少软件开发的工作量,缩短开发周期,并提高效率和软件的可靠性。








★ADO技术
可以在系统配置在管理工具“数据源 (ODBC)”中建立新的DSN。也可以在程序中使用Adodc控件Microsoft ADO Data Control 6.0来生成一个数据源,然后可以像系统的DSN一样引用这个Adodc控件。第二种方法开发的程序不需要用户再配置“数据源 (ODBC)”就可以直接使用开发的程序。


在StdAfx.h文件的各行#include语句之后加入以下内容:
#import "c:\program files\common files\system\ado\msado15.dll"  \
            no_namespace  \
            rename("EOF","adoEOF")


数据库连接语句
AfxOleInit();
_ConnectionPtr pConn;
HRESULT hRes;


hRes=pConn.CreateInstance("ADODB.Connection");
pConn->ConnectionTimeout=8;
hRes=pConn->Open(_bstr_t("Data Source=DSN名;UID=sa;PWD=;"),"","",adModeUnknown);


建立表头
m_ctrlDisp.InsertColumn(0,"字段名1",LVCFMT_LEFT,100);
m_ctrlDisp.InsertColumn(1,"字段名2",LVCFMT_LEFT,100);
m_ctrlDisp.InsertColumn(2,"字段名3",LVCFMT_LEFT,100);


显示表的内容(执行SQL选择语句)
_RecordsetPtr pRecordset;
CString strSql("SQL选择语句");
HRESULT hTRes;
hTRes=pRecordset.CreateInstance("ADODB.Recordset");
if(SUCCEEDED(hTRes))
{
hTRes=pRecordset->Open((LPTSTR)strSql.GetBuffer(130),pConn.GetInterfacePtr(),adOpenDynamic,adLockPessimistic,adCmdText); //GetBuffer()函数是为了把CString类型转换为Char*类型
int i=0;


m_ctrlDisp.DeleteAllItems();


while(!(pRecordset->adoEOF))
{
m_ctrlDisp.InsertItem(i,_bstr_t(pRecordset->GetCollect("字段名1")));
m_ctrlDisp.SetItemText(i,1,_bstr_t(pRecordset->GetCollect("字段名2")));
m_ctrlDisp.SetItemText(i,2,_bstr_t(pRecordset->GetCollect("字段名3")));


i++;
pRecordset->MoveNext();
}
}
pRecordset->Close();


执行SQL插入,删除和更新语句
CString strSql("SQL语句");
pConn->Execute((_bstr_t)strSql,NULL,adCmdText);


执行插入和更新操作的另一种方法
CString strSql;
strSql="select * from 表名";
_RecordsetPtr m_pRecordset;
HRESULT hTRes;
hTRes=m_pRecordset.CreateInstance(_T("ADODB.Recordset"));
hTRes=m_pRecordset->Open((LPTSTR)strSql.GetBuffer(130),pConn.GetInterfacePtr(),adOpenDynamic,adLockPessimistic,adCmdText);
if(SUCCEEDED(hTRes))
{
m_pRecordset->AddNew();


m_pRecordset->PutCollect("字段名1",_variant_t(值1));
m_pRecordset->PutCollect("字段名2",_variant_t(值2));
m_pRecordset->PutCollect("字段名3",_variant_t(值3));


m_pRecordset->Update();
}
m_pRecordset->Close();




★MFC中使用DAO类访问access97格式数据库
头文件
#include <afxdao.h>


连接数据库
CDaoDatabase* m_pDatabase;
CDaoRecordset* m_pRecordset;
m_pDatabase=new CDaoDatabase;
m_pDatabase->Open("数据库文件名.mdb");
m_pRecordset=new CDaoRecordset(m_pDatabase);


读取表的字段信息
CDaoTableDef tableDef(m_pDatabase);
CDaoFieldInfo fieldInfo;
tableDef.Open("数据表名");
int nFields=tableDef.GetFieldCount();//返回字段个数
for(int j=0;j<nFields;j++)
{
tableDef.GetFieldInfo(j,fieldInfo);
fieldInfo.m_strName//得到字段名的字符串
}
tableDef.Close();


执行查询SQL语句
CString strSql("SQL查询语句");
m_pRecordset->Open(dbOpenDynaset,strSql);
while(!m_pRecordset->IsEOF())
{
COleVariant var;
for(i=0;i<nFields;i++)
{
var=m_pRecordset->GetFieldValue(i);
CString=strVARIANT(var);//把取到的值转化为CString类型
}
m_pRecordset->MoveNext();
}
m_pRecordset->Close();
//类型转换函数
CString strVARIANT(const COleVariant &var)
{
CString strRet;
strRet = _T("Fish");
switch(var.vt){
case VT_EMPTY:
case VT_NULL:
strRet = _T("NULL");
break;
case VT_I2:
strRet.Format(_T("%hd"),V_I2(&var));
break;
case VT_I4:
strRet.Format(_T("%d"),V_I4(&var));
break;
case VT_R4:
strRet.Format(_T("%0.2f"),(double)V_R4(&var));
break;
case VT_R8:
strRet.Format(_T("%e"),V_R8(&var));
break;
case VT_CY:
strRet = COleCurrency(var).Format();
break;
case VT_DATE:
strRet = COleDateTime(var).Format(_T("%y年%m月%d日"));
break;
case VT_BSTR:
strRet = V_BSTRT(&var);
break;
case VT_DISPATCH:
strRet = _T("VT_DISPATCH");
break;
case VT_ERROR:
strRet = _T("VT_ERROR");
break;
case VT_BOOL:
return (V_BOOL(&var))?_T("True"):_T("False");
case VT_VARIANT:
strRet = _T("VT_VARIANT");
break;
case VT_UNKNOWN:
strRet = _T("VT_UNKNOWN");
break;
case VT_I1:
strRet = _T("VT_I1");
break;
case VT_UI1:
strRet.Format(_T("0x%02hX"),(unsigned short)V_UI1(&var));
break;
case VT_UI2:
strRet = _T("VT_UI2");
break;
case VT_UI4:
strRet = _T("VT_UI4");
break;
case VT_I8:
strRet = _T("VT_I8");
break;
case VT_UI8:
strRet = _T("VT_UI8");
break;
case VT_INT:
strRet = _T("VT_INT");
break;
case VT_UINT:
strRet = _T("VT_UINT");
break;
case VT_VOID:
strRet = _T("VT_VOID");
break;
case VT_HRESULT:
strRet = _T("VT_HRESULT");
break;
case VT_PTR:
strRet = _T("VT_PTR");
break;
case VT_SAFEARRAY:
strRet = _T("VT_SAFEARRAY");
break;
case VT_CARRAY:
strRet = _T("VT_CARRAY");
break;
case VT_USERDEFINED:
strRet = _T("VT_USERDEFINED");
break;
case VT_LPSTR:
strRet = _T("VT_LPSTR");
break;
case VT_LPWSTR:
strRet = _T("VT_LPWSTR");
break;
case VT_FILETIME:
strRet = _T("VT_FILETIME");
break;
case VT_BLOB:
strRet = _T("VT_BLOB");
break;
case VT_STREAM:
strRet = _T("VT_STREAM");
break;
case VT_STORAGE:
strRet = _T("VT_STORAGE");
break;
case VT_STREAMED_OBJECT:
strRet = _T("VT_STREAMED_OBJECT");
break;
case VT_STORED_OBJECT:
strRet = _T("VT_STORED_OBJECT");
break;
case VT_BLOB_OBJECT:
strRet = _T("VT_BLOB_OBJECT");
break;
case VT_CF:
strRet = _T("VT_CF");
break;
case VT_CLSID:
strRet = _T("VT_CLSID");
break;
}
WORD vt = var.vt;
if(vt & VT_ARRAY){
vt = vt & ~VT_ARRAY;
strRet = _T("Array of ");
}
if(vt & VT_BYREF){
vt = vt & ~VT_BYREF;
strRet += _T("Pointer to ");
}
if(vt != var.vt){
switch(vt){
case VT_EMPTY:
strRet += _T("VT_EMPTY");
break;
case VT_NULL:
strRet += _T("VT_NULL");
break;
case VT_I2:
strRet += _T("VT_I2");
break;
case VT_I4:
strRet += _T("VT_I4");
break;
case VT_R4:
strRet += _T("VT_R4");
break;
case VT_R8:
strRet += _T("VT_R8");
break;
case VT_CY:
strRet += _T("VT_CY");
break;
case VT_DATE:
strRet += _T("VT_DATE");
break;
case VT_BSTR:
strRet += _T("VT_BSTR");
break;
case VT_DISPATCH:
strRet += _T("VT_DISPATCH");
break;
case VT_ERROR:
strRet += _T("VT_ERROR");
break;
case VT_BOOL:
strRet += _T("VT_BOOL");
break;
case VT_VARIANT:
strRet += _T("VT_VARIANT");
break;
case VT_UNKNOWN:
strRet += _T("VT_UNKNOWN");
break;
case VT_I1:
strRet += _T("VT_I1");
break;
case VT_UI1:
strRet += _T("VT_UI1");
break;
case VT_UI2:
strRet += _T("VT_UI2");
break;
case VT_UI4:
strRet += _T("VT_UI4");
break;
case VT_I8:
strRet += _T("VT_I8");
break;
case VT_UI8:
strRet += _T("VT_UI8");
break;
case VT_INT:
strRet += _T("VT_INT");
break;
case VT_UINT:
strRet += _T("VT_UINT");
break;
case VT_VOID:
strRet += _T("VT_VOID");
break;
case VT_HRESULT:
strRet += _T("VT_HRESULT");
break;
case VT_PTR:
strRet += _T("VT_PTR");
break;
case VT_SAFEARRAY:
strRet += _T("VT_SAFEARRAY");
break;
case VT_CARRAY:
strRet += _T("VT_CARRAY");
break;
case VT_USERDEFINED:
strRet += _T("VT_USERDEFINED");
break;
case VT_LPSTR:
strRet += _T("VT_LPSTR");
break;
case VT_LPWSTR:
strRet += _T("VT_LPWSTR");
break;
case VT_FILETIME:
strRet += _T("VT_FILETIME");
break;
case VT_BLOB:
strRet += _T("VT_BLOB");
break;
case VT_STREAM:
strRet += _T("VT_STREAM");
break;
case VT_STORAGE:
strRet += _T("VT_STORAGE");
break;
case VT_STREAMED_OBJECT:
strRet += _T("VT_STREAMED_OBJECT");
break;
case VT_STORED_OBJECT:
strRet += _T("VT_STORED_OBJECT");
break;
case VT_BLOB_OBJECT:
strRet += _T("VT_BLOB_OBJECT");
break;
case VT_CF:
strRet += _T("VT_CF");
break;
case VT_CLSID:
strRet += _T("VT_CLSID");
break;
}
}
return strRet;
}


执行删除,插入和更新的SQL操作
CString strSql("SQL删除,插入或更新语句");
m_pDatabase->Execute(strSql,dbDenyWrite|dbFailOnError);


其他注意事项:
1.access里时间日期的格式需要加#号。例如:#2008-01-02#
2.注意字段名不可以太一般,如果凑巧是access的保留字的话就会出现意外错误。比如字段名为date,则会在插入数据遇到意外错误。
3.数据库信息的显示一般使用“列表控件”,而且其属性中“样式”的“查看”需要选择“报告”
首先对控件添加CListCtrl类型的变量,其主要函数有:
.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES)
.DeleteAllItems()
while(对象名.DeleteColumn(0));
.GetStringWidth(字符串)
.InsertColumn(i,列名,LVCFMT_LEFT,宽度)
.SetColumnWidth(i,宽度)
.InsertItem(行i,元组label)
.SetItemText(行i,列j,值)
.Scroll(CSize值)
原创粉丝点击