zoukankan      html  css  js  c++  java
  • MFC中使用ADO的记录集

     ADO是ActiveX Data Objects

    参考:https://blog.csdn.net/xzsfg6825/article/details/80047946

    记录集的open()方法的原型是这样的:

          HRESULT Recordset15::Open ( const _variant_t & Source, const _variant_t & ActiveConnection,enum CursorTypeEnum CursorType, enum LockTypeEnum LockType, long Options )

    使用方法:_RecordsetPtr m_Rs = NULL; m_Rs->Open(...);

    Execute 方法可执行指定查询、SQL 语句、存储过程或提供者特有的文本。返回的 Recordset 对象始终是只读的、仅向前的游标。
    CString sql = "select * from test_tb";
    m_Rs = theApp.m_pCon->Execute((_bstr_t)sql,NULL,adCmdText);返回的 Recordset 对象始终是只读的、仅向前的游标。不能使用MoveLast()和MovePrevious(),可以使用MoveNext()。
    CString sql = "delete from test_tb where id=0";
    theApp.m_pCon->Execute((_bstr_t)sql,NULL,adCmdText);

    CursorTypeEnum
    {
    adOpenUnspecified = -1,
    adOpenForwardOnly = 0,
    adOpenKeyset = 1,
    adOpenDynamic = 2,
    adOpenStatic = 3
    };

    (1)静态记录集:当前用户打开记录集后,记录集就保持不变一直到关闭后再次打开它。在这过程中如果数据库中的相应记录发生改变,在当前用户是看不到的。

        adOpenForwardOpnly——光标只能向前移动,它仅支持从一开始的行提取到结果集的末尾

        adOpenStatic——打开一个静态类型的游标。静态游标始终显示结果集,与光标第一次打开时一样。根据实现,静态游标可以是只读或读/写的,并提供向前和向后滚动。静态游标永远不会检测其他更新、 删除和插入。如果你的应用程序并不需要检测数据改变,而且需要滚动,静态游标是最佳选择。

    (2)动态记录集:记录集会实时的反映出数据库中相应记录的更改

        adOpenDynamic—— 打开一个完全动态的游标。动态游标可检测对结果集中的行进行的所有更改,而不管这些更改是从光标内部还是由光标外的其他用户发生。所有的 insert、 update 和 delete 语句所做的更改,所有用户都可通过游标可见。动态游标可以检测游标打开后对结果集中的行,顺序和值所做的任何更改。

        adOpenKeyset——保持当前记录集的个数不变,它只体现更新操作,不体现删除和添加操作,即只能看到其他用户对记录集数据的更新操作。

    3、游标锁定方法

    什么是锁定?

          锁定是DBMS限制对多用户环境中的行进行访问的过程。 当某行或列以独占的方式锁定时,其他用户将不被允许访问锁定的数据,直到锁定被释放。 这确保了两个用户不能同时更新连续的同一列。

          从资源角度来看,锁可能非常昂贵,只有在需要保存数据完整性时才应使用锁。 在数以百计或数千用户可能每秒都试图访问记录的数据库中(如连接到Internet的数据库),不必要的锁定可能会导致应用程序的性能下降。


    LockTypeEnum
    {
    adLockUnspecified = -1,
    adLockReadOnly = 1,
    adLockPessimistic = 2,
    adLockOptimistic = 3,
    adLockBatchOptimistic = 4
    };
    (1)adLockReadOnly——缺省值,只读锁定记录。

          Recordset对象以只读方式启动,无法更改数据。 只读锁是锁定类型中执行效率最快的,因为它不需要服务器来维持这个记录锁。

    (2)adLockPrssimistic——悲观锁定记录。

          提供程序通过在编辑之前立即在数据源上锁定记录来确保成功的编辑记录。 当然,这意味着一旦开始编辑,其他用户就无法使用记录,直到您通过调用Update方法来释放锁定。 在不能同时更改数据的系统中使用此类型锁,例如在机票预订系统中。

    (3)adLockOptimistic——乐观锁定记录。

          这意味着另一个用户可能会在你编辑记录和调用Update方法的期间更改数据,这会造成数据冲突。 在发生冲突的可能性较低或可以轻松解决冲突的情况下使用此锁定类型。

    (4)adLockBatchOptimistic——开放式批量更新锁:批量更新模式需要。

          许多应用程序一次获取多个行,然后需要进行协调更新,包括要插入,更新或删除的整个行集。 使用批量光标,只需要与服务器通信一次,从而提高了更新性能并降低了网络流量。 使用批量游标库可以创建一个静态游标,然后断开与数据源的连接。 此时,你可以对行进行更改,然后重新连接并将更改发布到批处理中的数据源。

    4、游标位置属性

            指示光标服务的位置(Recordset对象和Connection对象均可设置)      

             属性详解:    

         This property setting affects connections established only after the property has been set. Changing the CursorLocation property has no effect on existing connections.

           此属性设置仅影响属性设置后建立的连接。 更改CursorLocation属性对现有连接没有影响。(意即该属性必须在连接建立之前设置)

          Cursors returned by the Execute method inherit this setting. Recordset objects will automatically inherit this setting from their associated connections.

            由Execute方法返回的游标继承此设置。 Recordset对象将自动从它们的关联连接来继承这个设置。


            This property is read/write on a Connection or a closed Recordset, and read-only on an open Recordset.

            此属性在一个连接或关闭的记录集上是可读取/写入的,在打开的Recordset上为只读。


    CursorLocationEnum
    {
    adUseNone = 1,
    adUseServer = 2,
    adUseClient = 3,
    adUseClientBatch = 3
    };
    (1)adUseNone——不使用游标服务(这个常量已经过时,并且仅出于向后兼容性的考虑)

    (2)adUseServer——服务器游标,默认值。使用数据提供者的或驱动程序提供的游标。这些游标有时非常灵活,对于其他用户对数据源所作的更改具有额外的敏感性。但是,Microsoft Client Cursor Provider(如已断开关联的记录集)的某些功能无法由服务器端游标模拟,通过该设置将无法使用这些功能。

    (3)adUseClient——客户端游标。使用由本地游标库提供的客户端游标。 本地游标服务通常允许使用的许多功能可能是驱动程序提供的游标无法使用的,因此使用该设置对于那些将要启用的功能是有好处的。为了向后兼容,还支持同义adUseClientBatch。

    5、最常见的问题:获取记录集的RecordCount属性总为-1

    当游标类型CursorType设置为adoOpenStatic / adOpenKeyset时,RecordCount方法才能返回实际的记录数。如果将 CursorLocation 属性设置为 adUseClient,则只支持 adOpenStatic 的设置。

    示例:_ConnectionPtr m_pCon; _RecordsetPtr m_pRs;

    BOOL CRestaurantApp::InitInstance()
    {
        AfxEnableControlContainer();
        ::CoInitialize(NULL);//AfxOleInit();
        HRESULT hr;
        try
        {
            hr = m_pCon.CreateInstance("ADODB.Connection");//创建连接
            if(SUCCEEDED(hr))
            {
                m_pCon->CommandTimeout = 3; //连接延迟设置为3秒
                hr = m_pCon->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=restaurant.mdb","","",adModeUnknown);//连接数据库
            }
            else
            {
                _com_error e(hr);
                AfxMessageBox(e.ErrorMessage());//hr=-2147221164 没有注册类
            }
        }
        catch(_com_error e)
        {
            CString temp;
            temp.Format("连接数据库错误信息:%s,%s",e.ErrorMessage(),e.Description());
            ::MessageBox(NULL,temp,"提示信息",NULL);
            return FALSE;
        }
    
        CRestaurantDlg dlg;
        m_pMainWnd = &dlg;
        int nResponse = dlg.DoModal();
        if (nResponse == IDOK)
        {
        }
        else if (nResponse == IDCANCEL)
        {
        }
        return FALSE;
    }            
    AfxOleInit();
    HRESULT hr;
    _ConnectionPtr m_pConnection = NULL;
    m_pConnection.CreateInstance("ADODB.Connection"); //创建Connection对象实例
    m_pConnection->ConnectionTimeout = 30; //设置连接超时时间 30s
     if (m_pConnection == NULL)
    {
        TRACE("Connection 对象创建失败! 请确认是否初始化了COM环境
    ");
    }
    else
    {
        _com_error e(hr);
        AfxMessageBox(e.ErrorMessage());//hr=-2147221164 没有注册类
    }
    //连接字符串
    hr = m_pConnection->Open(_bstr_t(_T("Provider=OraOLEDB.Oracle.1;Password=test;Persist Security Info=True;User ID=test;Data Source=ORCL")),_bstr_t(_T("test")), _bstr_t(_T("test")), adConnectUnspecified); 
    if (SUCCEEDED(hr))// 测试数据库是否连接成功
    {
        TRACE("数据库初始化连接成功!");
    }
    _RecordsetPtr m_pRecordset = NULL;
    m_pRecordset.CreateInstance("ADODB.Recordset");//创建记录集的对象实例
     m_pRecordset->CursorLocation = CursorLocation;//设置游标位置
    CString strSQL;
    strSQL = "select * from test"; 
    m_pRecordset->Open(_bstr_t(strSQL), m_pConnection.GetInterfacePtr(), CursorType, LockType, adOptionUnspecified);

     - 简单栗子:

    首先在 StdAfx.h 中导入所需要的库:#import “c:program filescommon filessystemadomsado15.dll” no_namespace rename(“EOF”, “adoEOF”) ,这里重命名EOF是必要的,因为典型的VC应用都已经定义了EOF作为常数-1。

        ::CoInitialize(NULL);//初始化com库
        _ConnectionPtr pCon;
        pCon.CreateInstance("ADODB.Connection");
        HRESULT hr = pCon->Open("Provider = Microsoft.Jet.OLEDB.4.0; Data Source = User.mdb","","",adModeUnknown);
        // hr >=0 表示连接数据库成功
    //    ::CoUninitialize();//关闭当前线程的COM库
    
        UpdateData();
        CString sql;
        sql.Format("SELECT * FROM tb_User WHERE ID = %d", m_ID);
        _RecordsetPtr pRs;
        //方法1
    //    pRs = pCon->Execute((_bstr_t)sql, NULL, adCmdText);
        //方法2
        pRs.CreateInstance("ADODB.Recordset");//必须
        pRs->Open((_bstr_t)sql, _variant_t((IDispatch*)pCon, true), adOpenForwardOnly, adLockReadOnly, adCmdText);
    
        pRs->MoveFirst();
        if(!pRs->adoEOF)
        {
            MessageBox("ID已存在!","提示");
            return;
        }
    //////// 连接数据库User.mdb //// 在 OnInitDialog()中
    	::CoInitialize(NULL); // 初始化COM库
    	HRESULT hr;
    	try
    	{
    		hr = m_pCon.CreateInstance("ADODB.Connection");
    		if(SUCCEEDED(hr))
    		{
    			m_pCon->CommandTimeout = 3;
    			hr = m_pCon->Open("Provider = Microsoft.Jet.OLEDB.4.0;Data Source = User.mdb","","",adModeUnknown);
    		}
    		else
    		{
    			_com_error e(hr);
    			AfxMessageBox(e.ErrorMessage());
    			return TRUE;
    		}
    	}
    	catch(_com_error e)
    	{
    		AfxMessageBox(e.ErrorMessage());
    		return TRUE;
    	}
    	////////////////////////////////////////
    	m_pRs.CreateInstance("ADODB.Recordset");
    
    /////// 给数据库 User.mdb 添加一条纪录  /////
    m_pRs->Open("SELECT * FROM tb_User", _variant_t((IDispatch*)m_pCon,TRUE),adOpenKeyset,adLockPessimistic,adCmdText);
    // 注意:adLockUnspecified 的时候,使用 m_pRs->AddNew(); 会出错。故用 adLockPessimistic / adLockOptimistic
    m_pRs->AddNew();
    //设置字段的值   注意:设置空字符串会出错
    m_pRs->PutCollect((_bstr_t)"ID", dlg.m_ID);
    m_pRs->PutCollect((_bstr_t)"Name", (_bstr_t)dlg.m_name);
    m_pRs->PutCollect((_bstr_t)"Sex", (long)dlg.m_sex);
    m_pRs->PutCollect((_bstr_t)"Salary", (_bstr_t)dlg.m_salary);
    m_pRs->Update();//更新保存
    m_pRs->Close();
    /////// 给数据库 User.mdb 修改一条纪录  /////
    CString ID = m_list.GetItemText(nSel,0);
    CString sql = "SELECT * FROM tb_User WHERE ID = "+ID;
    m_pRs->Open((_bstr_t)sql, _variant_t((IDispatch*)m_pCon,TRUE),adOpenKeyset,adLockPessimistic,adCmdText);
    if(m_pRs->GetRecordCount() != 1)
    	return;
    CEditDlg dlg;
    /*	dlg.m_ID = atoi(ID);
    dlg.m_name = m_list.GetItemText(nSel, 1);
    dlg.m_sex = m_list.GetItemText(nSel, 2) == "男" ? 0:1;
    dlg.m_salary = m_list.GetItemText(nSel, 3);*/
    // 法2:获取纪录的字段的值  注意:设置空字符串会出错
    dlg.m_ID = m_pRs->GetFields()->Item["ID"]->Value;
    dlg.m_name = (char*)(_bstr_t)m_pRs->GetFields()->Item["Name"]->Value;
    dlg.m_sex = (long)m_pRs->GetFields()->Item["Sex"]->Value;
    dlg.m_salary = (char*)(_bstr_t)m_pRs->GetFields()->Item["Salary"]->Value;
    
    if(IDOK == dlg.DoModal())
    {
    	m_pRs->PutCollect((_bstr_t)"ID", dlg.m_ID);
    	m_pRs->PutCollect((_bstr_t)"Name", (_bstr_t)dlg.m_name);
    	m_pRs->PutCollect((_bstr_t)"Sex", (long)dlg.m_sex);
    	m_pRs->PutCollect((_bstr_t)"Salary", (_bstr_t)dlg.m_salary);
    	m_pRs->Update();
    	UpdateList();
    }
    m_pRs->Close();
    //////////////// 删除一条记录 /////////////////
    int nSel = m_list.GetSelectionMark();
    if(m_list.GetSelectedCount() < 1)
    {
    	MessageBox("请选择一行纪录再修改!","提示");
    	return;
    }
    if(m_pRs->GetState() == adStateOpen)//系统定义 adStateOpen = 1
    {
    	m_pRs->Close();
    }
    CString ID = m_list.GetItemText(nSel,0);
    /*
    CString sql = "SELECT * FROM tb_User WHERE ID = "+ID;
    m_pRs->Open((_bstr_t)sql, _variant_t((IDispatch*)m_pCon,TRUE),adOpenKeyset,adLockPessimistic,adCmdText);
    m_pRs->Delete(adAffectCurrent);//删除当前行
    m_pRs->Update();
    m_pRs->Close();*/
    //以下两句可代替上面的代码块,同样可以实现删除
    CString sql = "DELETE FROM tb_User WHERE ID = " + ID;
    m_pCon->Execute((_bstr_t)sql, NULL, adCmdText);
    
    UpdateList();
    

    ADO常用的连接方式和访问加密的ACCESS数据库

    原文:https://blog.csdn.net/drmcty/article/details/8152163 

    在stdafx.h中添加一句指令:

    #import "c:program filescommon filessystemadomsado15.dll"
    no_namespace
    rename ("EOF", "adoEOF")

    COM库的初始化在CWinApp::InitInstance()的重载函数中添加:AfxOleInit(),代码如下:

    BOOL CADOTest1App::InitInstance()
    {
    AfxOleInit();
    ......
    }

    1. ADO的连接方式:

    (1)通过JET数据库引擎对ACCESS2000数据库的连接:

           m_ pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;
           Data Source=C:\test.mdb","","",adModeUnknown);

       注:在使用ACCESS 2007存的数据库时,上面的函数应改为:

           m_ pConnection->Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\test.mdb","","",adModeUnknown);

    (2)通过DSN数据源对任何支持ODBC的数据库进行连接:

           m_pConnection->Open("Data Source=adotest;UID=sa;PWD=;","","",adModeUnknown);

    (3)不通过DSN对SQL SERVER数据库进行连接:

           m_pConnection->Open("driver={SQL Server};Server=127.0.0.1;DATABASE=vckbase;
           UID=sa;PWD=139","","",adModeUnknown);

    其中Server是SQL服务器的名称,DATABASE是库的名称。

    2. 访问加密的ACCESS数据库的连接方式

    访问加密的ACCESS2002数据库

    _ConnectionPtr m_pConnetion;
    m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=数据库路径文件名.mdb;UID=Admin;PWD=密码","","",adModeUnknown);

    访问加密的ACCESS2007数据库

    _ConnectionPtr m_pConnetion;
    m_pConnection->Open("Provider=Microsoft.ACE.OLEDB.12.0;Data source=数据库路径文件名.accdb;Jet OLEDB:Database Password=密码","","",adModeUnknown);
    ---------------------
    ADO编程详解(C++):blog.csdn.net/learnlhc/article/details/72714038

    常记溪亭日暮,沉醉不知归路。兴尽晚回舟,误入藕花深处。争渡,争渡,惊起一滩鸥鹭。

    昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否?知否?应是绿肥红瘦。
  • 相关阅读:
    1086. Tree Traversals Again (25)
    1094. The Largest Generation (25)
    1076. Forwards on Weibo (30)
    1083. List Grades (25)
    1082. Read Number in Chinese (25)
    【七夕特辑】程序员表白网页合集
    flex布局
    Nodejs进阶:基于express+multer的文件上传
    Git 和 SVN 之间的五个基本区别
    React通用后台管理系统
  • 原文地址:https://www.cnblogs.com/htj10/p/10800715.html
Copyright © 2011-2022 走看看