MFC ODBC 用法
来源:互联网 发布:京东金融数据挖掘大赛 编辑:程序博客网 时间:2024/06/05 17:46
主要内容:
?
?
?
?
?
?
?
?
?
?
?
MFC OBDC技术
概述
MFC的ODBC类对较复杂的ODBC
?
?
?
?
?
CDatabase类操作数据源
CDatabase类型的对象表示一个到数据源的连接,通过它可以操作数据源。
该类的成员函数如下表:
函数
说明
CDatabase
构造一个对象
Close
关闭数据源连接
Open
通过一个ODBC驱动程序创建到数据源的连接
OpenEx
通过一个ODBC驱动程序创建到数据源的连接
BeginTrans
开始事务
BindParameters
允许在调用CDatabase::ExecuteSQL前绑定参数
Cancel
取消异步操作或第二条线程中的过程
CommitTrans
执行事务
ExecuteSQL
执行SQL语句,不返回记录
Rollback
回滚事务,数据源返回先前的状态
该类的属性属性如下表:
属性
说明
CanTransact
如果数据源支持事务,返回非零
CanUpdate
如果CDatabase可以更新,返回非零
GetBookmarkPersistence
获得书签对记录集对象的持久性
GetConnect
返回ODBC连接串
GetCursorCommitBehavior
获得提交事务对记录集对象的影响
GetCursorRollbackBehavio
获得回滚事务对记录集对象的影响
GetDatabaseName
返回当前使用的数据库名
IsOpen
如果当前CDatabase对象连接到数据源,返回非零
SetLoginTimeout
设置数据源连接的超时数(秒为单位)
SetQueryTimeout
设置查询操作的超时数(秒为单位)
应用程序可使用多个CDatabase类型的对象。构造一个对象并调用Open()成员函数打开一个连接。接着构造CRecordset类型的对象以操作连接的数据源,构造时向记录集对象传递CDatabase类型的指针。完成使用后,用Close()成员函数销毁CDatabase类型的对象。
一般情况下并不需要直接使用CDatabase类型的对象,因为CRecordset类型的对象可以实现大多数的功能、但是在进行事务处理时,CDatabase就起到关键作用。事务(Transaction)指的是将一系列对数据源的更新放在一起,同时提交或一个都不提交,为的是确保多用户对数据源同时操作时的数据正确性。
CRecordset类操作记录集
一个CRecordset类型的对象代表从数据源选择的一组记录的集合——记录集,通过该类的方法实现对数据库中记录的各种操作。
该类常用的数据成员如下表:
成员
说明
m_hstmt
包含记录集的ODBC陈述句柄,类型为HSTMT
m_nFields
包含记录集中字段数据成员的数量,类型为UNIT
m_nParams
包含记录集中参数数据成员的数量,类型为UNIT
m_pDatabase
包含一个CDatabase对象指针,通过它访问数据源
m_strFilter
包含CString对象,定义SQL中WHERE子句
m_strSort
包含CString对象,定义SQL中ORDER
该类的构造方法如下表:
构造方法
说明
Close
关闭记录集和与之相关的HSTMT
CRecordset
构造一个CRecordset对象
Open
通过获得表或执行记录集所代表的查询来打开记录集
CRecordset类记录集属性如下表:
属性
说明
CanAppend
如果新记录可以通过Addnew添加到记录集,返回非零
CanBookmark
如果记录集支持书签,返回非零
CanRestart
如果Requery可以被调用来再次运行记录集查询,返回非零
CanScroll
如果可以在记录中回滚,返回非零
CanTransact
如果数据源支持事务,返回非零
CanUpdate
如果记录集可以被更新,返回非零
GetODBCFieldCount
返回记录集中字段的数量
GetRecordCount
返回记录集中记录的数量
GetSQL
获得SQL字符串
GetStatus
获得记录集的状态
GetTableName
获得记录集所属的表名
IsBOF
如果记录集定位在第一条记录之前,返回非零
IsDeleted
如果记录集定位在一条删除的记录,返回非零
IsEOF
如果记录集定位在最后一条记录之后,返回非零
IsOpen
如果调用过Open函数,返回非零
CRecordset类更行操作如下表:
更新操作
说明
AddNew
准备增加一条新纪录,调用Update之后完成添加
CancelUpdate
取消任何未完成的更新
Delete
从记录集中删除当前记录
Edit
准备对当前记录进行修改,调用Update后完成修改
Update
通过将新记录或编辑的数据存入数据源来完成AddNew或Edit操作
记录集有两种形式:snapshot(表示数据的静态视图)和dynaset(表示记录集与其他用户对数据库的更新保持同步)。
CFieldExchange类处理数据交换
CFieldExchange类支持数据库类所使用的记录集字段交换(RFX)程式。如果使用自定义的数据类型写数据交换程式,会使用这个类。否则不会直接使用此类。RFX在记录集对象的字段数据成员与数据源中当前记录的相应字段之间交换数据。
CRecordView类显示记录
CRecordView对象用于在控件中显示数据库记录的视图。这种视图是一种直接连到一个CRecordView对象的格式视图,它从一个对话框模板创建资源,并将CRecordView对象的字段显示在对话框模版的控件里。对象利用DDX和RFX机制,使窗体上的空间和记录集的字段值之间数据移动自动化,也就是说,用户不需要编写一行代码就可以完成简单的数据库记录查看程序。
CDBException类处理异常
由CException类派生,以3个继承的成员变量反映对数据库操作时的异常:
?
?
?
使用MFC ODBC 编程建立应用程序
MFC ODBC编程模型概述
使用MFC
?
?
?
?
?
?
?
通过AppWizard建立数据库应用程序
“New”-->”MFC
通过AppWizard创建了一个MFC
使用CDatabase类方法打开数据源
通过CDatabase类的Open函数来打开数据源,该函数原型如下:
virtual
LPCTSTR
BOOL
BOOL
LPCTSTR
BOOL
);
下面的例子表示如何打开数据源:
//在文档类中加入
//CDatabase类对象
CDatabase
//连接对象到一个数据源(没有密码),ODBC连接对话框将是中隐藏
m_pdatabase.Open(_T(“students”),
//或者也可以显示ODBC对话框,请用户提供连接信息
m_pdatabase.Open(NULL);
像程序Sample一样,通过向导生成数据库工程,不用添加代码就能实现对数据源的打开。在CRecordset类中有一个名为GetDefaultConnect()的虚函数值得注意,通过调用它可以返回默认的数据源连接(也就是在生成工程的时候所选择的数据源)来打开数据源。该函数如下:
CString
{
return
}
使用CRecordste类打开记录集
通过声明CRecordset记录集类的对象,再利用记录集类的Open()函数可打开记录集,从而获取数据库中表的数据。也正是在调用Open()函数后,记录集当中的成员变量得到数据源中表的字段值。Open()函数的形式如下:
virtual
UNIT
LPCTSTR
DWORD
);
其中nOpenType为打开的类型,可取只有一下4种:
?
?
?
第二个参数lpszSQL是一个CString的指针,指向以下内容之一:
?
?
?
第三个参数dwOptions为一系列选项的组合,它的默认值为None。
可以像下面这样调用Open()函数来打开记录集:
CDatabase
m_pdatabase.Open(_T(“students”),
CRecordset
Sample.Open(CRecordset::dynaset,
以上语句先用CDatabase对象打开一个数据源,之后构造记录及对象,最后记录及对象Sample以动态方式打开students表中的name字段。
下面的语句表示以全部默认方式执行记录记得打开操作:
CDatabase
m_pdatabase.Open(_T(“students”),
CRecordset
Sample.Open();
也可以像下面代码中那样打开一个表中的所有字段:
CDatabase
m_pdatabase.Open(_T(“students”),
CRecordset
Sample.Open(CRecordset::dynaset,
经过上面的操作,记录集对象的字段变量就获得了数据库中特定表中指定字段的数据。
像程序Sample一样,在向导当中选择数据源和表名。在CRecordset类中有一个名为GetDefaultSQL()的虚函数值得注意,通过调用它可以返回默认的SQL语句,用于形成记录集对象。该函数如下:
CString
{
return
}
绑定记录集
通过向导创建工程后,程序的框架就生成出来。如果打开CRecordset的派生类CSampleSet,会发现里面已经有了5个变量:
//Field/Param
//{{AFX_FIELD(CSampleSet,
long
CString
Long
Long
CString
//}}AFX_FIELD
这5个变量正好与要访问的表中的字段同名,并且变量的类型也与字段类型一致。这是MFC自动添加的变量,已绑定表中的字段。如果表中的字段是中文的,那么MFC会创建m_column1、m_column2等与之对应。RFX实现了这种绑定。
RFX(Record
可以在CSampleSet类的DoFieldExchange函数中看到一组组的RFX函数调用,正是通过调用它们,使CSampleSet记录集中的变量与students表中的字段对应起来。
void
{//{{AFX_FIELD_MAP(CSampleSet)
pFX->SetFieldType(CFieldExchange::outputColumn);
RFX_Long(pFX,
RFX_Long(pFX,
RFX_Long(pFX,
RFX_Long(pFX,
RFX_Long(pFX,
//}}AFX_FIELD_MAP
}
RFX函数通常有3个参数(个别的会有4或5个)。第一个参数为一个指向CFieldExchange类对象的指针,第二个参数为数据源中的一个字段名称,第三个参数是与字段相对应的记录集中的变量名。常用的RFX函数如下表:
函数
数据类型
RFX_Bool
BOOL
RFX_Byte
BYTE
RFX_Binary
CByteArray
RFX_Double
Double
RFX_Sing
Float
RFX_Int
Int
RFX_Long
Long
RFX_LongBinary
CLongBinary
RFX_Text
CString
RFX_Date
CTime
参数化记录集和查询
CRecordset类对象中有两个成员变量,一个为m_strFilter(过滤字符串,负责对记录集进行过滤,返回过滤后的记录),另一个为m_strSort(排序字符串,对记录集进行排序)。
m_strFilter存放着SQL语句中WHERE子句的条件字符串,m_strSort中则存放着SQL语句中ORDER
下面的代码中向m_strFilter赋值“comment=good”,向m_strSort赋值“name”:
CRecordset
Sample.m_strFilter
Sample.m_strSort
除了直接向m_strFilter赋值外,还可以使用参数化。利用参数化可以更直观,更方便地完成条件查询任务。使用参数化的步骤如下:
首先声明参变量:
CString
CString
在构造函数中初始化参变量
age1
comment
将参变量与对应列绑定
pFX->SetFieldType(CFieldExchange::param);
pFX->Text(pFX,
pFX->Text(pFX,
最后利用参变量进行条件查询
m_pSet->m_strFilter
m_pSet->age
m_pSet->comment
m_pSet->Requery();
参变量的值按绑定的顺序替换查询字符串中的“?”适配符。代码中的m_pSet是CRecordView类的一个记录集指针,指向当前文档类中的记录集变量。它是在CRecordView类的OnInitialUpdate中被赋予文档类下记录集对象的指针的。下面是程序中CSampleView类的OnInitialUpdate函数体:
void
{ //为m_pSet赋予文档类下的记录集对象的指针
m_pSet
CRecordView::OnInitialUpdate();
ResizeParentToFit();
}
遍历记录集合
CRecordset类中有一组函数负责记录集指针的移动,例如使用记录集指针下移一个记录、使用记录集指针上移一个记录等。
1、
2、
3、
4、
5、
6、
知道上面的这些函数的意义后,下面来看如何遍历记录集。下面的代码中m_pSet是一个记录集指针,m_list为一个列表框控件(ClistBox类)的变量:
if(!m_pSet->IsOpen()) //用IsOpen函数检测记录集是否打开
m_pSet->Open();
m_pSet->MoveFirst();
while(!m_pSet->IsEOF())
{
m_list.AddString(m_pSet->m_name);
m_pSet->MoveNext();
}
m_pSet->MoveFirst(); //遍历完成后,使记录集指针指向第一条记录
书签定位和绝对定位
当在记录集中浏览的时候,可能想返回记录集中特定的一条记录,CRecordset提供了两种方法可以指定记录集到特定的位置。
1、
可以在记录集中的某一条记录增加一个书签。在记录集浏览时由于用户的增删操作使记录的绝对位置发生改变,所以以来绝对位置是不可靠的。因此需要使用书签定位来为所想要的记录定位。CRecordset类中提供的书签定位的方法是GetBookmark和SetBookmark两个函数,他们的原型如下:
void
void
这里只需直接使用CDBVariant的对象即可。
//创建CDBVariant对象
CDBVariant
//rs是CRecordset类或CRecordset类派生类的对象
rs.GetBookmark(bookmark);
//一系列移动到其他记录的代码
rs.MoveNext();
rs.MoveNext();
rs.SetBookmark(bookmark);
GetBookmark函数将当前的记录存入一个CDBVariant的对象中,经过一系列的纪录移动之后,在调用SetBookmark,并且用刚才记录“书签”的CDBVariant对象bookmark作参数来使用当前记录集重新指向“书签”的位置。
是否支持书签定位取决于ODBC驱动程序和记录集类型。可以通过调用CRecordset::CanBookmark来确定是否支持书签定位。如果想支持书签定位,还需要在记录集的Open函数的dwOptions参数位置中加入CRecordset::useBookmarks参数。注意forward-only
这个函数的返回值为bitmask,这是一个DWORD类型的返回值。该值可以是下表中的多个bitmask值的组合。
bitmask值
书签的有效性
SQL_BP_CLOSE
Requery操作后,书签有效
SQL_BP_DELETE
对某行执行delete操作后,书签对此行依然有效
SQL_BP_DROP
一次Close操作后,书签有效
SQL_BP_SCROLL
任何Move操作之后,书签都有效
SQL_BP_TRANSACTION
一次事务被提交或回滚后,书签有效
SQL_BP_UPDATE
对某行执行Update操作后,书签对此行有效
SQL_BP_OTHER_HSTMT
与某记录集对象相关的书签对另一记录集也有效
2、
相对于书签定位,绝对定位就好像记住某本书的某一个固定页码一样。绝对定位就是通过原始的记录位置来设置当前记录,比如可以设置记录集中第8条记录为当前记录。如想使用绝对定位来改变当前的记录集位置,可以调用CRecordset::SetAbsolutePosition函数。其原型为:
void
nRows表示记录集中的一个绝对位置。调用该函数会把记录集指针定位到nRows参数所指行号的记录上。
下面的代码表示把记录集定位到第12条记录的位置上:
long
row
rs.SetAbsolutePositon(row);
对于ODBC的记录集来说,绝对位置1指的是记录集当中的第一条记录,绝对位置如果是0则代表的是BOF位置(在第一条记录之前)。
(***forward-only
获取记录集的数据
通过在对话框上添加控件,并且为控件绑定变量来达到数据交换并显示的目的,与控件绑定的变量正是记录集中的那些字段变量。步骤如下:
l
l
l
到底记录集中的变量是如何把数据显示在控件上呢?下面讲述DDX技术。
DDX是Dialog
CRecordView类里面有一个DoDataExchange函数,所有的DDX函数都是在DoDataExchange中调用的。DoDataExchange函数为DDX函数提供了一个CDataExchange类对象的指针。在工程刚刚创建时,CSampleView::DodataExchange函数是一个空函数,因此此时对话框上并没有控件,更没有与控件对应的变量。但经过窗体添加控件、为控件添加变量之后,再打开DoDataExchange函数,将会出现下面这样的代码:
void
{
CRecordView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSampleView)
DDX_FieldText(pDX,
DDX_FieldText(pDX,
DDX_FieldText(pDX,
DDX_FieldText(pDX,
DDX_FieldText(pDX,
//}}AFX_DATA_MAP
}
DDX_FieldText函数负责在对话框控件和记录集中字段变量之间建立联系。因为记录集中的字段变量对应的是数据库中表的每个字段,所以就能在控件上看到表中的数据了。DDX函数有四个参数,分别为:
l
l
l
l
DDX可以管理以下类型数据变量与控件的数据交换。它们是short、long、int、DWORD、CString、float、double、BOOL以及BYTE。
程序通过UpdateData这个函数在控件与变量之间达到双向数据,而不是直接调用DoDataExchange。UpdateData函数的原型如下:
BOOL
bSaveAndValidate指示了数据传输的方向,当为TRUE时就是控件向变量传输。反之,就是变量向控件传输数据。默认值为TRUE
添加记录
对记录的操作大多数都是由CRecordset类来负责的,执行添加的任务也不例外。CRecordset类中的函数AddNew()表示向表中添加一条新的纪录,该函数原型如下:
virtual
执行AddNew()函数之后会新增加一条空记录,等待输入数据。此时记录的每一个字段都被初始化NULL。在输入新的记录数据之后,需调用另一个CRecordset类的函数才能完成对新记录的添加,这个函数是Update(),函数原型为:virtual
在调用完AddNew函数、输入新数据之后一定要调用Update,它负责把新添加的数据保存到数据源。实际上AddNew函数只是在内存中创建了一块缓冲区,等待输入数据,之后需要使用Update来真正把数据存入数据源。如果在调用Update之前滚动到了另一条记录,那么新记录就会丢失,也不会提出警告。对于dynaset(动态集)类型的记录集,新记录会添加到末尾。新记录不能被添加到Snapshot类型的记录集中。最后还需要调用CRecordset::Requery函数以刷新记录集:virtual
Requery函数负责刷新记录集来反映当前最新的数据。在每次对记录进行添加、删除后,都有必要调用Requery来更新记录集。调用Requery函数后,记录集指针重新指向第一条记录。
下面的代码实现了在一个名为OnAdd的函数中添加记录:
void
{
//添加一条新记录
m_pSet->AddNew();
//对记录集中的m_id、m_name、m_department、m_age等赋值
m_pSet->m_id
m_pSet->m_name
m_pSet->m_department
m_pSet->m_age
m_pSet->m_comment
//更新记录集,将新记录存入数据源
m_pSet->Update();
//刷新记录集,并使记录集指针回到第一条记录
m_pSet->Requery();
}
删除记录
调用CRecordset类中的Delete函数进行删除记录。该函数用于删除当前记录集指针指向的记录。原型如下:virtual
一次成功的删除后,被删除记录的字段全部被设为NULL,必须调用Move函数移动到其他记录上来一处被删除的记录。如果删除不成功,记录中的数据也不会被破坏。一旦移除了删除的记录,就再也不能返回他了。在调用Delete函数时,记录集中必须有一条有效的记录,否则会产生错误。。如果Delete了一条记录,但没有Move到另一条记录就有进行了Delete操作,Delete会产生一个CDBException类的错误。
下面的代码在一个名为OnDelete的函数中实现了删除当前记录的操作:
void
{
//删除当前记录
m_pSet->Delete();
//刷新记录集
m_pSet->Requery();
}
修改记录
CRecordset::Edit函数的作用是允许修改当前的记录。原型如下:
virtual
调用Edit之后,就可以直接重新设定当前记录中每个字段的值了。再重新设定之后,还需要调用Update函数来保存对数据的修改。实际上,调用Edit之后,要被修改的值先被保存起来。如果Edit之后没有Update,而是移动到另一条记录,那么记录以前的值被重新恢复,不对记录作出修改。或者,调用了一次Edit,而对记录也作出了修改,然后又调用了一次Edit,那么记录还是被恢复到第一次调用Edit之前的值。
下面的代码在名为OnEdit的函数中实现对数据的编辑:
void
{
m_pSet->Edit();
m_pSet->m_id
m_pSet->m_name
m_pSet->m_department
m_pSet->m_age
m_pSet->m_comment
m_pSet->Update();
m_pSet->Requery();
}
直接执行SQL语句(增加、删除表等)
并不是所有的ODBC功能都被数据库类所支持,所以有时候需要使用直接执行SQL语句来对数据库进行一些操作。
CDatabase类中有一个函数ExecuteSQL,通过它可以直接执行SQL语句,对数据库进行操作。原型如下:void
参数lpszSQL是一个CString类型的指针,包含一条可执行的、有效地SQL命令。这个函数并不返回信息,如果要对记录进行操作,那么还是要使用记录集对象。
下面的代码可以在一个名为class的表中增加一条记录。m_database是一个CDatabase类的对象。VALUES中是新增记录的具体值,分别于表中的每一个字段相对应。
m_pSet->Open();
m_pSet->AddNew();
m_database.ExecuteSQL(“insert
m_pSet.Update();
m_pSet->Edit();
m_database.ExecuteSQL(“Delete
m_pSet.Update();
事务处理
事务操作涉及CDatabase类的几个成员函数,BeginTrans表示开始事务,CommitTrans表示接受所有对数据源的修改,或者调用Rollback来终止整个事务。执行事务的三个步骤:
l
l
l
下面的代码中要删除一家商店中的一项商品,因为要将两个记录集中涉及该商品的所有记录同时删除,所以要使用事务处理。记录集orderset为订单记录,记录集goodsset为商品品种记录。m_shop为CDatabase类对象,假设它已经连接到了数据源。strgoodsID为用户输入的要删除商品的ID。两个记录集中都使用m_strFilter变量来过滤出要删除的记录。
BOOL
{ //开始事务
if(!m_shop.BeginTrans())
return
//创建订单记录集
COrderSet
orderset.m_strFilter
if(!orderset.Open(CRecordset::dynaset))
return
//创建商品记录集
CGoodsSet
goodsset.m_strFilter
if(!goodsset.Open(CRecordset::dynaset))
return
//操作中使用了try…catch()来捕获错误信息
//因为有时会经常出现一些意想不到的错误
TRY
{ //删除订单记录
while(!orderSet.IsEOF())
{
orderset.Delete();
orderset.MoveNext();
}
//删除商品条目
goodsset.Delete();
//执行事务
m_shop.CommitTrans();
}
CATCH_ALL(e)
{ //取消事务
m_shop.Rollback();
return
}
END_CATCH_ALL
//关闭记录集
orderset.Close();
goodsset.Close();
return
}
使用多记录集
有时候需要使用多个记录集,以使在一个程序中可以操作多个表。生成工程时,通常只选择一个表作为记录集要对应的对象。而且就算在生成工程时选择多个表,那么AppWizard也只会产生多个表的一个笛卡尔乘积,并不会为每一个表产生一个记录集。
通过Visual
“View”
- MFC ODBC 用法
- MFC ODBC 用法
- MFC ODBC 用法
- MFC ODBC 用法
- MFC ODBC 用法
- MFC ODBC 详细用法
- MFC ODBC
- MFC ODBC
- MFC ODBC
- MFC ODBC
- MFC 中 ODBC类
- MFC ODBC数据库编程
- MFC ODBC编程
- MFC的ODBC实验
- MFC中的ODBC类
- MFC ODBC(一)
- MFC 数据库ODBC
- MFC ODBC类使用心得
- string 所有函数及功能
- WIN2003域服务器通过组策略禁止部门员工上网
- C语言四舍五入函数
- java测试错误集 -Spring
- IOS里面一些基础类型的使用点
- MFC ODBC 用法
- java经典面试题/java基础
- 用python的tiwsted实现一个定时器
- cocos2d中.plist文件的使用
- Novatek Graphics
- AIX操作命令
- 《深入理解java虚拟机》学习笔记7——Java虚拟机类生命周期
- js中arguments的使用
- 提高班一年,我的变化