背景
接触C++以来,因为之前学的java做Web时经常要和数据库打交道,所以也就一直想用C++来操作数据库。之前也听过ODBC数据源的方法听说比较麻烦,C++用ADO的方法连接数据比较方便。
下面就是具体的步骤和代码了。
1.导入ADO的库
使用ADO的话必须要导入它的库,这语句放到头文件.h中,因为我这里是用的MFC程序建的工程,所以我放在stdafx.h头文件中
//导入ADO的库 #import "C:\\Program Files\\Common Files\\System\\ado\\msado15.dll" no_namespace rename("EOF","adoEOF")文件msado15.dll可以在你的电脑中的相应路径C:\Program Files\Common Files\System\ado找到;no_namespace 表示没有命名空间,可以不写不过后面的ADO对象要加上ADODB::引入;rename("EOF","adoEOF")是用adoEOF替换EOF ,如果你用到BOF的话也可以通过这种方式替换。
2.在头文件中定义成员变量和成员函数
在AdoDlg.h文件中:
//定义变量 _ConnectionPtr m_conn; //连接智能指针 _RecordsetPtr m_rec;//记录集智能指针 HRESULT hr; // //列表控件变量 CListCtrl m_listCtrl; //函数 bool AdoOpen(char* userName,char* pwd,char* conStr,char* errStr); //连接数据库 //_RecordsetPtr AdoExucute(char* sqlStr); //执行sql语句,操作表 bool AdoClose();//关闭数据库 void InsertCol();//插入表头 void GetRecordSet();//获得记录集 void AdoQuery();//查询数据 bool AdoAdd();//增加数据 bool AdoUpdate();//修改数据 bool AdoDelete();//删除数据
3.在使用ADO前要初始化COM类库环境
在AdoDlg.cpp文件中:
a.在构造函数中初始化成员变量
m_conn=NULL;
b.在OnInitDialog()函数中
//初始化COM类库 //CoInitialize返回的是HRESULT类型的值,返回S_OK(值为0)表示COM初始化成功, // 返回S_FALSE(值为1)表示当前线程已经初始化过COM,所以返回S_OK或S_FALSE都是对的 /*if(FAILED(::CoInitialize(NULL))) { MessageBox("初始化COM库失败"); return FALSE; }*/ AfxOleInit();//MFC工程建议用AfxOleInit();//控制台建议用CoInitalize(),同时在Close函数或是析构函数中记得调用::CoUninitialize();卸载COM环境;
//MFC工程建议用AfxOleInit();就行了。
4.实现成员函数
a .建立与数据库的连接
//连接数据库 bool CAdoDBDlg:: AdoOpen(char* userName,char* pwd,char* conStr,char* errStr) { //捕获异常 try{ //创建Connection对象的一个实例 hr=m_conn.CreateInstance(_uuidof(Connection));///创建Connection对象 //通过用户名、密码以及连接字符串连接数据库 m_conn->Open(conStr,userName,pwd,NULL); }catch(_com_error e) { MessageBox(e.ErrorMessage()); } return TRUE; }
b.获得查询的结果集
//获取结果集 void CAdoDBDlg::GetRecordSet() { CString sql= "select * from MEMBERUSER"; //查询的SQL语句 try{ m_rec.CreateInstance(_uuidof(Recordset));//创建结果集对象 m_rec->Open(_bstr_t(sql),m_conn.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText); }catch(_com_error e) { MessageBox(e.Description()); } }aa. ADO中Recordset.Open()参数说明
C.也可通过Execute函数来获得结果集
//执行SQL语句 _RecordsetPtr CAdoDBDlg::AdoExucute(char* sqlStr) { try { if(m_conn==NULL) { MessageBox("请先连接数据库,再操作!"); return NULL; } _variant_t RecordsAffected;//此次操作的记录数 _RecordsetPtr PRecord; //通过sql语句操作数据库并返回结果集指针 PRecord=m_conn->Execute(_bstr_t(sqlStr),&RecordsAffected,adCmdText); /*int IntRecords = RecordsAffected.intVal; CString StrRecords="0"; StrRecords.Format("此次操作了 %d 条数据.",IntRecords); AfxMessageBox(StrRecords);*/ return PRecord; } catch (_com_error e) { MessageBox(e.ErrorMessage()); } }
D.关闭函数
//关闭数据库连接 bool CAdoDBDlg::AdoClose() { if(m_conn!=NULL) { m_conn->Close();//关闭连接 m_conn=NULL; m_rec->Close();//关闭结果集 m_rec=NULL; //::CoUninitialize();//卸载COM环境 } if(m_conn==NULL) return TRUE; else return FALSE; }
E.插入列表控件的表头和设置样式
我用的是CListCtrl控件来显示查询到的数据,因为之前做类似Windows任务管理器时就是用的列表控件来显示数据,所以第一就想到了用它来显示表中的数据。
//插入表头 void CAdoDBDlg::InsertCol() { //表的列名 CString szItem[]={("记录数"),_T("ID"),_T("MemberName"),_T("AccounterNumber"),_T("Age"),_T("Gender"),_T("Birthday"),_T("RoleName"),_T("Pwd"),_T("Integal")}; //设置列表控件的样式 LONG lStyle; lStyle= GetWindowLong(m_listCtrl.m_hWnd,GWL_STYLE);//获得列表控件的当前样式 lStyle &=~LVS_TYPEMASK; //清除显示方式位 lStyle |=LVS_REPORT; //设置view属性的值为Report SetWindowLong(m_listCtrl.m_hWnd,GWL_STYLE,lStyle); //设置扩展风格--网格 m_listCtrl.SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT); //设置列表控件的表头 int szLength = sizeof(szItem)/sizeof(szItem[0]);//求出数组长度 for (int i=0;i<szLength;i++) { m_listCtrl.InsertColumn(i,szItem[i],LVCFMT_RIGHT,70,-1);//向控件中插入表头 } }aa.遍历数据库中的所有表名和表的所有字段 第 6.7点
5.///////////////////////////////////////////////增删改查
a.查询
void CAdoDBDlg::AdoQuery() { //查询表中的数据 m_rec=AdoExucute("SELECT * FROM MEMBERUSER M;"); }
如果使用了GetRecordSet()方法这个函数可以不用,因为Recordset.Open(sql,.....)里面的sql语句就是查询表数据,就可以得到结果集
b.增加数据
//增加数据 bool CAdoDBDlg::AdoAdd() { if(m_conn==NULL) { MessageBox("数据库尚未连接,请连接后再操作!"); return FALSE; } CString strId1,strName,strAccounterName,strAge,strGender,strBirthday,strPwd,strIntegral,strRoleId; int strId=12; strName="中国人"; strAccounterName="zgr3"; strAge="100"; strGender="男"; //获取系统当前时间 SYSTEMTIME st = {0}; GetLocalTime(&st); strBirthday.Format("%d-%02d-%02d %02d:%02d:%02d",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond); strPwd="123456"; strIntegral="120"; strRoleId="2"; GetRecordSet();//获取记录集 if(m_rec!=NULL) { UpdateData(TRUE); for(int i=0;i<3;i++) { strAccounterName.Format("lyx%d",i);//主键唯一,防止重复 m_rec->AddNew(); m_rec->PutCollect(_variant_t("MEMBERID"),_variant_t((long)(strId+i))); <span style="font-family: Arial, Helvetica, sans-serif;">//主键唯一,防止重复</span> m_rec->PutCollect(_variant_t("MEMBERNAME"),_variant_t(strName)); m_rec->PutCollect(_variant_t("ACCOUNTNUMBER"),_variant_t(strAccounterName)); m_rec->PutCollect(_variant_t("AGE"),_variant_t(strAge)); m_rec->PutCollect(_variant_t("GENDER"),_variant_t(strGender)); m_rec->PutCollect(_variant_t("BIRTHDAY"),_variant_t(strBirthday)); m_rec->PutCollect(_variant_t("PWD"),_variant_t(strPwd)); m_rec->PutCollect(_variant_t("MEMBER_INTEGRAL"),_variant_t(strIntegral)); m_rec->PutCollect(_variant_t("ROLEID"),_variant_t(strRoleId)); } m_rec->Update(); return TRUE; }else { return FALSE; } }注意:
1.如果主键冲突就无法增加数据到数据库中,这个问题要注意,我就出现了这个问题,最后打断点运行才发现。
2.如果你有的字段没有插入,数据库为空,那就查询不出来,比如我因为生日日期类型之前没有想到如何处理,就直接把
m_rec->PutCollect(_variant_t("BIRTHDAY"),_variant_t(strBirthday));这句注释掉了,这样虽然可以正常插入到数据库中,但是当我点击查询按钮时,在数据库中这条数据及其以后的数据都无法在列表控件CListCtrl中显示出来。
c.删除数据
//删除数据 bool CAdoDBDlg::AdoDelete() { if(m_conn==NULL) { MessageBox("数据库尚未连接,请连接后再操作!"); return FALSE; } GetRecordSet(); int pos =m_listCtrl.GetSelectionMark();//获得当前选中列表项索引,获得第几条数据 try { m_rec->Move(long(pos),vtMissing);//移到指定的第几条数据 m_rec->Delete(adAffectCurrent);//删除当前影响的数据 m_rec->Update(); return TRUE; } catch (_com_error e) { MessageBox(e.Description()); return FALSE; } }
D.修改数据
//修改 bool CAdoDBDlg::AdoUpdate() { if(m_conn==NULL) { MessageBox("数据库尚未连接,请连接后再操作!"); return FALSE; } UpdateData(TRUE); GetRecordSet();//获取记录集 int pos =m_listCtrl.GetSelectionMark();//获得当前选中列表项索引 try{ m_rec->Move(long(pos),vtMissing);//移到指定条记录 m_rec->PutCollect(_variant_t("gender"),_variant_t("女"));//修改指定字段的值 m_rec->Update();//更新到数据库 return TRUE; }catch(_com_error e) { MessageBox(e.Description()); return FALSE; } }
6.响应按钮函数
//////////////////////////////////////按钮处理函数 //建立连接 void CAdoDBDlg::OnBnClickedBtnAdolink() { // TODO: Add your control notification handler code here if(m_conn==NULL) { ////删除列表控件中的所有记录 int ColNum=m_listCtrl.GetHeaderCtrl()->GetItemCount(); for(int i=ColNum;i>=0;i--) //注意要从后面向前面删除,从前往后删会删不干净 { m_listCtrl.DeleteColumn(i); } m_listCtrl.DeleteAllItems();//建立连接前删除控件内的所有数据 ////连接oracle数据库的连接字符串 CString connStr=""; connStr.Format("Provider=OraOLEDB.Oracle.1;User ID=%s;Password=%s;Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=%s)(PORT=%s))(CONNECT_DATA=(SERVICE_NAME=%s)));Persist Security Info=False",\ "XXX", "XXX", "127.0.0.1", "1521", "orcl");//User, Psw, Ip, Port, DataBaseName <span style="white-space:pre"> </span>// 上文 \ 表示连接上一行 bool isConn=FALSE; isConn=AdoOpen("XXX","XXX",(LPSTR)(LPCSTR)connStr,NULL);//建立连接 if(isConn) { MessageBox("连接oracle数据库成功!"); ////插入表头 InsertCol(); }else { MessageBox("无法和数据库建立连接!"); } } } //断开与数据库的连接 void CAdoDBDlg::OnBnClickedBtnAdobreak() { // TODO: Add your control notification handler code here if(AdoClose()) { MessageBox("数据库已断开连接!"); }else{ MessageBox("数据库断开失败!"); } } ////////////////////////////////////////////////////
//////////////////////////////////////////////////// //查询数据库 void CAdoDBDlg::OnBnClickedBtnQuery() { m_rec.CreateInstance(_uuidof(Recordset));//创建记录实例 m_listCtrl.DeleteAllItems();//查询前删除控件内的所有数据 //先求出表中一共有多少条数据 _RecordsetPtr recordSet; recordSet = AdoExucute("select count(*) from memberUser"); variant_t count=0; _variant_t index=long(0); count = recordSet->GetCollect(index);//获得查询到的结果中的值 int num = count.intVal;//转换成int类型 // TODO: Add your control notification handler code here //AdoQuery();//查询数据 GetRecordSet();//获取记录集 int RecordNum=0;//计数 while (!m_rec->adoEOF) { variant_t id,name,accounterNumber,age,gender,birthday,roleName,pwd,integral; for (int i=0;i<num;i++) { id= m_rec->GetCollect("memberId"); name = m_rec->GetCollect("MEMBERNAME"); accounterNumber=m_rec->GetCollect("ACCOUNTNUMBER"); age=m_rec->GetCollect("AGE"); gender=m_rec->GetCollect("GENDER"); birthday=m_rec->GetCollect("BIRTHDAY"); roleName=m_rec->GetCollect("ROLEID"); pwd=m_rec->GetCollect("PWD"); integral=m_rec->GetCollect("MEMBER_INTEGRAL"); CString strid,strname,straccounterNumber,strage,strgender,strbirthday,strroleName,strpwd,strintegral,strRecordNum; strid=(LPCSTR)_bstr_t(id); strname=(LPCSTR)_bstr_t(name); straccounterNumber=(LPCSTR)_bstr_t(accounterNumber); strage=(LPCSTR)_bstr_t(age); strgender=(LPCSTR)_bstr_t(gender); strbirthday=(LPCSTR)_bstr_t(birthday); strroleName=(LPCSTR)_bstr_t(roleName); strpwd=(LPCSTR)_bstr_t(pwd); strintegral=(LPCSTR)_bstr_t(integral); RecordNum++; strRecordNum.Format("%d",RecordNum); //插入数据 m_listCtrl.InsertItem(i,strRecordNum); m_listCtrl.SetItemText(i,1,strid); m_listCtrl.SetItemText(i,2,strname); m_listCtrl.SetItemText(i,3,straccounterNumber); m_listCtrl.SetItemText(i,4,strage); m_listCtrl.SetItemText(i,5,strgender); m_listCtrl.SetItemText(i,6,strbirthday); m_listCtrl.SetItemText(i,7,strroleName); m_listCtrl.SetItemText(i,8,strpwd); m_listCtrl.SetItemText(i,9,strintegral); m_rec->MoveNext(); } } //AdoClose();//关闭连接 } //删除 void CAdoDBDlg::OnBnClickedBtnDelete() { // TODO: Add your control notification handler code here if(AdoDelete()) { MessageBox("删除成功!"); }else { MessageBox("删除失败!"); } } //增加 void CAdoDBDlg::OnBnClickedBtnAdd() { // TODO: Add your control notification handler code here // CAddDataDlg m_AddDateDlg; //if(m_AddDateDlg) //m_AddDateDlg.DoModal(); if(AdoAdd()) { MessageBox("增加成功!"); }else { MessageBox("增加失败!"); } } //修改 void CAdoDBDlg::OnBnClickedBtnUpdate() { // TODO: Add your control notification handler code here if(AdoUpdate()) { MessageBox("更新成功!"); }else { MessageBox("更新失败!"); } }
7.效果界面
版权声明:本文为博主原创文章,未经博主允许不得转载。