数据库编程总结(精选7篇)
当前各种主流数据库有很多,包括Oracle, MS SQL Server, Sybase, Informix, MySQL, DB2, Interbase / Firebird, PostgreSQL, SQLite, SAP/DB, TimesTen, MS ACCESS等等。数据库编程是对数据库的创建、读写等一列的操作。数据库编程分为数据库客户端编程与数据库服务器端编程。数据库客户端编程主要使用ODBC API、ADO、ADO.NET、OCI、OTL等方法;数据库服务端编程主要使用OLE DB等方法。数据库编程需要掌握一些访问数据库技术方法,还需要注意怎么设计高效的数据库、数据库管理与运行的优化、数据库语句的优化。
一、访问数据库技术方法
数据库编程分为数据库客户端编程与数据库服务器端编程。数据库客户端编程主要使用ODBC API、ADO、ADO.NET、OCI、OTL等方法;数据库服务端编程主要使用OLE DB等方法。
1、几种是数据库访问方法比较
ODBC
API是一种适合数据库底层开发的编程方法,ODBC
API提供大量对数据源的操作,ODBC
API能够灵活地操作游标,支持各种帮定选项,在所有ODBC相关编程中,API编程具有最高的执行速度。DAO提供了很好的数据库编程的对象模型.但是,对数据库的所有调用以及输出的数据都必须通过Access/Jet数据库引擎,这对于使用数据库应用程序,是严重的瓶颈。
OLE
DB提供了COM接口,与传统的数据库接口相比,有更好的健壮性和灵活性,具有很强的错误处理能力,能够同非关系数据源进行通信。
ADO最主要的优点在于易于使用、速度快、内存支出少和磁盘遗迹小。
ADO.NET 是利用数据集的概念将数据库数据读入内存中,然后在内存中对数据进行操作,最后将数据集数据回写到源数据库中。
OTL 是 Oracle, Odbc and DB2-CLI Template Library 的缩写,是一个C++编译中操控关系数据库的模板库,OTL中直接操作Oracle主要是通过Oracle提供的OCI接口进行,进行操作DB2数据库则是通过CLI接口来进行,至于MS的数据库和其它一些数据库,则OTL只提供了ODBC来操作的方式。当然Oracle和DB2也可以由OTL间接使用ODBC的方式来进行操纵。具有以下优点:跨平台;运行效率高,与C语言直接调用API相当;开发效率高,起码比ADO.net使用起来更简单,更简洁;部署容易,不需要ADO组件,不需要.net framework 等。
2、VC数据库编程几种方法
VC数据库编程几种方法,包括ODBC连接、MFC
ODBC连接、DAO连接、OLE
DB、OLE
DB
Templates连接、ADO、Oracle专用方法(OCI(Oracle
Call
Interface)访问、Oracle
Object
OLE
C++
Class
Library)。
<1.>通用方法
1.ODBC连接
ODBC(Open
DataBase
Connectivity)是MSOA的一部分,是一个标准数据库接口。它提供对关系数据库访问的统一接口,实现对异构数据源的一致访问。ODBC数据访问由以下部分组成:
<1>句柄(Handles):ODBC使用句柄来标识ODBC环境、连接、语句和描述器.<2>缓存区(Buffers):
<3>数据类型(Data
types)
<4>一致性级别(Conformance
levels)
用ODBC设计客户端的一般步骤:
<1>分配ODBC环境
<2>分配连接句柄
<3>连接数据源
<4>构造和执行SQL语句
<5>获得查询结果
<6>断开数据源的连接
<7>释放ODBC环境
ODBC
API是一种适合数据库底层开发的编程方法,ODBC
API提供大量对数据源的操作,ODBC
API能够灵活地操作游标,支持各种帮定选项,在所有ODBC相关编程中,API编程具有最高的执行速度.因此,ODBC
API编程属于底层编程。
2.MFC
ODBC连接
MFC
ODBC是MFC对ODBC进行的封装,以简化对ODBC
API的 调用,从而实现面向对象的数据库编程接口.MFC
ODBC的封装主要开发了CDatabase类和CRecordSet类
(1)CDatabase类
CDatabase类用于应用程序建立同数据源的连接。CDatabase类中包含一个m_hdbc变量,它代表了数据源的连接句柄。如果要建立CDatabase类的实例,应先调用该类的构造函数,再调用Open函数,通过调用,初始化环境变量,并执行与数据源的连接。在通过Close函数关闭数据源。
CDatabase类提供了对数据库进行操作的函数及事务操作。
(2)CRecordSet类
CRecordSet类定义了从数据库接收或者发送数据到数据库的成员变量,以实现对数据集的数据操作。
CRecordSet类的成员变量m_hstmt代表了定义该记录集的SQL语句句柄,m_nFields为记录集中字段的个数,m_nParams为记录集所使用的参数个数。
CRecordSet的记录集通过CDatabase实例的指针实现同数据源的连接,即CRecordSet的成员变量m_pDatabase.MFC
ODBC编程更适合于界面型数据库应用程序的开发,但由于CDatabase类和CRecordSet类提供的数据库操作函数有限,支持的游标类型也有限,限制了高效的数据库开发。在编程层次上属于高级编程。
应用实例: 1.打开数据库
CDatabase database;
database.OpenEx(_T(“DSN=zhuxue”),CDatabase::noOdbcDialog);//zhuxue为数据源名称
2.关联记录集
CRecordset recset(&database);
3.查询记录
CString sSql1=“";
sSql1 = ”SELECT * FROM tablename“;
recset.Open(CRecordset::forwardOnly, sSql1, CRecordset::readOnly);
int ti=0;
CDBVariant var;//var可以转换为其他类型的值
while(!recset.IsEOF())
{
//读取Excel内部数值
recset.GetFieldValue(”id“,var);
jiangxiang[ti].id=var.m_iVal;
recset.GetFieldValue(”name“, jiangxiang[ti].name);
ti++;
recset.MoveNext();
}
recset.Close();//关闭记录集
4.执行sql语句
CString sSql=”“;
sSql+=”delete * from 院系审核“;//清空表
database.ExecuteSQL(sSql);
sSql也可以为Insert ,Update等语句
5.读取字段名
sSql = ”SELECT * FROM Sheet1“;
//读取的文件有Sheet1表的定义,或为本程序生成的表.// 执行查询语句
recset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly);
int excelColCount=recset.GetODBCFieldCount();//列数
CString excelfield[30];
//得到记录集的字段集合中的字段的总个数
for(i=0;i { CODBCFieldInfo fieldinfo; recset.GetODBCFieldInfo(i,fieldinfo); excelfield[i].name =fieldinfo.m_strName;//字段名 } 6.打开excel文件 CString sDriver = ”MICROSOFT EXCEL DRIVER(*.XLS)“;// Excel安装驱动 CString sSql,sExcelFile;//sExcelFile为excel的文件路径 TRY { // 创建进行存取的字符串 sSql.Format(”DRIVER={%s};DSN=';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=/“%s/”;DBQ=%s“,sDriver, sExcelFile, sExcelFile); // 创建数据库(既Excel表格文件) if(database.OpenEx(sSql,CDatabase::noOdbcDialog)) { //可以把excel作为一个数据库操作 } } catch(e) { TRACE1(”Excel驱动没有安装: %s“,sDriver); AfxMessageBox(”读取失败,请检查是否定义数据区Sheet1“); } 3.DAO连接 DAO(Data Access Object)是一组Microsoft Access/Jet数据库引擎的COM自动化接口.DAO直接与Access/Jet数据库通信.通过Jet数据库引擎,DAO也可以同其他数据库进行通信。DAO还封装了Access数据库的结构单元,通过DAO可以直接修改Access数据库的结构,而不必使用SQL的数据定义语言(DDL)。 DAO的体系结构如下: DAO封装的类: (1)CdaoWorkspace:对DAO工作区(数据库处理事务管理器)的封装 (2)CdaoDatabase:对DAO数据库对象的封装,负责数据库连接.(3)CdaoRecordset:对DAO记录集对象的封装,代表所选的一组记录.(4)CdaoTableDef:对表定义对象的封装,代表基本表或附加表定义.(5)CdaoQueryDef:对查询对象的封装,包含所有查询的定义.(6)CdaoException:DAO用于接收数据库操作异常的类.(7)CDaoFieldExchange DAO提供了很好的数据库编程的对象模型.但是,对数据库的所有调用以及输出的数据都必须通过Access/Jet数据库引擎,这对于使用数据库应用程序,是严重的瓶颈。 DAO相对于ODBC来说,属于高层的数据库接口.4.OLE DB连接 OLE DB对ODBC进行了两方面的扩展:一是提供了数据库编程的OLE接口即COM,二是提供了一个可用于关系型和非关系型数据源的接口。 OLE DB提供了COM接口,与传统的数据库接口相比,有更好的健壮性和灵活性,具有很强的错误处理能力,能够同非关系数据源进行通信。 与ODBC API一样,OLE DB也属于底层的数据库编程接口,OLE DB结合了ODBC对关系数据库的操作功能,并进行扩展,可以访问非关系数据库。 OLE DB访问数据库的原理如下: OLE DB程序结构: OLE DB由客户(Consumer)和服务器(Provider)。客户是使用数据的应用程序,它通过OLE DB接口对数据提供者的数据进行访问和控制。OLE DB服务器是提供OLE DB接口的软件组件。根据提供的内容可以分为数据提供程序(Data Provider)和服务提供程序(Service Provider)。 程序结构原理图如下: <1>数据提供程序 数据提供程序拥有自己的数据并把数据以表格的形式呈现给使用者使用.<2>服务提供程序 服务提供程序是数据提供程序和使用者的结合。它是OLE DB体系结构中的中间件,它是OLE DB数据源的使用者和数据使用程序的提供者 <3>数据使用程序 数据使用程序对存储在数据提供程序中的数据进行使用和控制.OLE DB开发程序的一般步骤: <1>初始化COM环境 <2>连接数据源 <3>打开对话 <4>执行命令 <5>处理结果 <6>清除对象 应用实例: 使用OLEDB编写数据库应用程序 1 概述 OLE DB的存在为用户提供了一种统一的方法来访问所有不同种类的数据源。OLE DB可以在不同的数据源中进行转换。利用OLE DB,客户端的开发人员在进行数据访问时只需把精力集中在很少的一些细节上,而不必弄懂大量不同数据库的访问协议。OLE DB是一套通过COM接口访问数据的ActiveX接口。这个OLE DB接口相当通用,足以提供一种访问数据的统一手段,而不管存储数据所使用的方法如何。同时,OLE DB还允许开发人员继续利用基础数据库技术的优点,而不必为了利用这些优点而把数据移出来。 使用ATL使用OLE DB数据使用程序 由于直接使用OLE DB的对象和接口设计数据库应用程序需要书写大量的代码。为了简化程序设计,Visual C++提供了ATL模板用于设计OLE DB数据应用程序和数据提供程序。利用ATL模板可以很容易地将OLE DB与MFC结合起来,使数据库的参数查询等复杂的编程得到简化。MFC提供的数据库类使OLE DB的编程更具有面向对象的特性。Viual C++所提供用于OLE DB的ATL模板可分为数据提供程序的模板和数据使用程序的模板。 使用ATL模板创建数据应用程序一般有以下几步骤: 1)、创建应用框架 2)、加入ATL产生的模板类 3)、在应用中使用产生的数据访问对象3 不用ATL使用OLE DB数据使用程序 利用ATL模板产生数据使用程序较为简单,但适用性不广,不能动态适应数据库的变化。下面我们介绍直接使用MFC OLE DB类来生成数据使用程序。模板的使用 OLE DB数据使用者模板是由一些模板组成的,包括如下一些模板,下面对一些常用类作一些介绍。1)、会话类 CDataSource类 CDataSource类与OLE DB的数据源对象相对应。这个类代表了OLE DB数据提供程序和数据源之间的连接。只有当数据源的连接被建立之后,才能产生会话对象,可以调用Open来打开数据源的连接。CSession类 CSession所创建的对象代表了一个单独的数据库访问的会话。一个用CDataSource类产生的数据源对象可以创建一个或者多个会话,要在数据源对象上产生一个会话对象,需要调用函数Open()来打开。同时,会话对象还可用于创建事务操作。 CEnumeratorAccessor类 CEnumeratorAccessor类是用来访问枚举器查询后所产生的行集中可用数据提供程序的信息的访问器,可提供当前可用的数据提供程序和可见的访问器。2)、访问器类 CAcessor类 CAccessor类代表与访问器的类型。当用户知道数据库的类型和结构时,可以使用此类。它支持对一个行集采用多个访问器,并且,存放数据的缓冲区是由用户分配的。CDynamicAccessor类 CDynamicAccessor类用来在程序运行时动态的创建访问器。当系统运行时,可以动态地从行集中获得列的信息,可根据此信息动态地创建访问器。CManualAccessor类 CManualAccessor类中以在程序运行时将列与变量绑定或者是将参数与变量捆定。3)、行集类 CRowSet类 CRowSet类封装了行集对象和相应的接口,并且提供了一些方法用于查询、设置数据等。可以用Move()等函数进行记录移动,用GetData()函数读取数据,用Insert()、Delete()、SetData()来更新数据。CBulkRowset类 CBulkRowset类用于在一次调用中取回多个行句柄或者对多个行进行操作。CArrayRowset类 CArrayRowset类提供用数组下标进行数据访问。4)、命令类 CTable类 CTable类用于对数据库的简单访问,用数据源的名称得到行集,从而得到数据。CCommand类 CCommand类用于支持命令的数据源。可以用Open()函数来执行SQL命令,也可以Prepare()函数先对命令进行准备,对于支持命令的数据源,可以提高程序的灵活性和健壮性。 在stdafx.h头文件里,加入如下代码。#include extern CComModule _Module;#include #include #include // if you are using schema templates 在stdafx.cpp文件里,加入如下代码。#include CComModule _Module;决定使用何种类型的存取程序和行集。获取数据 在打开数据源,会话,行集对象后就可以获取数据了。所获取的数据类型取决于所用的存取程序,可能需要绑定列。按以下步骤。 1、用正确的命令打开行集对象。 2、如果使用CManualAccessor,在使用之前与相应列进行绑定。要绑定列,可以用函数GetColumnInfo,如下所示: // Get the column information ULONG ulColumns = 0;DBCOLUMNINFO* pColumnInfo = NULL;LPOLESTR pStrings = NULL;if(rs.GetColumnInfo(&ulColumns, &pColumnInfo, &pStrings)!= S_OK)AfxThrowOLEDBException(rs.m_pRowset, IID_IColumnsInfo);struct MYBIND* pBind = new MYBIND[ulColumns];rs.CreateAccessor(ulColumns, &pBind[0], sizeof(MYBIND)*ulColumns);for(ULONG l=0;l 3、用while循环来取数据。在循环中,调用MoveNext来测试光标的返回值是否为S_OK,如下所示: while(rs.MoveNext()== S_OK){ // Add code to fetch data here // If you are not using an auto accessor, call rs.GetData()} 4、在while循环内,可以通过不同的存取程序获取数据。1)如果使用的是CAccessor类,可以通过使用它们的数据成员进行直接访问。如下所示: 2)如果使用的是CDynamicAccessor 或CDynamicParameterAccessor 类,可以通过GetValue或GetColumn函数来获取数据。可以用GetType来获取所用数据类型。如下所示: while(rs.MoveNext()== S_OK){ // Use the dynamic accessor functions to retrieve your // data ULONG ulColumns = rs.GetColumnCount(); for(ULONG i=0;i { rs.GetValue(i); } } 3)如果使用的是CManualAccessor,可以指定自己的数据成员,绑定它们。就可以直接存取。如下所示: while(rs.MoveNext()== S_OK){ // Use the data members you specified in the calls to // AddBindEntry.wsprintf(”%s“, szFoo);} 决定行集的数据类型 在运行时决定数据类型,要用动态或手工的存取程序。如果用的是手工存取程序,可以用GetColumnInfo函数得到行集的列信息。从这里可以得到数据类型。4 总结 由于现在有多种数据源,想要对这些数据进行访问管理的唯一途径就是通过一些同类机制来实现,如OLE DB。高级OLE DB结构分成两部分:客户和提供者。客户使用由提供者生成的数据。 就像其它基于COM的多数结构一样,OLE DB的开发人员需要实现很多的接口,其中大部分是模板文件。 当生成一个客户对象时,可以通过ATL对象向导指向一个数据源而创建一个简单的客户。ATL对象向导将会检查数据源并创建数据库的客户端代理。从那里,可以通过OLE DB客户模板使用标准的浏览函数。 当生成一个提供者时,向导提供了一个很好的开端,它们仅仅是生成了一个简单的提供者来列举某一目录下的文件。然后,提供者模板包含了OLE DB支持的完全补充内容。在这种支持下,用户可以创建OLE DB提供者,来实现行集定位策略、数据的读写以及建立书签。应用案例: Visual C++中使用OLE DB读写SQL Server 在需要对数据库进行操作时,OLE DB总是被认为是一种效率最高但最难的方法。但是以我最近使用OLE DB的经验看来,OLE DB的效率高则高矣,但却一点都不难。说它难恐怕主要是因为可参考的中文资料太少,为了帮助以后需要接触OLE DB的同行,我撰写了这篇文章。本文包含如下内容: 1.OLE DB写数据库; 2.OLE DB读数据库; 3.OLE DB对二进制数据(text、ntext、image等)的处理。 首先来看看对SQL Server进行写操作的代码,有一定VC基础的读者应该可以很顺利地看懂。OLE DB写数据库,就是这么简单! 注: 1.以下代码中使用的模板类EAutoReleasePtr 2.以下代码均在UNICODE环境下编译,因为执行的SQL语句必须是UNICODE的。设置工程为UNICODE的方法是:首先在project->settings->C/C++的属性页中的Preprocessor中,删除_MBCS写入UNICODE,_UNICODE。然后在link属性页中Category中选择output,在Entry-Point symbol 中添加wWinMainCRTStartup。 EAutoReleasePtr //失败,可能是因为数据库没有启动、用户名密码错等等 return;}EAutoReleasePtr //出错 return;}EAutoReleasePtr //出错 return;}hResult = ExecuteSQL(pICommand, pICommandText, _T(”USE PBDATA“));if(FAILED(hResult)){ //如果这里失败,那就是SQL语句执行失败。在此处,就是PBDATA还未创建 return;} // 创建表 ExecuteSQL(pICommand, pICommandText, _T(”CREATE TABLE 2005_1(Volume real NOT NULL,ID int NOT NULL IDENTITY)“)); // 添加记录 ExecuteSQL(pICommand, pICommandText, _T(”INSERT INTO 2005_1 VALUES(100.0)“));//...其中几个函数的代码如下: HRESULT ConnectDatabase(IDBInitialize** ppIDBInitialize, LPCTSTR pszDataSource, LPCTSTR pszUserID, LPCTSTR pszPassword){ ASSERT(ppIDBInitialize!= NULL && pszDataSource!= NULL && pszUserID!= NULL && pszPassword!= NULL); UINT uTimeout = 15U;// 连接数据库超时(秒) TCHAR szInitStr[1024]; VERIFY(1023 >= wsprintf(szInitStr, _T(”Provider=SQLOLEDB;Data Source=%s;Initial Catalog=master;User Id=%s;Password=%s;Connect Timeout=%u“), pszDataSource, pszUserID, pszPassword, uTimeout)); //Initial Catalog=master指明连接成功后,”USE master“。 EAutoReleasePtr HRESULT hResult = ::CoCreateInstance(CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,IID_IDataInitialize,(void**)&pIDataInitialize); if(FAILED(hResult)) { return hResult; } EAutoReleasePtr hResult = pIDataInitialize->GetDataSource(NULL, CLSCTX_INPROC_SERVER,(LPCOLESTR)szInitStr,IID_IDBInitialize,(IUnknown**)&pIDBInitialize); if(FAILED(hResult)) { return hResult; } hResult = pIDBInitialize->Initialize(); if(FAILED(hResult)) { return hResult; } * ppIDBInitialize = pIDBInitialize.Detach(); return S_OK;} HRESULT CreateSession(IDBInitialize* pIDBInitialize, IOpenRowset** ppIOpenRowset){ ASSERT(pIDBInitialize!= NULL && ppIOpenRowset!= NULL); EAutoReleasePtr HRESULT hResult = pIDBInitialize->QueryInterface(IID_IDBCreateSession,(void**)&pSession); if(FAILED(hResult)) { return hResult; } EAutoReleasePtr hResult = pSession->CreateSession(NULL, IID_IOpenRowset,(IUnknown**)&pIOpenRowset); if(FAILED(hResult)) { return hResult; } * ppIOpenRowset = pIOpenRowset.Detach(); return S_OK;} HRESULT CreateCommand(IOpenRowset* pIOpenRowset, ICommand** ppICommand, ICommandText** ppICommandText){ ASSERT(pIOpenRowset!= NULL && ppICommand!= NULL && ppICommandText!= NULL); HRESULT hResult; EAutoReleasePtr { EAutoReleasePtr hResult = pIOpenRowset->QueryInterface(IID_IDBCreateCommand,(void**)&pICreateCommand); if(FAILED(hResult)) { return hResult; } hResult = pICreateCommand->CreateCommand(NULL, IID_ICommand,(IUnknown**)&pICommand); if(FAILED(hResult)) { return hResult; } } EAutoReleasePtr hResult = pICommand->QueryInterface(&pICommandText); if(FAILED(hResult)) { return hResult; } * ppICommand = pICommand.Detach(); * ppICommandText = pICommandText.Detach(); return S_OK;} HRESULT ExecuteSQL(ICommand* pICommand, ICommandText* pICommandText, LPCTSTR pszCommand, LONG* plRowsAffected){ ASSERT(pICommand!= NULL && pICommandText!= NULL && pszCommand!= NULL && pszCommand[0]!= 0); HRESULT hResult = pICommandText->SetCommandText(DBGUID_DBSQL,(LPCOLESTR)pszCommand); if(FAILED(hResult)) { return hResult; } LONG lAffected; hResult = pICommand->Execute(NULL, IID_NULL, NULL, plRowsAffected == NULL ? &lAffected : plRowsAffected,(IUnknown**)NULL); return hResult;} 以上就是写数据库的全部代码了,是不是很简单呢?下面再来读的。 // 先用与上面代码中一样的步骤获取pICommand,pICommandText。此处省略 HRESULT hResult = pICommandText->SetCommandText(DBGUID_DBSQL,(LPCOLESTR)_T(”SELECT Volume FROM 2005_1 WHERE ID = @@IDENTITY"));//取我们刚刚添加的那一条记录 if(FAILED(hResult)){ return;} LONG lAffected;EAutoReleasePtr return;} EAutoReleasePtr return;} // 一个根据表中各字段的数值类型而定义的结构,用于存储返回的各字段的值 struct CLoadLastFromDB { DBSTATUS dwdsVolume; DWORD dwLenVolume; float fVolume;}; // 此处我们只查询了一个字段。如果要查询多个字段,CLoadLastFromDB中要添加相应的字段定义,下面的dbBinding也要相应扩充。dbBinding[].iOrdinal要分别指向各个字段,dbBinding[].wType要根据字段类型赋合适的值。 DBBINDING dbBinding[1];dbBinding[0].iOrdinal = 1; // Volume 字段的位置,从 1 开始 dbBinding[0].obValue = offsetof(CLoadLastFromDB, fVolume);dbBinding[0].obLength = offsetof(CLoadLastFromDB, dwLenVolume);dbBinding[0].obStatus = offsetof(CLoadLastFromDB, dwdsVolume);dbBinding[0].pTypeInfo = NULL;dbBinding[0].pObject = NULL;dbBinding[0].pBindExt = NULL;dbBinding[0].dwPart = DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH;dbBinding[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;dbBinding[0].eParamIO = DBPARAMIO_NOTPARAM;dbBinding[0].cbMaxLen = 0;dbBinding[0].dwFlags 该题库系统采用树状结构的设计方式,整个系统包含有多层子模块,在运行过程中以满足用户的需求,可实现多种功能系统具有以下主要功能:1)登录;2)系统维护;3)判分;4)帮助。系统结构图如图1所示。 2 数据库设计与维护 数据库技术作为信息技术主要技术之一,在社会各个领域有着广泛的应用,数据库设计的目标,是从满足用户要求、数据库性能、对现实世界的模拟程度、开发应用的速度与质量等方面加以考虑的,其设计策略为:对内,即对某个较为独立的日常事务为封闭式;而对外,即对整个目标系统,它又是开放式的,从而保证数据高质共享。设计一个合理的数据库,可为日后整理数据库节省时间,并能快捷地得到精确结果。 1)登录库:用于存考生及其学号信息,在该库中有学号、姓名、班级三个字段; 2)题库:用于存储考题信息,在该库中有科目、题型、分值、章节3个字段; 3)基本题库:用于存储大量教学及考试用题,在系统中采用了5个基本题库,分别是:填空题库、选择题库、判断题库、问答题库、计算题库,每个题库中的机构均相同,表征一道试题仅有图形与文字是不够的,用户有可能还要知道该道题的难度如何、题型、是否已选中,试题是否有图形以及答案等,所以在各个题库的字段如表1所示。其中“文字”字段采用备注型,用于存储详细的题目清单。数据库设计时所涉及到的程序较多,而且针对不同类型的科目考试也有所差异,但可通过对系统程序段进行有效的分类,用户可以根据各自不同的需求进行修改,得到相关的考试内容。同时,作为一个高性能的考试系统,应及时对数据库进行维护,因为维护不仅是维护其正常运行,而且也是设计工作的继续和提高。 进入题库维护模块,选择要增加的试题学科,输入题型、难度系数、试题的要求及答案等。试题可以有几种内容:1)文本;2)特殊字符;3)图形;4)前三种的任意组合。在系统结构设计时采用了文字与图形两字段:若是文本,则可在文字字段中输入文本;若是图形和文本,则在文字字段中输入文本,在图形字段中输入图形,若有特殊字符则可通过office创建对象插入通用型字段中。 另可以将是将已经存在的数据库追加到题库,数据库中要求两库字段类型相同,用户可根据需要选择一部分记录追加。 3 试卷的生成 假设题库已经存在,考试系统的输入信息是学生的学号,班级,要考科目。之后按一定的搜索算法在题库中选取符合用户要求的题目,送入成卷数据库,重复上述过程,直到生成一张试卷,并同时提示学生可以答题、倒计时始。 如果考生在输入信息后,系统在题库中搜索试题时总是自上而下顺序检索,则必然生成的试卷类似,或者选出的试题都是题库中位置靠前的结果。因此,在将题库里试题量扩充足够多的同时,在开始每一次搜索之前,随机地设置一个搜索起点,从这点开始在题库中分别向前和向后顺序搜索,直到找到相符合的记录,搜索起点start被定义为: start=mod(val(substr(time(1),10,2),m)*100,其中time()是VFP的时钟函数。Time()的返回值是当前的时钟字符串,时钟字符串的第10,11位是秒的小数位。变量m表示题库中的试题数量,这是必须考虑的因素,因为不允许start超出题库的范围以外。 4 判分 判分是一个重要模块,在数据库设计时就要考虑到这点,所以每题的后面都要有答案。但对于主观题来说判分就比较困难了,这里笔者采用通过OLE构件对象访问DOC文档方式解决的,Microsoft Office的所有程序都支持OLE 2.0,即Word程序可以作为OLE服务器,评分程序则作为OLE客户程序将DOC文档作为OLE对象嵌入到Word程序中,通过OLE 2.0 APIs评分程序便能访问DOC文档的信息。 考虑到大多数高校考试卷要进行备份,以备今后的检查,因此本考试系统特提供了VFP 6.0与Word的接口。这样,考试系统会把每个考生的答题情况生成一个文档。同时,将该文档存于服务器机器中,以备将来刻盘备份。VFP610与Word接口的代码如下: 5 帮助模块 考试系统的使用说明,即详细介绍该系统的操作,从学生登陆开始一直到提交试卷判分为止。 摘要:对于高校来说,期末考试工作即繁重又复杂,如果一贯以出试题,印试卷,判分这一形式考下去,将会浪费众多的人力物力。所以为学院开发考试系统是一个切实可行的措施。借鉴以往题库开发经验,利用VFP环境下开发考试系统。系统集出题,判分于一体,能大大提高工作效率,同时可构建多学科题库,改变题库难度、容量来适合不同专来不同层次的考生。 关键词:题库,考试系统,VFP 参考文献 [1]周焱.基于VFP6.0教学题库系统的开发[J].江南大学学报:自然科学版,2003,2(5). [2]王晶莹,王国辉.VFP数据库开发实例解析[M].北京:机械工来出版社,2004. [3]Microsoft公司.Microsoft Word 2000 Binary File Format[M].2003-08-03. [4]Bazian M.Visual Foxpro 6.0开发使用手册[M].北京:机械工来出版社,2000. 【关键词】网站规划 互联网媒体 网络编程和数据库 一、互联网新媒体 大家普遍认知的大众传媒主要包括报纸、广播、杂志、书籍和电影电视等媒介。随着数字化技术的发展,互联网技术迅速普及和网站的大量建立,互联网正成为一种新的媒体广泛进入人们的生活。人类社会,就要随着新一代信息传播新技术、新媒介进入一个信息传播的时代。 二、互联网的属性特点 信息资源丰富:目前全球网民数量已超过10亿,网上主机数量超过亿台,可检索的网页数约近百亿页,真正称得上“信息海洋”。 形态多样化:多媒体技术是将传统的、相互分离的各种信息传播形式(如语言、文字、声音、图像和影像等)有机地融合在一起,进行各种信息的处理、传输和显示。 传播范围广:不论在世界的哪个角落,只要计算机连入网络,那么你就可以将信息传送给他,或是获取他的信息。 三、如何建立门户网站 1.前期调查 建立门户网站之前,要进行大量的信息调查工作,弄清楚企业的商业信息是如何使用的。对于大多数企业而言,这意味着要进行商业信息应用的调查和研究。调查的目的是了解谁使用信息,信息是如何使用,以及信息如何流入和流出。 2.产品与技术的选择 在进行完信息的使用调查之后,企业就要选择门户产品和技术。门户软件不仅要满足商业信息和应用访问的需要,还要满足事先定义的技术层面(如协议)的要求。目前,由于有相当数量的公司推出了企业门户解决方案,这为企业提供了较大的选择余地。但不可否认,目前企业门户的产品良莠不齐,功能和所采用的技术差别较大,如何正确选择适合自身企业需要的企业门户产品是一门学问。 四、企业门户的建设 选好技术和产品,接下来就是建设了。这方面需要注意的是企业信息要集成到门户有关目录之下,或安排在某个主题里,以便用户可以容易地找到所需要的信息。信息的组织及个性化,应用和服务以能够满足用户的需求为目的。 五、网站技术解决方案 1.网站采用自主服务器。 2.网站设计采用的操作系统是 Window2003server 。申请PHP空间。 3.网站完全自己开发,基本模板来自互联网。 4.网页程序使用PHP 、 mysql数据库程序等。 六、网站规划设计要点 因特网正在改变世界,它促成了网络经济雏形的形成,特别是电子商务正由新概念走向实用化。由于因特网具有传播信息容量极大、形态多样、迅速方便、全球覆盖、自由和交互的特点,已经发展成为新的传播媒体,所以全球几乎各个企业、机构纷纷建立自己的Web站点。 Web站点是向用户或潜在客户提供信息(包括产品和服务)的一种方式。其文档所包含的内容是由被称为超文本(HyperText)的文本、图形图像、声音,甚至电影等组成。使这些超文本能够有机地关联并可使浏览器识别,是通过HTML语言(HyperText Markup Language超文本标记语言)实现的。同时CGI(Common Gateway Interface公共网关接口)能使Web具有交互功能。Web站点指引用户浏览该站点或其他站点上的分页信息,可以通过表格和电子邮件的连接提供双向交互方式。站点建立后,你的企业就在国内,甚至在国际上有了一席之地,有了每周7天、每天24小时的“虚拟门市部”。网站是未来企业开展电子商务的基础设施和信息平台,它是“知识经济”的制高点,企业的网址犹如企业的商标和品牌一样,是反映企业形象和文化的巨大的无形资产。 因此企业网站规划必须注意以下几个方面: 1.目标明确、定位正确 Web站点的设计是企业或机构发展战略的重要组成部分。要将企业站点作为在因特网——这个新媒体上展示企业形象、企业文化的信息空间,领导一定要给予足够的重视,明确设计站点的目的和用户需求,从而作出切实可行的计划。 挑选与锤炼企业的关键信息,利用一个逻辑结构有序地组织起来,开发一个页面设计原型,选择用户代表来进行测试,并逐步精炼这个原型,形成创意。 分析有些网站的效果不如预想的好,主要原因是对用户的需求理解有偏差,缺少用户的检验造成的。设计者常常将企业的市场营销和商业目标放在首位,而对用户和潜在的用户的真正需求了解不多。所以,企业或机构应清楚地了解本网站的受众群体的基本情况,如受教育程度、收入水平、需要信息的范围及深度等,从而能够有的放矢。 2.主题鲜明、富有特色 在目标明确的基础上,完成网站的构思创意即总体设计方案。对网站的整体风格和特色作出定位,规划网站的组织结构。 Web站点应针对所服务对象(机构或人)不同而具有不同的形式。有些站点只提供简洁文本信息;有些则采用多媒体表现手法,提供华丽的图像、闪烁的灯光、复杂的页面布置,甚至可以下载声音和录像片段。最好的Web站点将把图形图像表现手法与有效的组织与通信结合起来。 要做到主题鲜明突出,力求简洁,要点明确,以简单明确的语言和画面告诉大家本站点的主题,吸引对本站点有需求的人的视线,对无关的人员也能留下一定的印象。对于一些行业标志和公司的标志应充分加以利用。 1、strconn=Driver={Microsoft Access Driver(*.mdb)}; _ DBQ=F:Inetpubwwwrootsomedirdb1.mdb;DefaultDir= _ f:Inetpubwwwrootsomedir;uid=LoginID; _ pwd=Password;DriverId=25;FIL=MSAccess; set conn = server.createobject(adodb.connection) co 1、设顺序表L中的数据元素递增有序。试写一算法,将数据元素x插入到顺序表L的适当位置,以保持该表的有序性。 解:存储结构为: typedef struct SeqList { DataType *data; int MaxLen; int len;}SeqList;算法如下: void insertLx(SeqList &L, DataType x){ if(L.len==L.maxlen)return;int i=L.len-1;while(i>=0 && x 2、试写一个算法,在带头结点的单链表L的元素x前插入一个结点y。解:存储结构如下: typedef struct Lnode {ElemType data;struct Lnode *next;}Lnode, *LinkList;算法如下: void insert_y_before_x(LinkList L, ElemType x, ElemType y){ Lnode *q, *p=L; while(p->next && p->next->data!=x)p=p->next;//找x的前驱结点p;if(!p->next)return;// 若不存在结点x,则返回; q=new Lnode;q->data=y;q->next=p->next;p->next=q;} 3、试写一个算法,统计带头指针的单链表L的元素个数。解:存储结构如下: typedef struct Lnode {ElemType data;struct Lnode *next;}Lnode, *LinkList;算法如下: int length(LinkList L){ int len=0;Lnode *p=L;while(p){ len++;p=p->next;} return len;} 注:如果单链表是带头结点的,则算法如下: int length(LinkList L){ int len=0;Lnode *p=L->next;;while(p){ len++;p=p->next;} return len;} 4、试写一个算法,在带头结点的单链表L的第k个结点后插入一个结点x。解: 存储结构如下: typedef struct Lnode {ElemType data;struct Lnode *next;}Lnode, *LinkList;算法如下: void insert_after_k(LinkList L, int k, ElemType x){ if(k<0)return;Lnode *q, *p=L;int i=0;while(p && i q=new Lnode;q->data=x;q->next=p->next;p->next=q;} 注:如果是在L的第k个结点前插入一个结点,则找第k-1个结点p,然后插入。5、试写一个算法,在带头结点的单链表L中删除所有的数据元素为x的结点。解: 存储结构如下: typedef struct Lnode {ElemType data;struct Lnode *next;}Lnode, *LinkList;算法如下: void Delete_all_x(LinkList L, Elemtype x){ Lnode *p, *q;p=L;while(p){ if(p->next && p->next->data==x){q=p->next;p->next=q->next;delete q;} else p=p->next;} } 注意:要删除所有的值为x的结点。6、假设一个单循环链表L的数据域为整型,设计一个算法,求该表中所有结点的数据之和。解: 存储结构如下: typedef struct Lnode {ElemType data;struct Lnode *next;}Lnode, *LinkList; 假设L带头结点,且L指向头结点,则算法如下: int sum_Of_Data(LinkList L){ int s=0;Lnode *p=L->next;while(p!=L){s+=p->data;p=p->next;} return s;} 假设L不带头结点,且L指向循环链表中任何一个结点,则算法如下: int sum_of_data(LinkList L){ int s=0;Lnode *p=L;if(L){ s+=p->data;p=p->next;while(p!=L){ s+=p->data;p=p->next;} } return s;} 注:以上两种情形,只要给出其中一种情形的解即可。 7、假设二叉树用二叉链表存储,设计一个算法,求二叉树的结点个数。解:存储结构如下: typedef struct bitnode {ElemType data;struct bitnode *lchild, *rchild;}bitnode, *bitree;算法如下: int nodes(bitree T){ if(!T)return 0;else return(1+nodes(T->lchild)+nodes(T->rchild));} 8、写一个算法,建立二叉树的二叉链表。解:存储结构如下: typedef char ElemType;typedef struct bitnode {ElemType data;struct bitnode *lchild, *rchild;}bitnode, *bitree;算法如下: void creat_bitree(bitree &T){ //按扩展的先序序列输入结点,输入‘#’表示空。ElemType ch; cin>>ch;if(ch==’#’)T=0;else { T=new bitnode;T->data=ch;creat_bitree(T->lchuild);creat_bitree(T->rchild);} } 或者写成以下算法: bitree creat_bitree(void){ //按扩展的先序序列输入结点,输入‘#’表示空。bitree T;ElemType ch; cin>>ch;if(ch==’#’)T=0;else { T=new bitnode;T->data=ch;creat_bitree(T->lchuild);creat_bitree(T->rchild);} return T;} 9、假设一棵二叉树的先序序列为EBADCFHGIKJ,中序序列为ABCDEFGHIJK,请画出该二叉树,并写出后序序列。解:该二叉树如下: 后序序列为:ACDBGJKIHFE。 10、假设一棵二叉树的层次序列为ABCDEFGHIJ,中序序列为DBGEHJACIF,请画出该二叉树,并写出其先序序列和后序序列。解:该二叉树如下: 先序序列为:ABDEGHJCFI; 后序序列为:DGJHEBIFCA。 11、编写一个递归算法,将用二叉链表表示的二叉树的所有结点的左、右子树交换。解:存储结构如下: typedef char ElemType;typedef struct bitnode {ElemType data;struct bitnode *lchild, *rchild;}bitnode, *bitree;算法如下: void exchange(bitree &T){if(!T)return;bitree temp;temp=T->lchild;T->lchild=T->rchild;T->rchild=temp;exchange(T->lchild);exchange(T->rchild);} 12、试写出二叉链表表示的二叉树的先序遍历的非递归算法。解:存储结构如下: typedef char ElemType;typedef struct bitnode {ElemType data;struct bitnode *lchild, *rchild;}bitnode, *bitree;算法如下: void preorder(bitree T){ //先序遍历,当前结点入栈。#define MaxNum 20 bitree stack[MaxNum];int top=0;//指向栈顶的下一位置。bitnode *p;p=T;while(p || top>0){while(p){cout< 1:PLC编程语言有5种,即顺序功能图(SFC),梯形图(STL),功能块图,指令表,和结构文本。其中顺序功能图(SFC)是最容易理解的,按照时间的先后顺序执行。然后转换成梯形图,因为梯形图是PLC普遍采用的编程语言。不过SFC转换梯形图是很简单的。 2:就好比是开关在合上时两触点接触的一瞬间继电器就有动作了,这叫上升沿。 下降沿就好比开关两触点始终保持接触时,继电器没有动作,只有开关两点断开时的瞬间继电器才动作。 关键词:软件开发,数据库设计,前端编程,合理运用 常见的信息管理软件 (MIS) 通常由应用程序和数据库两部分组成, 这里通常涉及的数据库是关系数据库, 数据信息在其中被存储和处理。产品的开发过程中, 同时需要程序语言和数据库的设计。这就涉及到一个彼此份量的搭配问题, 亦即是程序设计多一些, 还是数据库设计多一些。 相信很多计算机软件工作者都有这样的经历, 上学时学习了各种程序设计语言和数据库设计。那时觉得数据库就是“select”, 程序语言就是流程和变量, 似乎二者没有必然联系, 当正式为用户开发产品时, 才发现原来这才是我们需要做的。于是写一些程序, 做一些表, 就成了最初带有数据库的应用软件。随着学习和实践的发展, 慢慢的技术熟练了, 但很多时候把握不好程序设计与数据库的搭配比例。 具体看两个案例:一个程序设计娴熟的软件开发工程师更善于用程序语言来实现功能, 结果他设计的数据库非常简单, 只是一些没有深度关联的表, 数据库在他手里就变成了一个纯粹的存储器, 而前端的程序设计才是他的重头戏!所以他采用了典型的微软组合VB+access, 结果一旦用户需求有更改, 就需要修改并重新编译和发布程序, 更严重的是用户数据量变大时, 该软件的运行效率急剧下降。另一个开发者或者意识到了数据库的优势, 于是数据库系统采用了sqlserver, 大规模进行了数据库的开发, 哪怕一个查询也要写成存储过程或者函数, 最后搞的产品还没有发布, 自己的维护人员却累个半死, 因为维护程序的人根本看不懂他写的程序, 数据库中也存在了太多的存储过程和函数, 查找起来非常繁琐。以上两种极端表现显然是不可取的。 软件的开发, 需要根据具体情况来设计。数据库的发明为软件业带来了很大好处, 很多数据的处理在数据库内部都是经过优化的, 因此适当地应用好数据库的设计可以简化前端程序的开发, 并且是便于维护和高效的。例如数据库的索引可以提高查询效率;一个复杂的查询可以用视图来实现, 这样在数据表变更时只需要调整视图而不用修改前端程序设计;约束可以帮助捕获运行中的异常和避免设计缺陷……然而不是说数据库是万能的, 数据库也不可能完全取代前端的程序设计。程序是可以做得很细, 从原理上是可以完成任何需要的合理的逻辑, 但是如果任何内容都用程序设计实现, 那么最后的应用程序会很庞大, 运行效率也不会很高甚至是累赘的。适当合理地利用数据库实现, 即可以保证处理速度, 又可以减少程序与数据库的交互次数, 从而整体上设计更合理, 效率也更高。 再看一个VB+access的简单例子, 我们需要在access中插入主键信息是整数的信息, 插入时前端程序需要知道当前插入信息的主键值, 所以要插入的信息的主键需要在应用程序中生成。在access中自动生成整形主键值有自增长和随机数两种方式, 显然这样的生成速度很快, 但是应用程序在插入数据时无法获得主键值, 因此在应用程序中可以模拟数据库自增长方式, 亦即查询出最大值然后加一再作为主键插入。但是这种自增长的方式会造成一个问题, 那就是整数资源的浪费, 例如数据库中有10条记录, 主键分别是1到10, 如果删除了中间几条, 再插入时新的主键会是11, 那么中间删除的几条的主键值便不可以再利用了, 这样的后果是将来数据量太大时, 主键值有超出计算机整数运算能力的范围。所以我们曾为了节约资源, 在前端应用程序中用了所谓“智能”的方法来充分利用闲置的整数资源, 这种方法需要遍历已存记录, 所以记录多时效率异常低下, 因为这样遍历交互次数太多了。最后解决的方法是, 第一, 把数据库中相应的字段类型更改为长整型尽量避免溢出;第二, 在应用程序端依然采用最大值加一的方式生成主键, 但是提供一个整体刷新的方法, 就是在一定时期后整体整理数据库中的主键, 使之从小到大重新更新并排序, 例如如果数据库中存在1、3、4、6、7, 我们使之整理成为1、2、3、4、5。如此即利用了数据库管理和批量集中整理的思想解决了这一问题。合理的利用不仅仅是直接使用, 还可以借鉴思想。 【数据库编程总结】推荐阅读: 数据库复习经典总结05-31 oracle数据库总结06-03 空间数据库实验总结07-14 数据库知识点重点章节总结07-16 施工经验数据总结10-07 数据结构课程总结06-27 数据结构期末总结07-13 数据分析实习总结10-16 数据质量提升活动总结10-28 数据库与数据库营销06-15数据库编程总结 篇2
数据库编程总结 篇3
几种连接数据库的asp编程代码 篇4
数据结构试题大题编程及参考答案 篇5
plc编程学习总结 篇6
前端编程与数据库设计的合理运用 篇7