ODBC是个老古董,现抛弃之,改为使用 ADO。
在此提醒自己,在要实现任何一个功能之前,应该先充分了解所有实现路径,谨慎选择,以免干了一段时间后才又恍然发现,有更好的方法。
ADO 花了一个早上终于连接并执行数据库操作了,当然花这么多时间,和自己对 vs 的文件夹管理不熟悉有关,在不必要的事情上徒徒浪费时间。
长个记性,头文件、源文件最好还是放在生成的筛选器中,然后加入附加包含目录即可,别搞有的没的。
(另外提醒,在手动 update 数据库时,最好做好备份,千万别把 where 条件弄错了)
参考:
ADO在C++中的使用_阿珊境界-CSDN博客_c++ado
ADO 连接
1.需要包含头文件 icrsint.h,其中有用到的宏 官方例子(实际自己写可有可无):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 _COM_SMARTPTR_TYPEDEF(IADORecordBinding, __uuidof(IADORecordBinding)); class CCustomRs : public CADORecordBinding { BEGIN_ADO_BINDING (CCustomRs) ADO_VARIABLE_LENGTH_ENTRY2 (2 , adVarChar, m_ch_fname, sizeof (m_ch_fname), m_ul_fnameStatus, false ) ADO_VARIABLE_LENGTH_ENTRY2 (4 , adVarChar, m_ch_lname, sizeof (m_ch_lname), m_ul_lnameStatus, false ) END_ADO_BINDING () public : CHAR m_ch_fname[22 ]; CHAR m_ch_lname[32 ]; ULONG m_ul_fnameStatus; ULONG m_ul_lnameStatus; }; inline void TESTHR (HRESULT _hr) { if FAILED (_hr) _com_issue_error (_hr) ; }
2.引入文件 msado15.dll 1 #import "msado15.dll" no_namespace rename("EOF" , "EndOfFile" )
该文件在目录 C:\Program Files\Common Files\System\ado
下可以找到,最好把它搬到工程目录下使用,不同系统版本可能不同no_namespace 是指忽略命名空间,rename 则是把ADO 中的EOF 重命名为adoEOF 。命成什么名字无所谓,但注意声明中的名字要和代码中的名字一致。
3.报错:无法打开源文件 msado15.tlh
新生成工程
调整配置管理器,选择 x64 或 x86
4.初始化 初始化:CoInitialize(NULL);
卸载:CoUninitialize();
5.实例化 新建 x.udl,双击配置连接数据库,测试成功后,文本形式打开,文本内容正常为 Provider=SQLOLEDB.1;Persist Security Info=False;User ID=xx;Password=xxxxx;Initial Catalog=DB;Data Source=IP
,其中 Password是后加的。
两个方法,推荐第 2 种,方法1 我把握不住。测试时,一开始用方法1还好好的,不知道搞了什么,后面就不能正常查询了。
方法1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 _RecordsetPtr pRs ("ADODB.Recordset" ) ; CCustomRs rs; IADORecordBindingPtr picRs (pRs) ; pRs->Open (L"SELECT * FROM [DCWLW].[dbo].[center]" , L"Provider = SQLOLEDB.1; Persist Security Info = False; User ID = xxx; Password = xxxxx; Initial Catalog = DB; Data Source = IP" , adOpenStatic, adLockOptimistic, adCmdText); TESTHR (picRs->BindToRecordset (&rs)); while (!pRs->EndOfFile) { printf ("Name = %s %s\n" , (rs.m_ul_fnameStatus == adFldOK ? rs.m_ch_fname : "<Error>" ), (rs.m_ul_lnameStatus == adFldOK ? rs.m_ch_lname : "<Error>" )); pRs->MoveNext (); }
方法2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 _ConnectionPtr pConn (__uuidof(Connection)) ; _RecordsetPtr pRec (__uuidof(Recordset)) ; _CommandPtr pCmd (__uuidof(Command)) ; pConn.CreateInstance ("ADODB.Connection" ); pRec.CreateInstance ("ADODB.Recordset" ); pCmd.CreateInstance ("ADODB.Command" ); pConn->ConnectionString = "Provider=SQLOLEDB.1;Persist Security Info=False;User ID=xx;Password=xxxxx;Initial Catalog=DB;Data Source=IP" ; pConn->Open ("" , "" , "" , adConnectUnspecified); const char * strSQL = "SELECT\ [report_5001_id]\ , [report_str]\ , isnull(row_state, 'good') as row_state\ , [create_date]\ , [barcode]\ , [states]\ , [dy]\ , [dl]\ , [wdmax]\ , [wdmin]\ , [soc]\ , [err_str]\ , [err_str2]\ , [err_str3]\ , [err_str4]\ FROM[DCWLW].[dbo].[report_5001]\ where cast([dl] as decimal) > 50.0 and create_date > '2021'" ; pRec = pConn->Execute (_bstr_t (strSQL), NULL , adCmdText); while (!pRec->EndOfFile) { string str = LPSTR (_bstr_t (pRec->GetCollect ("barcode" ))); cout << str << endl; pRec->MoveNext (); } pRec->Close (); pConn->Close (); pRec.Release (); pCmd.Release (); pConn.Release ();
6.错误捕获 1 2 3 4 5 6 7 8 9 try { ... }catch (_com_error& e) { printf ("Error:\n" ); printf ("Code = %08lx\n" , e.Error ()); printf ("Meaning = %s\n" , e.ErrorMessage ()); printf ("Source = %s\n" , (LPCSTR)e.Source ()); printf ("Description = %s\n" , (LPCSTR)e.Description ()); }