第三章关系编程
本章描述了使用OCCI开发与关系数据库中存储数据协作的C++应用程序的基础。
本章包含以下主题:
?连接数据库
?池连接
?执行SQL DDL和DML语句
?OCCI环境中的SQL语句类型
?执行SQL查询
?动态执行语句
?提交事务
?缓存语句
?处理异常
连接数据库
关于应用程序连接数据库,有许多不同的选项。
创建和终止一个环境
所有的OCCI处理都在环境(Environment)类的上下文中发生。一个OCCI环境提供应用程序模式和用户指定的内存管理函数。下面是怎样创建一个OCCI环境的代码例子:Environment *env = Environment::createEnvironment();
所有使用createXXX方法(连接、连接池、语句)创建的OCCI对象必须被显式地终止,因此,在适当的情况下,也必须显式地终止环境。下面是终止OCCI环境的代码例子:Environment::terminateEnvironment(env);
另外,一个OCCI环境应当有一个比某些在此环境上下文中生成的对象类型更大的生命周期,这些对象类型包括:Agent,Bytes,Date,Message,InternalDS,InternalYM,Subscription and Timestamp 。这项规则不适用于BFile、Blob和Clob对象。下面的代码例子示范了这个概念:
const string userName = "SCOTT";
const string password = "TIGER";
const string connectString = "";
Environment *env = Environment::createEnvironment();
{
Connection *conn = env->createConnection(
userName, password, connectString);
Statement *stmt = conn->createStatement(
"SELECT blobcol FROM mytable");
ResultSet *rs = stmt->executeQuery();
rs->next();
Blob b = rs->getBlob(1);
cout << "Length of BLOB : " << b.length();
.
.
.
stmt->closeResultSet(rs);
conn->terminateStatement(stmt);
env->terminateConnection(conn);
}
Environment::terminateEnvironment(env);
如果应用程序需要访问像静态或者全局变量这样的全局范围的对象,在环境终止前必须将这些对象置为空(NULL)。在上述例子中,如果b是一个全局变量,那么在terminateEnvironment()调用之前必须生成一个b.setNull()的调用。
可以使用createEnvironment方法的模式参数来指定应用程序:
?在线程环境中运行(THREADED_MUTEXED 或者THREADED_UNMUTEXED)
?使用对象(OBJECT)
此模式可以在每个环境中独立设置。
打开和终止一个连接
环境(Environment)类是创建连接(Connection)对象的类工厂。首先生成一个环境(Environment)实例,然后使用这个实例让用户能够通过createConnection()方法连接到数据库。
下面的代码创建了一个环境实例并用它来为数据库用户scott(密码tiger)建立一个到数据库的连接。
Environment *env = Environment::createEnvironment();
Connection *conn = env->createConnection("scott", "tiger");
必须使用下面代码例子中的terminateConnection()方法在工作对话的最后显式地关闭连接。同样需要显式地终止OCCI环境。
所有在一个连接(Connection)实例中建立或命名的对象(Refs,Bfiles,Producers,Consumers 等等)都必须存在于这个实例的内部生命周期内;这些对象的生命周期在连接(Connection)终止前必须被显式地终止。
env->terminateConnection(conn);
Environment::terminateEnvironment(env);
池连接
本节讨论如何使用OCCI的连接池特性。主要包括下列主题:
?生成一个连接池
无状态池连接
二者主要的不同在于无状态连接池StatelessConnectionPools被用于不依赖于状态考虑的应用程序中,这些应用程序可以通过预认证的连接来提升性能。
创建一个连接池
对许多中间等级的应用程序来说,应当支持大量线程到数据库的连接。因为每个线程只存在相对短的时间,而为每一个线程打开一个到数据库的连接将导致连接利用的低效和性能的下降。
通过引入连接池特性,应用程序可以创建一个可为大量线程使用的小的连接集。使得数据库资源的使用更加有效。
创建一个连接池
使用createConnectionPool()方法生成一个连接池:
virtual ConnectionPool* createConnectionPool(
const string &poolUserName,
const string &poolPassword,
const string &connectString ="",
unsigned int minConn =0,
unsigned int maxConn =1,
unsigned int incrConn =1) = 0;
此例中使用了下列参数:
poolUserName :连接池的拥有者
poolPassword :访问连接池的密码
connectString :为连接池关联的数据库服务器指定的数据库名称
minConn :连接池生成后打开的最小连接数
maxConn :连接池维护的最大连接数。当连接池中打开最大数目的连接时,所有的连接都是繁忙状态,此时一个需要连接的OCCI方法等待直至得到其中一个空闲连接,除非连接池调用了一个setErrorOnBusy()。
incrConn :当所有连接是繁忙状态并且一个调用需要连接时所允许打开的多余连接的数量。这个增量只有在打开的连接总数少于连接池允许的最大数目时被实现。
下面的代码例子显示了何生成一个连接池:
const string connectString = "";
unsigned int maxConn = 5;
unsigned int minConn = 3;
unsigned int incrConn = 2;
ConnectionPool *connPool = env->createConnectionPool(
poolUserName,
poolPassword,
connectString,
minConn,
maxConn,
incrConn);
也可以动态配置所有的参数,从而设计一个具有读取目前负载(打开的连接数和繁忙的连接数)灵活性的应用程序,并且可以适当地调节这些参数。也可以使用setTimeOut()方法来设置比特定时间更大的空闲连接的超时值。OCCI周期性地终止空闲进程,以用来维护一个优化的打开连接数。
没有一个环境只能有一个连接池的限制。在一个单独的OCCI环境中可以存在多个连接池,这些连接池可以连接到同一个或不同的数据库。这对于要求负载均衡来说是有用的。
代理服务器连接
批准连接池用户作为其他连接的代理服务器,在使用连接池其中一个连接的数据库用户中不需要密码就可以记录日志。
一个代理连接可以使用下面任何一种方法生成:
ConnectionPool->createProxyConnection(
const string &username,
Connection::ProxyType proxyType = Connection::PROXY_DEFAULT);
或
ConnectionPool->createProxyConnection(
const string &username,
string roles[],
int numRoles,
Connection::ProxyType proxyType = Connection::PROXY_DEFAULT);
此例中使用了下列参数:
roles[] :此角色数组指定了一个角色列表,其中的角色在代理连接为客户端激活后被激活。Connection::ProxyType proxyType = Connection::PROXY_DEFAULT :枚举Connection::ProxyType 列举了表示到达代理认证的多种方式的常量。PROXY_DEFAULT被用于指示name表示一个数据库用户名并且是目前唯一支持的代理认证模式。
无状态池连接
无状态池连接是为那些需要短连接时间并且不需要处理状态考虑的应用程序而特殊设计的。其主要的优点在于提升性能,因为消耗在连接上的时间和认证协议被消除了。
无状态连接池生成并维护一组可以被多线程使用的无状态的,认证的到数据库的连接。一旦一个线程完成对连接的使用,应当将连接释放给连接池。如果没有可用的连接,新的连接被生成。因此,连接池中连接的数目是动态增长的。
连接池中的一些连接可能会被标记为指定的属性。用户可能要求一个默认的连接,设置特定的属性,例如全局化支持设置,对他进行标记并返回给连接池。当需要一个具有相同属性的连接时,可以生成一个相同标记连接的要求,连接池中具有相同标记的其中一个连接可以被复用。连接上的标记可以被改变或者重置。
代理连接也可以通过无状态连接池接口创建和维护。
无状态池连接通过多工连接来提升中端应用程序的级别。然而在大的事务中不应当使用一个
通过StatelessConnectionPool的连接,因为长时间保持连接会导致同步性下降。
--------------------------------------------------------------------------------------------------------------------------------- 警告:
?OCCI不会验证连接标记对的正确性。用户应当保证不同客户端属性的连接不使用同一个
标记。
?OCCI不会在释放连接前通过提交或回滚来移除连接的状态。如果当连接释放回连接池时
它的一个状态仍旧保持,当这个连接重用时仍然显示此状态。用户应当在将连接释放回连接池之前移除连接上的状态。
--------------------------------------------------------------------------------------------------------------------------------- 有两类无状态的连接池:
?同构连接池在建立连接池时提供用户名和密码用于认证所有连接。因此,所有的连接将
有同样的认证上下文。此类连接池不支持代理连接。
?在异构连接池中可以使用不同的用户名对不同的连接进行认证。在异构连接池中也可以
存在代理连接,前提是服务器为创建他们赋予必要的权限。
例3-1说明了一个对连接池的基本使用情景。例3-2展示了建立和使用同构无状态连接的使用情景,例3-3提供了异构连接池的用法。
例3-1 无状态连接池(StatelessConnectionPool)的使用情景
因为连接池大小是动态的,考虑到修改用户的要求,指定最大连接数。假设一个无状态连接池以下列的参数被创建:
minConn = 5
incrConn = 2
maxConn = 10
当连接池创建时打开五个连接:
openConn = 5
使用get[AnyTagged][Proxy]Connection()方法,用户消耗了所有五个打开的连接:openConn = 5
busyConn = 5
当用户需要另一个连接时,连接池将打开两个新的连接并返回其中一个给用户:openConn = 7
busyConn = 6
连接池中连接数的上限在连接池建立时由maxConn指定。
用户也可以使用setPoolSize()方法在连接池建立后修改其参数。
如果建立了一个异构的连接池,变量incrConn和minConn被忽略。
例3-2 怎样生成和使用同构无状态连接池
使用下列基本的步骤和伪代码命令生成一个同构无状态的连接池:
1.使用createStatelessConnectionPool()在环境(Environment)的同构模式中生成一个无状
态的连接池。
StatelessConnectionPool *scp =
env->createStatelessConnectionPool(
username, passwd, connectString, maxCon, minCon, incrCon,
StatelessConnectionPool::HOMOGENEOUS );
2.通过调用getConnection()方法从连接池中得到一个新的或已经存在的连接。
Connection *conn=scp->getConnection(tag);
执行这个调用时,在连接池中搜索一个与标记匹配的连接。如果这样的连接存在,就将其返
回给用户。否则,返回一个使用连接池用户名密码认证的非标记的连接。
另外,可以使用getAnyTaggedConnection()来得到一个连接。如果既没有匹配的标记
也没有空(NULL)标记可用时,此调用将会返回一个带有非匹配标记的连接。需要对使用getTag()返回的连接上的标记进行验证。
Connection *conn=scp->getAnyTaggedConnection(tag);
string tag=conn->getTag();
3.使用这个连接。
4.通过releaseConnection()释放这个连接到无状态连接池StatelessConnectionPool中。
scp->releaseConnection(conn, tag);
一个空标记,””,用于去掉此连接的标记。
在getConnection()中使用相同的标记参数值可以从无状态连接池中找回连接。
Connection *conn=scp->getConnection(tag);
除了将连接返回到无状态连接池外,可以使用terminateConnection()来销毁连接。
scp->terminateConnection(conn);
5.在环境Environment对象上通过aterminateStatelessConnectionPool()来销毁连接池。
env->terminateStatelessConnectionPool(scp);
例3-3 怎样生成和使用异构无状态连接池
使用下列基本的步骤和伪代码命令生成一个异构无状态的连接池:
1.使用createStatelessConnectionPool()在环境(Environment)的异构模式中生成一个无状
态的连接池。
StatelessConnectionPool *scp =
env->createStatelessConnectionPool(
username, passwd, connectString, maxCon, minCon, incrCon,
StatelessConnectionPool::HETEROGENEOUS);
2.通过调用以异构连接池选项重载的无状态连接池的getConnection()方法从连接池中得到
一个新的或者已经存在的连接。
Connection *conn=scp->getConnection(username, passwd, tag);
执行这个调用时,在连接池中搜索一个与标记匹配的连接。如果这样的连接存在,就将其返回给用户。否则,返回一个使用连接池用户名密码认证的非标记的连接。
另外,可以使用为异构连接池重载的getAnyTaggedConnection()来得到一个连接。如
果既没有匹配的标记也没有空(NULL)标记可用时,此调用将会返回一个带有非匹配标记的连接。需要对使用getTag()返回的连接上的标记进行验证。
Connection *conn=scp->getAnyTaggedConnection(tag);
string tag=conn->getTag();
也可以通过无状态连接池中的getProxyConnection()或者getAnyTaggedProxyConnection()调用来使用代理连接。
Connection *pcon = scp->getProxyConnection(proxyName, roles{}, nuRoles, tag, proxyType);
Connection *pcon = scp->getAnyTaggedProxyConnection( proxyName, tag, proxyType);
3.使用这个连接。
4.通过releaseConnection()释放这个连接到无状态连接池StatelessConnectionPool中。
scp->releaseConnection(conn, tag);
一个空标记,””,用于去掉此连接的标记。
在getConnection()中使用相同的标记参数值可以从无状态连接池中找回连接。
Connection *conn=scp->getConnection(tag);
除了将连接返回到无状态连接池外,可以使用terminateConnection()来销毁连接。
scp->terminateConnection(conn);
5.在环境Environment对象上通过aterminateStatelessConnectionPool()来销毁连接池。
env->terminateStatelessConnectionPool(scp);
执行SQL DDL和DML语句
SQL是工业范围内操作关系数据库的语言。在OCCI中使用Statement类执行SQL命令。
创建一个Statement对象
调用Connection对象的createStatement()方法创建一个Statement对象,如下所示:Statement *stmt = conn->createStatement();
创建一个执行SQL命令的Statement对象
一旦创建了一个Statement对象,通过调用对象中的execute(),executeUpdate(),executeArrayUpdate()或者executeQuery()方法来执行SQL语句。这些方法分别被用于下列目的:
?execute() :执行所有未指定的语句类型
?executeUpdate() :执行DML和DDL语句
?executeQuery() :执行一个查询
?executeArrayUpdate() :执行多重DML语句
创建一个数据库表
使用executeUpdate()方法,下面的例子说明了如何创建一个数据库的表:
stmt->executeUpdate("CREATE TABLE basket_tab (fruit VARCHAR2(30), quantity NUMBER)");
向表中插入数据
相似地,可以通过调用executeUpdate()方法执行SQL的INSERT语句:
stmt->executeUpdate("INSERT INTO basket_tab VALUES('MANGOES', 3)");
executeUpdate()方法返回SQL语句影响的行数。
参见:$ORACLE_HOME/rdbms/demo 中的代码例子,这些例子说明了如何在表中执行insert、select、update和delete操作。
重用Statement对象
可以重用Statement对象多次执行SQL语句。例如,通过Statement对象的setSQL方法指定语句,用于使用不同的参数反复执行相同的语句。
stmt->setSQL("INSERT INTO basket_tab VALUES(:1,:2)");
现在可以尽可能多次地执行INSERT语句了。如果稍后,需要执行一个不同的SQL语句,只需要简单地重置语句对象,例如:
stmt->setSQL("SELECT * FROM basket_tab WHERE quantity >= :1");
因此,OCCI语句对象和其相关的资源被分配或者在不需要时被释放。可以在任何时候通过getSQL()方法取回目前Statement对象的内容。
终止Statement对象
应当显式地终止和回收Statement对象。
Connection::conn->terminateStatement(Statement *stmt);
OCCI环境中的SQL语句类型
在OCCI环境中有三种类型的SQL语句:
?标准语句以特定的值使用SQL命令
?参数化语句存在参数,或者绑定变量
?可调用语句调用保存的PL/SQL存储过程
Statement方法被细分成这些可用于所有语句的类型、可用于用于参数化的语句类型和可用于可调用的语句类型。、
标准语句
前面的片段描述了DDL和DML命令,例如:
stmt->executeUpdate("CREATE TABLE basket_tab (fruit VARCHAR2(30), quantity NUMBER)");
和
stmt->executeUpdate("INSERT INTO basket_tab VALUES('MANGOES', 3)");
这些是可以显式定义语句值的标准语句的例子。因此,在这些例子中,CREATE TABLE语句指定了表名(basket_tab),INSERT语句中约定了需要插入的值('MANGOES', 3)。
参数化语句
可以通过为语句的输入变量设置占位符来使用不同的参数执行相同的语句。这些语句被视为参数化的语句,因为它们可以通过使用参数从一个用户或者程序接受输入。
例如:假设需要使用不同的参数执行一个INSERT语句,首先通过Statement对象的setSQL()方
法来指定语句:
stmt->setSQL("INSERT INTO basket_tab VALUES(:1, :2)");
然后调用setxxx()方法来指定参数,其中xxx代表参数的类型。下面的例子调用了setString()和setInt()方法来输入这些类型的值到第一和第二个参数中。
插入一行:
stmt->setString(1, "Bananas"); //第一个参数的值
stmt->setInt(2, 5); //第二个参数的值
指定参数后,向行中插入值:
stmt->executeUpdate(); //执行语句
插入另一行:
stmt->setString(1, "Apples"); //第一个参数的值
stmt->setInt(2, 9); //第二个参数的值
指定参数后,再次向行中插入值:
stmt->executeUpdate(); //执行语句
如果应用程序反复执行相同的语句,避免修改输入参数类型,因为每当输入类型修改需要重新绑定。
可调用语句
PL/SQL保存的存储过程,顾名思义,是存储在数据库服务器上用于被应用程序重用的过程。通过使用OCCI,一个包含其他SQL语句的过程调用视为可调用语句。
例如,假设需要调用一个过程countFruit(),返回指定种类的水果数量。像在参数化语句中那样调用Statement类的setXXX()方法,来指定PL/SQL中的输入参数。
stmt->setSQL("BEGIN countFruit(:1, :2); END:");
int quantity;
stmt->setString(1, "Apples"); // 指定过程的第一个(IN)参数
然而,在调用保存的存储过程前,需要通过调用registerOutParam()方法指定所有的输出参数的类型和大小。对于IN/OUT参数,使用setXXX()方法传递参数值,getXXX()方法取回结果。stmt->registerOutParam(2, Type::OCCIINT, sizeof(quantity));
//指定第二个(输出)参数的类型和大小
现在,通过调用过程执行语句:
stmt->executeUpdate(); //调用过程
最后,通过相应的getxxx()方法得到输出参数:
quantity = stmt->getInt(2); // 得到第二个(输出)参数的值
使用数组作为可调用语句的参数
PL/SQL保存的通过可调用语句执行的存储过程可以使用数组作为参数。数组中元素的数目和数组中元素的维度通过setDataBufferArray()来指定。
下面的例子展示了setDataBufferArray()方法:
void setDataBufferArray(
unsigned int paramIndex,
void *buffer,
Type type,
ub4 arraySize,
ub4 *arrayLength,
sb4 elementSize,
ub2 *elementLength,
sb2 *ind = NULL,
ub2 *rc = NULL);
此例中使用了下列参数:
paramIndex :参数号码
buffer :包含一组值得数据缓冲
type :数据缓冲中的数据类型
arraySize :数组中元素的最大数目
arrayLength :数组中元素的数量
elementSize :数组中目前元素的大小
elementLength :长度数组的指针。elementLength[i]存放数组中第i个元素的当前长度。
ind :指示信息
rc :返回代码
流式读写
OCCI支持插入和取回的流式接口,通过将数据截成小段来进行大规模数据的插入和取出操作。此方法最小化了客户端的内存需求。可以使用参数化语句来使用流式接口,正如SELECT和各种DML命令,也可以通过PL/SQL块中的可调用语句。流支持的数据类型有BLOB,CLOB,LONG,LONG RAW,RAW和VARCHAR2。
流式数据分为三类:
?可写流对应SELECT/DML语句中绑定的变量或者可调用语句中的输入(IN)参数。
?可读流对应一个在SELECT语句中取回的值或者可调用语句中的(OUT)参数。
?双向流对应一个绑定的IN/OUT变量。
通过Stream类的方法支持流式接口。
Stream类中的getStream()方法返回一个支持对DML和可调用语句读写的流式对象。
?对于写操作,将数据传向一个绑定的变量或者一个IN或IN/OUT参数。
?对于读操作,从一个输出或输入/输出参数中取回数据。
status()方法决定了流式操作的状态。
在流模式中绑定数据:SELECT/DML和PL/SQL
按照下面的步骤并参考例3-4在流模式中绑定数据:
1.使用合适的绑定占位符创建一个SELECT/DML或PL/SQL语句。
2.为每一个在流模式要用到的绑定位置调用Statement类的setBinaryStreamMode()和
setCharacterStreamMode()方法。如果绑定的位置是一个PL/SQL或IN/OUT参数类型,通过调用这些方法的三个参数的版本和设置inArg为TRUE来指示。
3.执行语句;Statement类的status()方法将返回NEEDS_STREAM_DATA。
4.通过Statement类的getStream()方法得到流式对象。
5.使用Statement类的writeBuffer()和writeLastBuffer()方法写数据。
6.使用Statement类的clostStream()方法关闭流。
7.在所有的流关闭后,Statement类的status()方法将改变相应的值,如
UPDATE_COUNT_AVAILABLE。
例3-4 在流模式中绑定数据
Statement *stmt = conn->createStatement(
"Insert Into testtab(longcol) values (:1)"); //longcol是LONG 类型的列
stmt->setCharacterStreamMode(1, 100000);
stmt->executeUpdate();
Stream *instream = stmt->getStream(1);
char buffer[1000];
instream->writeBuffer(buffer, len); //写数据
instream->writeLastBuffer(buffer, len); //重复
stmt->closeStream(instream); //stmt->status()是UPDATE_COUNT_AVAILABLE Statement *stmt = conn->createStatement("BEGIN testproc(:1); END;");
//如果testproc的参数是IN或IN/OUT,将TRUE传给setCharacterStreamMode或、、
//setBinaryStreamMode
stmt->setBinaryStreamMode(1, 100000, TRUE);
在流模式中取数据:PL/SQL
按照下面的步骤并参照例3-5从流模式中取数据:
1.使用合适的绑定占位符创建一个DML语句。
2.为每一个在流模式要用到的用于从流模式中取回数据的绑定位置调用Statement类的
setBinaryStreamMode()和setCharacterStreamMode()方法。
3.执行语句;Statement类的status()方法将返回STREAM_DATA_AVAILABLE。
4.通过Statement类的getStream()方法得到流式对象。
5.使用Statement类的readBuffer()和readLastBuffer()方法读数据。
6.使用Statement类的clostStream()方法关闭流。
例3-5 使用PL/SQL在流模式中取数据
Statement *stmt = conn->createStatement("BEGIN testproc(:1); END;");
//参数1 是OUT 类型
stmt->setCharacterStreamMode(1, 100000);
stmt->execute();
Stream *outarg = stmt->getStream(1);
//使用Stream::readBuffer/readLastBuffer 读取数据
在流模式中取数据:ResultSet
执行SQL查询和3-16页的例3-7提供了关于使用结果集的流式接口的解释。
使用多重流
如果要使用多重的读写流,需要保证一个流的读写完成于另一个流的读写之前。
使用Statement类的getCurrentStreamParam()方法或者ResultSet类的getCurrentStreamColumn()方法决定流的位置。如果流中有可以读取的数据,Statement类的status()方法会返回READY_FOR_READ,否则,如果数据已经被读取过了,将会返回INACTIVE,见表12-44。随后,应用程序可以读取下一个流式列。例3-6说明了如果使用两个同步的流进行读写操作。
例3-6 使用多重流读写
Statement *stmt = conn->createStatement(
"Insert into testtab(longcol1, longcol2) values (:1,:2)");
//longcol1 和longcol2 是插入到流模式中的两列
stmt->setBinaryStreamMode(1, 100000);
stmt->setBinaryStreamMode(2, 100000);
stmt->executeUpdate();
Stream *col1 = stmt->getStream(1);
Stream *col2 = stmt->getStream(2);
col1->writeBuffer(buffer, len); //第一个流
... //完成col1流的写操作
col1->writeLastBuffer(buffer, len); //转到col2
col2->writeBuffer(buffer, len); //第二个流
//读多重流
stmt = conn->createStatement("select longcol1, longcol2 from testtab");
ResultSet *rs = stmt->executeQuery();
rs->setBinaryStreamMode(1, 100000);
rs->setBinaryStreamMode(2, 100000);
while (rs->next())
{
Stream *s1 = rs->getStream(1)
while (s1->status() == Stream::READY_FOR_READ)
{
s1->readBuffer(buffer,size); //处理
} //完成第一个流
rs->closeStream(s1);
//移到下一列。rs->getCurrentStreamColumn() 返回2
Stream *s2 = rs->getStream(2)
while (s2->status() == Stream::READY_FOR_READ)
{
s2->readBuffer(buffer,size); //处理
} //关闭流
rs->closeStream(s2);
}
--------------------------------------------------------------------------------------------------------------------------------- 注意:不能与在同一个Statement和ResultSet对象中的setDataBuffer()方法一起使用这些流式接口。
--------------------------------------------------------------------------------------------------------------------------------- 参见:第11章“优化OCCI应用程序的性能”中11-6页的“应用程序管理的数据缓冲”
迭代修改行
当对每一行反复发出executeUpdate方法时,OCCI提供了一种在单独的网络往返中给多行数据发送数据的有效机制。在每个迭代中使用Statement类的addIteration()方法来进行修改不同行和批量操作。
为了迭代执行INSERT、UPDATE和DELETE操作,必须:
?设置最大迭代次数
?为变量长度参数设置最大参数大小
设置最大迭代次数
对于迭代操作,首先通过调用setMaxIterations()方法指定语句中完成的最大迭代次数:Statement->setMaxIterations(int maxIterations);
可以通过调用getMaxIterations()方法取出当前最大迭代次数。
设置最大参数大小
如果迭代操作中包括可变长度的数据类型,如string和Bytes,必须设置最大参数大小以便OCCI 分配最大的缓冲。
Statement->setMaxParamSize(int parameterIndex, int maxParamSize);
不需要为固定长度的数据类型设置最大参数大小,如Number和Date,或者那些使用setDataBuffer()方法的参数。
可以通过调用getMaxParamSize()方法取出当前最大参数大小。
执行迭代操作
在设置了最大迭代次数和最大参数大小(如果需要的话)后,就可以使用参数化的语句进行迭代操作了。
stmt->setSQL("INSERT INTO basket_tab VALUES(:1, :2)");
stmt->setString(1, "Apples"); // 第一行的第一个参数值
stmt->setInt(2, 6); // 第一行的第二个参数值
stmt->addIteration(); // 加入迭代
stmt->setString(1, "Oranges"); // 第二行的第一个参数值
stmt->setInt(1, 4); // 第二行的第二个参数值
stmt->executeUpdate(); // 执行语句
如上述例子所示,除了最后一次迭代,在每次迭代完成后调用addIteration()方法;最后一次迭代完成后,触发executeUpdate()方法。当然,如果没有必要插入第二行时,不需要调用addIteration()方法,或者做接下来的setxxx()方法。
迭代操作使用注解
?迭代操作只为使用标准或者参数化语句的INSERT,UPDATE和DELETE操作设计。不能用
于可调用语句和查询。
?在迭代之间不允许改变数据类型。例如,如果为参数1使用setInt(),在以后的迭代中就
不能为相同的参数使用setString()。
执行SQL查询
SQL查询语句允许应用程序从数据库中基于任何指定的限制请求信息。结果集作为查询的结果返回。
结果集
数据库的查询操作将查询的结果放到被称作结果集的行集合中。在OCCI中,一个SQL的SELECT语句通过Statement类的executeQuery方法执行。此方法返回代表查询结果的ResultSet对象。
ResultSet *rs = stmt->executeQuery("SELECT * FROM basket_tab");
可以操作结果集中已经有的数据。例如,需要打印表的内容。ResultSet类的next()方法被用于取数据,getxxx()方法被用于取结果集中单独的一列,如下面的例子所示:
cout << "The basket has:" << endl;
while (rs->next())
{
string fruit = rs->getString(1); // 得到string型的第一列
int quantity = rs->getInt(2); // 得到int型的第二列
cout << quantity << " " << fruit << endl;
}
ResultSet类的next()和status()方法返回Status,如表12-37定义。
如果数据对当前行可用,状态为DATA_AVAILABLE。在所有的数据被读取后,状态改为END_OF_FETCH。如果有任何输出流需要被读取,状态为STREAM_DATA_AVAILABLE,直到所有的流数据被成功读取。
例3-7说明了怎么样取流数据到结果集中,3-11页的“流式读写”提供了大致背景。
例3-7 使用结果集在流模式中取数据
char buffer[4096];
ResultSet *rs = stmt->executeQuery
("SELECT col1, col2 FROM tab1 WHERE col1 = 11");
rs->setCharacterStreamMode(2, 10000);
while (rs->next ())
{
unsigned int length = 0;
unsigned int size = 500;
Stream *stream = rs->getStream (2);
while (stream->status () == Stream::READY_FOR_READ)
{
length += stream->readBuffer (buffer +length, size);
}
cout << "Read " << length << " bytes into the buffer" << endl;
}
指定查询
IN绑定变量可用于在查询语句的WHERE子句中指定约束。例如,下列程序只打印那些最小量为4的项:
stmt->setSQL("SELECT * FROM basket_tab WHERE quantity >= :1");
int minimumQuantity = 4;
stmt->setInt(1, minimumQuantity); // 设置第一个参数
ResultSet *rs = stmt->executeQuery();
cout << "The basket has:" << endl;
while (rs->next())
cout << rs->getInt(2) << " " << rs->getString(1) << endl;
通过设置预取量优化性能
尽管ResultSet方法每次取一行数据,从服务器上取数据的实际操作不需要为每次单行的查询耗费一次网络的往返。为了最大化性能,可以设置每次到服务器的往返时所取得行数。
为了实现此功能,可以通过setPrefetchRowCount()方法设置预取的行数,或者通过setPrefetchMemorySize()方法设置预取用到的内存大小。
如果这两项均被设置,会预取指定行数,除非先达到指定的内存限制。如果达到了指定的内存限制,预取操作会返回适合由setPrefetchMemorySize()方法定义的内存空间尽可能多的行数。
预取是默认打开的,数据库会始终取多余的一行。通过设置预取行数和内存大小为0来关闭预取。
--------------------------------------------------------------------------------------------------------------------------------- 注意:如果LONG类型的列是查询中的一部分,预取是无效的。包含LOB列的查询可以被预取,因为LOB定位器,而不是数据,被查询返回。
--------------------------------------------------------------------------------------------------------------------------------- 动态执行语句
当需要执行一个DML操作时,使用executeUpdate方法。同样的,当执行一个查询时,使用executeQuery()方法。
如果应用程序需要允许动态事件,并且在运行时不确定需要执行哪一个语句,就需要使用OCCI提供的execute()方法。调用execute()方法返回下列状态:
?UNPREPARED
?PREPARED
?RESULT_SET_AVAILABLE
?UPDATE_COUNT_AVAILABLE
?NEEDS_STREAM_DATA
?STREAM_DATA_AVAILABLE
每当调用时execute()方法时会返回其中一个状态,也可以通过使用status方法询问这个语句。Statement stmt = conn->createStatement();
Statement::Status status = stmt->status(); // UNPREPARED状态
stmt->setSQL("select * from emp");
status = stmt->status(); // PREPARED状态
如果语句对象是用一个SQL字符串创建的,那么它是在PREPARED状态下创建的。例如:Statement stmt = conn->createStatement("insert into foo(id) values(99)");
Statement::Status status = stmt->status(); // PREPARED状态
status = stmt->execute(); // UPDATE_COUNT_AVAILABLE状态
当在此Statement上设置另一个SQL语句时,状态变为PREPARED。例如:
stmt->setSQL("select * from emp"); // PREPARED状态
status = stmt->execute(); // RESULT_SET_AVAILABLE状态
状态定义
本节描述了与语句对象相关的Status的可能值:
?UNPREPARED
?PREPARED
?RESULT_SET_AVAILABLE
?UPDATE_COUNT_AVAILABLE
?NEEDS_STREAM_DATA
?STREAM_DATA_AVAILABLE
UNPREPARED
如果未使用setSQL()方法为一个Statement对象赋予SQL字符串,那么语句是UNPREPARED状态。Statement stmt = conn->createStatement();
Statement::Status status = stmt->status(); // UNPREPARED状态
PREPARED
如果一个Statement对象使用SQL字符串创建,即以PREPARED状态创建。例如:
Statement stmt = conn->createStatement("INSERT INTO demo_tab(id) VALUES(99)"); Statement::Status status = stmt->status(); // PREPARED状态
在这个Statement对象上设置另一个SQL语句也会将其状态改为PREPARED。例如:
status = stmt->execute(); // UPDATE_COUNT_AVAILABLE状态stmt->setSQL("SELECT * FROM demo_tab"); // PREPARED状态
RESULT_SET_AVAILABLE
RESULT_SET_AVAILABLE状态说明一个已经执行了一个合适的公式化的查询,结果是可以通过结果集访问的。
当为一个查询设置了一个Statement对象,其状态是PREPARED。一旦执行了这个查询,状态改为RESULT_SET_AVAILABLE。例如:
stmt->setSQL("SELECT * from EMP"); // PREPARED状态
status = stmt->execute(); // RESULT_SET_AVAILABLE状态
为了访问结果集中的数据,使用下面的语句:
ResultSet *rs = Statement->getResultSet();
UPDATE_COUNT_AVAILABLE
当一个PREPARED状态的DDL或DML语句被执行,它的状态改变为UPDATE_COUNT_AVAILABLE,如下面的代码所示:
Statement stmt = conn->createStatement("INSERT INTO demo_tab(id) VALUES(99)"); Statemnt::Status status = stmt->status(); // PREPARED状态
status = stmt->execute(); // UPDATE_COUNT_AVAILABLE状态
状态与这条语句执行所影响的行数有关。即:
?语句不包括任何输入或输出流。
?不是查询语句,而是DDL或DML语句。
可以通过下面的语句得到受影响的行数:
Statement->getUpdateCount();
注意DDL语句的结果将更新计数为0。同样的,一个无任何匹配条件符合的update语句也将更新计数为0。在这样的情况下,不能通过报告的状态来推断语句的种类。
NEEDS_STREAM_DATA
如果存在任何需要写入的输出流,执行会直到流数据完全被提供后才结束。在这样的情况下,状态改为NEEDS_STREAM_DATA来指示必须写入一个流。在写入流后,调用status()状态来确定是否还需要写入更多的流数据,或者此次执行是否已结束。
当语句中含有多重流参数时,使用getCurrentStreamParam()方法来找到需要写入的那个参数。如果执行了一个迭代或者数组操作,getCurrentStreamIteration()方法揭示了要写入数据的那个迭代。
一旦处理完所有的流数据,状态改变为RESULT_SET_AVAILABLE或UPDATE_COUNT_AVAILABLE。
STREAM_DATA_AVAILABLE
这个状态显示应用程序在执行完之前需要向OUT或者IN/OUT参数读入一些流数据。在读取完流之后,调用status方法来确定是否有更多的流数据需要读取,或者此次执行是否已经结束。当语句中含有多重流参数时,使用getCurrentStreamParam()方法来找到需要写入的那个参数。如果执行了一个迭代或者数组操作,getCurrentStreamIteration()方法揭示了要写入数据的那个迭代。
一旦处理完所有的流数据,状态改变为UPDATE_COUNT_REMOVE_AVAILABLE。
ResultSet类也有可读的流并且像Statement类的可读流一样。
提交事务
所有的SQL DML语句均在事务的上下文中执行。一个应用程序通过提交或回滚一个事务来使语句造成的改变持久化。SQL COMMIT和ROLLBACK语句可以使用executeUpdate()方法执行,也可以调用Connection::commit()和Connection::rollback()方法。
如果希望立即提交DML作出的变化,可以通过触发下列语句打开Statement类的自动提交模式:
Statement::setAutoCommit(TRUE);
一旦自动提交生效,每次变化都会被自动固化。相当于每次执行后立即调用提交。
如果需要回到默认模式,关闭自动提交,触发下面的语句:
Statement::setAutoCommit(FALSE);
缓存语句
语句缓存特性在一个会话中建立并管理一个语句cache。通过有效利用客户端准备好的游标提升了应用程序的性能和规模,并且消除了重复的语句解析。
语句缓存技术可以用于连接和会话缓冲,也可以不使用连接池。典型的使用场景参见例3-8和例3-9。
例3-8 不使用连接池的语句缓存
下面的步骤和相应的伪代码实现了不使用连接池的语句缓存特性:
1.在Environment对象中利用createConnection()调用创建Connection对象。
Connection *conn = env->createConnection(username, password, connecstr);
2.在setStmtCacheSize()调用中使用非零的size参数启用Connection对象中的语句缓存。
conn->setStmtCacheSize(10);
接下来对getStmtCacheSize()的调用将决定缓存的大小,而利用setStmtCacheSize()调用改变语句缓存的大小,或者将size参数设置为零来关闭语句缓存。
3.在Connection对象中调用createStatement()创建一个Statement对象;如果缓存就绪,
Statement将返回,否则一个带有NULL标记的Statement将为用户创建。
Statement *stmt = conn->createStatement(sql);
使用createStatement()方法的变化形式来获取先前缓存的标记语句。
Statement *stmt = conn->createStatement(sql, tag);
4.利用语句执行SQL命令并得到结果。
5.将语句返回给缓存。
conn->terminateStatement(stmt, tag);
如果不希望缓存语句,使用disableCaching()调用和terminateStatement()的变化形式:stmt->disableCaching();
conn->terminateStatement(stmt);
如果需要确认一个语句是否被缓存,触发Connection对象中的isCached()调用。
在释放时可以选择标记一个语句然后为另一个语句使用同样的标记来重用它。标记将被用于搜索缓存。一个去掉标记的语句,其标记为NULL,是被标记语句的特例。
如果两个语句仅仅在标记上有差异,它们被视为不同的两个语句,或者只有它们其中一个被标记时。
6.终止连接。
例3-9 使用连接池的语句缓存
下面的步骤和相应的伪代码实现了使用连接池的语句缓存特性:
1.调用Environment的createConnectionPool()方法创建一个连接池。
ConnectionPool *conPool = env->createConnectionPool(username, password,
connecstr,minConn, maxConn, incrConn);
如果使用StatelessConnectionPool,调用createStatelessConnectionPool()。接下来的操作对于ConnectionPool和StatelessConnectionPool对象是一样的。
Stateless ConnectionPool *conPool = env->createStatelessConnectionPool(username,
password, connecstr, minConn, maxConn, incrConn, mode);
2.在setStmtCacheSize()调用中使用一个非零的size参数为连接池中所有连接启用语句缓存。
conPool->setStmtCacheSize(10);
接下来对getStmtCacheSize()的调用将决定缓存的大小,而利用setStmtCacheSize()调用改变语句缓存的大小,或者将size参数设置为零来关闭语句缓存。
3.在ConnectionPool对象中调用createConnection()从连接池中获得Connection对象;如果
Statement已经在缓存中,将其返回,否则一个带有NULL标记的Statement将为用户创建。
Connection *conn = conPool->createConnection(username, password, connecstr);
使用createStatement()方法的变化形式来获取先前缓存的标记语句。
Statement *stmt = conn->createStatement(sql, tag);
4.在Connection对象中调用createStatement()创建Statement对象;如果缓存就绪,则返回
Statement,否则一个带有NULL标记的Statement将为用户创建。
Statement *stmt = conn->createStatement(sql);
使用createStatement()方法的变化形式来获取先前缓存的标记语句。
Statement *stmt = conn->createStatement(sql, tag);
5.利用语句执行SQL命令并得到结果。
6.将语句返回给缓存。
conn->terminateStatement(stmt, tag);
如果不希望缓存语句,使用disableCaching()调用和terminateStatement()的变化形式:stmt->disableCaching();
conn->terminateStatement(stmt);
如果需要确认一个语句是否被缓存,触发Connection对象中的isCached()调用。
7.释放连接terminateConnection()。
conPool->terminateConnection(conn);
--------------------------------------------------------------------------------------------------------------------------------- 注意:
?语句缓存只用于setStmtCacheSize()调用后创建的连接。
?如果语句缓存在连接池级别未被启用,仍然可以为连接池中的每个单独连接实现。
--------------------------------------------------------------------------------------------------------------------------------- 处理异常
每个OCCI方法在其不成功时均会生成异常。异常的类型是SQLException。OCCI使用C++标准模板库(STL, Standard Template Library),因此能被STL抛出的任何异常也可以被OCCI方法抛出。STL异常从标准异常类中继承。exception::what()方法返回一个到下一个错误文本的指针。在捕捉块中错误文本保证为有效的。
SQLException类包含Oracle指定的错误代码和消息。它从标准异常类继承,所以也可以通过使用exception::what()方法获取错误文本。
除此之外,SQLException()类有两种用于获取错误信息的方法。getErrorCode()方法返回Oracle 错误代码。可以使用getMessage()方法返回与通过exception::what()方法相同的错误文本。getMessage()方法返回一个STL字符串,因此可以像其他STL字符串一样被复制。
基于错误处理策略,可以选择与标准异常不同的方式处理OCCI异常,或者可以选择不区分这二者。
如果选择不区分OCCI异常和标准异常,捕捉异常部分的代码会像下面这样:
catch (exception &excp)
{
cerr << excp.what() << endl;
}
如果决定与标准异常不同地处理OCCI异常,捕捉异常部分的代码会像下面这样:
catch (SQLException &sqlExcp)
{
cerr < } catch (exception &excp) { cerr << excp.what() << endl; } 在上面的捕捉异常部分中,SQL异常被第一个块捕捉,非SQL的异常被第二个块捕捉。如果颠倒这两个块的顺序,SQL异常将不会被捕捉。因为SQLException继承自标准异常,标准异常捕捉块也会处理SQL异常。 参见: ?在批量更新中发起的处理错误,关于其特殊特性的描述,参考“Optimizing Performance of OCCI Applications”部分,在11章的11-9页的“Modifying Rows Iteratively”。 ?参考Oracle Database Error Messages,获取有关Oracle错误消息的更多信息。 处理空值和删除的数据 通常情况下,在使用ResultSet()类的getxxx()方法获取数据值或Statement类为空(NULL)或被删除时不会导致异常。然而,可以通过调用setErrorOnNull()方法或setErrorOnTruncate()方法来改变这样的行为。如果setErrorxxx()方法以causeException=TRUE被调用,当一个数据值为空或已经被删除时会发起SQLException。 默认的行为是不发起一个SQLException。一个列或参数的值也可以为空(NULL),通过调用ResultSet或Statement对象的isNULL()方法,也可以返回TRUE。 rs->isNull(columnIndex); stmt->isNull(paramIndex); 如果列或参数的值被删除,通过调用ResultSet或Statement对象的isTruncated(),也可以返回TRUE。 rs->isTruncated(columnIndex); stmt->isTruncated(paramIndex); 对于通过setDataBuffer()方法和setDataBufferArray()方法取回的数据来说,异常处理行为由指示变量的存在与否控制,返回的代码如表3-1,3-2和3-3所示。 第三章 机械设计编程基础 2.1 编程和图表处理的基本方法 一、编制机械设计计算程序的基本方法 (1) 设计数据 (2) 表格、线图及标准规范 (3) 算法设计 [] p p dlh T σσ≤= 4 式中,T 为转矩; h 为键高度; l 为键的工作长度; [σp ]为轮毂的许用挤压应力。 表1 平键(摘自GB1096-90) 轴径 mm d mm b mm h 自6~8 2 2 >8 ~10 3 3 >10~12 4 4 >12~17 5 5 >17~22 6 6 >22~30 8 7 >30~38 10 8 >38~44 12 8 >44~50 14 9 二、设计图表处理的基本方法 1.表格(手册中的)分为两类:? ?? ..:;:着某种联系表格中的数据之间存在列表函数任何联系表格中的数据之间没有数表 2.表格处理的基本方法: (1) 表格的程序化:将数表中的数据以数组形式存储和检索,直接编 在解题的程序中。 (2) 表格的公式化:对于列表函数,可用曲线拟合的方法形成数学表 达式并直接编于程序中。 2-2 设计数表的处理 一、表格的程序化 1. 数表 一维(元)数表:所查取的数据只与一个变量有关的数表; 二维(元)数表:所查取的数据与两个变量有关的数表; 它们均可用一维和二维数组的形式存入计算机,以备程序使用。 一维(元)数表程序化 示例1 : 示例2 : int I; float GAMA[ ] ={ 7.87,7.85,8.30,7.75}; printf( “1. 工业纯铁\ n”); printf( “1. 钢材\ n”); printf( “2. 高速钢\ n”); printf( “3. 不锈钢\ n”); printf( “选择材料类型:”); scanf( “ % d”,&I); printf( “3. 不锈钢\ n”); printf( “材料的密度:% f\ n”,GAMA[I -1]); 表2 材料的密度 材 料 密度 / (g.。cm -3) 工业纯铁 7。87 钢 材 7。85 高 速 钢 8。30 不 锈 钢 7。75 第三章最简单的c程序设计 实践教学: 属性:实训 时间:学时。 实践教学内容: 实验目的:熟悉运算符、表达式,掌握标准输入输出函数的适用方法和顺序结构程序设计的一般方法。 实验内容和步骤: 1.编程,要求从键盘按规定的格式输入时间(时:分:秒), 并将输入的时间在屏幕上显示出来,存入ex3_1.c文件, 并编译、调试、运行。 #include 2.编程,要求从键盘输入数据,使整型变量a=10,b=8;字符 型c1=’A’,c2=’a’;实型变量x=3.1,y=64.54。并按规定格式输出变量的值。格式如下。存入ex3-2.c文件,并编译、调试、运行。 __int___a=__10___b=____8 char_c1=__A,___c2=____a float___x=_3.1,___y=64.54 #include 第3-1讲 第3章 单片机汇编语言程序设计 【课 题】MCS-51汇编语言编程 【授课方法】在专业教室讲授,举例说明汇编语言编程应用。 【目的要求】了解本课程汇编语言编程的基础知识; 理解MCS-51汇编语言编程方法; 掌握MCS-51汇编语言编程相关规定和硬件知识。 【重点难点】灵活运用与编程有关的规定。 【教学过程】1、复习 2、程序设计的重要性 3、程序设计方法 汇编语言程序设计 微型机应用离不开应用程序的设计。单片机程序设计多采用汇编语言编写。本章介绍 MCS51系统汇编语言程序编写的一般知识:有关规定、习惯用法、常见程序结构和编程方法。要学会编写程序应掌握编程的一般知识,还要分析一些经典程序,从修改现有程序入手,先简后难,循序渐进,最后达到自已设计应用系统和编写程序的目的。 3.1 单片机汇编程序设计方法与流程 3.1.1 汇编语言程序设计步骤 用汇编语言编制程序的过程,称为汇编语言程序设计。通常,汇编语言程序设计的步 骤如下:整个汇编程序设计的流程图见图3.1,当然、短小程序可能不要这么复杂。 1、设计规划,建立数学模型 设计前对项目作评估和规划,程序功能、运算精度、执行速度、各硬件特点、掌握设计的重点和难点。 2、选择适当的算法 对于同一个任务,往往可用不同的程序实现。此时应结合所用机器的指令系统,对不同的算法进行分析比较,经各方面综合考虑选择一种最佳算法,使程序精简,且执行速度快。 3、程序结构的设计 程序结构设计是把所采用的算法转化为汇编语言程序的准备阶段,特别是对于情况复杂的大型课题,必须进行程序结构设计。它可以分为模块化程序设计、结构程序设计及自顶向下设计等。 设计 课 题 划 设 计规算法模型绘流程程图编 制序汇编 调试试运行完成 修改程序 修改修改规划算法 流程 仿真图3.1汇编语言程序设计流程图 . 第三章简单程序设计 3.1 流程结构和语句 1 . 三种流程结构 顺序结构,选择结构,循环结构——程序在逻辑上执行的流程。 ●顺序结构:按语句在源程序中出现的次序依次执行; ●选择结构:根据一定的条件有选择地执行或不执行某些语句。 ●循环结构:在一定条件下重复执行相同的语句。 所有的流程控制都是由语句实现的,且任何一个表达式都可作为一个语句使用,成之为表达式语句 2. 表达式语句 任何表达式通过在其末尾加一个“;”,可使表达式成为一个语句,形式为: 表达式; 其中“;”是C语句的组成部分,表示一个语句结束。表达式语句能够独立出现在程序中,而表达式则不能独立出现。 例如:x=y+1 是表达式 x=y+1;是语句 习惯上把赋值表达式语句如:x=y+1;新为赋值语句。函数调用也是表达式,因此: printf(“hellow”)是表达式; printf(“hellow”);是语句,习惯上称为输出语句。 scanf(“%d%d”,&x,&y);函数调用表达式语句(输入语句) 3. C的语句概述 C的一个“说明”也必须以分号结束,也称为语句,因此C的语句分说明语句和执行语句两类。 说明语句可以出现在程序中任何块(函数或复合语句)的外面——称为外部说明或块内——称为局部说明(在执行语句的前面)。 外部说明必须放在一个源程序文件中所有函数定义的外面;局部说明包括类型定义、变量和函数说明,其作用是描述程序中被处理数据(变量或函数)的名称和类型供解释程序使用。 执行语句只能出现在函数体内且处于局部说明的后面,执行语句完成对数据的处理和对程序流程的控制。 常用的程序结构为: 常量说明 类型说明 变量说明/*外部说明*/ 返回类型函数名(参数表) { 变量说明/*局部说明*/ 执行语句 } 1. p138 第6题在同一坐标轴中绘制下列两条曲线并标注两曲线交叉点。 >> t=0:0.01:pi; >> x1=t; >> y1=2*x1-0.5; >> x2=sin(3*t).*cos(t); >> y2=sin(3*t).*sin(t); >> plot(x1,y1,'r-',x2,y2,'g-') >> axis([-1,2,-1.5,1]) >> hold on >> s=solve('y=2*x-0.5','x=sin(3*t)*cos(t)','y=sin(3*t)*sin(t)'); >> plot(double(s.x),double(s.y),'*'); 截图: p366 第4题绘制极坐标曲线,并分析对曲线形状的影响。 function [ output_args ] = Untitled2( input_args ) %UNTITLED2 Summary of this function goes here % Detailed explanation goes here theta=0:0.01:2*pi; a=input('请输入a的值:'); b=input('请输入b的值:'); n=input('请输入n的值:'); rho=a*sin(b+n*theta); polar(theta,rho,'k'); end 下面以a=1,b=1,n=1的极坐标图形为基础来分析a、b、n的影响。 对a的值进行改变:对比发现a只影响半径值的整倍变化 对b的值进行改变:对比发现b的值使这个圆转换了一定的角度 对n的值进行改变:对比发现当n>=2时有如下规律 1、当n为整数时,图形变为2n个花瓣状的图形 2、当n为奇数时,图形变为n个花瓣状的图形 分别让n为2、3、4、5 课堂教学教案 教师姓名:课程名称:Java程序设计授课时数:2 第3次课 附录3 3.1 Java程序的构成 3.2 数据类型、变量与常量 ●语言成分 1. 关键字: 由Java语言定义的,具有特定含义的单词 2. 标识符: 以字母开头的字母数字序列 标识符命名规则①②③④⑤ 3.分隔符 3.2.1 基本数据类型 1. 什么是数据类型 2. 数据类型分类 1)基本数据类型 2)引用数据类型 3. 基本数据类型 3.2.2 变量与常量 ?Java 标识符 ?类名(接口名)—名词 第一字母大写,每一单词首字母大写。 例:AccountBook ?方法名—动词 第一字母小写,每一单词首字母大写。 例:balanceAccount() ?变量名—名词 第一字母小写,每一单词首字母大写。 ?常量名 全部大写,单词间用下划线分开 . 例:HEAD_COUNT ?Java标识符要区分大小写 标识符中的合法字符:字母、数字、_ 、$ (非数字开头) ?数据类型与说明语句 ?Java程序中所处理的数据是将各种数据类型实例化后的数据。 ?数据类型实例化的方法:说明语句 ?实例化数据的两种形式:变量与常量 ?数据类型与说明语句 ?基本数据类型说明语句例:(同时给变量赋初值) ?Java几乎是将字符串视为基本数据类型 ?常数表示法(字面值) ?布尔常数true false ?整型常数 一般常量:32bit 长整型常量:64bit (88L) 十进制数:非0开头的正负整数105,-23 八进制数:0开头的正负整数017(15), -023(-19) 十六进制:0x开头的正负整数0x2F(47),-0xa8(-168) ?浮点常数 一般浮点常量(32bit) 3.14F 6.18E3F 双精度浮点数(64bit ) 7.56D 6.02E23 (D可省) 3.3 表达式 ?数据类型转换 ?同种数据类型转换: 短类型→ 长类型:默认(系统自动转换) 长类型→短类型:强制 ?布尔型与其他数据类型之间不能强制类型转换 ?Wrapper类 ?Wrapper类例-Integer ?属性 static int MAX_VALUE 返回int型数据的最大值 static int MIN_VALUE 返回int型数据的最小值 ?构造方法 Integer(int value) Integer(String s) ?方法 int intValue() double doubleValue() String toString() static String toString(int i) static Int parseInt(String s) static Integer valueOf(String s) ?类型转换-利用类/对象方法 ?利用类方法(静态方法) Integer.parseInt("23") //返回整数23 Integer.toString(23) //返回字符串"23" Double.parseDouble("12.3") C语言第三章顺序结构程序设计期末测试习题与答案 1、关于算法的描述,下列正确的是 ( )。 A.一个算法可以没有输入,但必须有输出 B.一个算法必须要有输入,但可以没有输出 C.一个算法有几个输入就必须有几个输出 D.一个算法如果没有输入,则此算法是错误的 参考答案:A 2、算法的每一个步骤都应是确切定义的,不能有二义性,相同的输入应该得到相同的输出,这是算法的 ( )。 A.确定性 B.可行性 C.正当性 D.有穷性 参考答案:A 3、以下程序片段: int x=2,y=3; printf(); 的运行结果是 ( )。 A.输出为:x=2 B.输出为:x=2,y=3 C.输出为:y=3 D.什么都不输出 参考答案:D 4、已知a,b,c为int型变量,若从键盘输入:2,3,4<回车>,使a的值为2,b的值为3,c的值为4,以下选项中合法的输入语句是 ( )。 A.scanf(“a=%d,b=%d,c=%d”,&a,&b,&c); B.scanf(“%dV%dV%d”,&a,&b,&c); C.scanf(“%d,%d,%d”,&a,&b,&c); D.scanf(“%2d%3d%4d”,a,b,c); 参考答案:C 5、若int a,b; double x; 以下不合法的scanf函数调用语句是 ( )。 A.scanf(“%3d%*3d%lf”,&a,&b,&x); B.scanf(“%ld%lo%o”,&a,&b,&x); C.scanf(“%o%f%lo”,&a,&b); D.scanf(“%d%o%f”, &a,&b,&x); 参考答案:C 6、有输入语句:scanf(“a=%db=%dc=%d”,&a,&b,&c);为使变量 a的值为1,b的值为3,c的值为5,则正确的数据输入方式是 ( )。 A.a=1b=3c=5↙ B.1,3,5↙ C.135↙ D.a=1 b=3 c=5↙ 参考答案:A 7、putchar ( )函数可以向终端输出一个 ( )。 A.整型变量表达式值 B.字符或字符型变量值 C.字符串 D.实型变量值 3.1编程序:用getchar函数读入两个字符给c1,c2,然后分别用putchar和printf函数输出这两个字符。并思考以下问题:(1)变量c1,c2应定义为字符型或整型?或两者皆可?(2)要求输出C1和C2值的ASCII 码,应如何处理?用putchar函数还是printf函数?(3)整型变量与字符型变量是否在任何情况下都可以互相替代? 1、#include 第三章JSP语法基础习题 一、选择题 1.JSP的编译指令标记通常是指:() A)Page指令、Include指令和Taglib指令 B)Page指令、Include指令和Plugin指令 C)Forward指令、Include指令和Taglib指令 D)Page指令、Param指令和Taglib指令 2.可以在以下哪个()标记之间插入Java程序片?() A)<% 和%> B)<% 和/> C) 和%> D)<% 和!> 3.下列哪一项不属于JSP动作指令标记?() A) 智慧树知到程序设计基础(C语言)测试第三章单元测试参考答案 ?总题数: 10 1 【判断题】 (10分) 表达式25/3%3的值为2. A.错 B.对 正确 本题总得分10分 2 【判断题】 (10分) 若有定义:int y=2; 则计算表达式y+=y后的y值是2() A.对 B.错 正确 本题总得分10分 3 【单选题】 (10分) 下列不正确的叙述是()。 A.在C语言程序中,SUM和sum是两个不同的变量。 B.若a和b类型相同,在计算了赋值表达式a=b后b中的值将复制到a 中,而b中的值不变。 C.在C语言程序中,%运算符的优先级高于/ 运算符。 D.在C语言程序中,进行赋值运算时,先将右侧表达式的值转化左侧变 量的类型再赋给变量。 正确 本题总得分10分 4 【单选题】 (10分) 在C语言中,要求运算对象必须是整型的运算符是()。 A.- B.% C.* D./ 正确 本题总得分10分 5 【单选题】 (10分) 下列选项中正确的定义语句是()。 A.double a ; b; B.double a=7,b=7; C.double , a , b; D.double a=b=7; 正确 本题总得分10分 6 【单选题】 (10分) 输入一个3位正整数n,分别输出n的个位a、十位b、百位c。下面程序的语句填空应为:() #include 1.概念填空题 1.1一个C++程序是由一个或多个函数所组成,即使是最简单的程序,也必须有一个main函 数。该函数是程序执行的起点和终点。C++中,函数不允许嵌套定义,允许嵌套调用。 1.2 函数执行过程中通过return 语句将函数值返回,当一个函数不需要返回值,需要使用 void 作为类型名。 1.3 在C++中,如果函数定义在后,调用在先,需要原型声明。其格式和定义函数时的函 数头的形式基本相同,但参数表中形参不是必须的,同时必须以; 结尾。 1.4 递归程序分两个阶段执行递推,回归。 1.5 函数名相同,但对应形参表不同的一组函数称为重载函数,参数表不同是指类型不 同或参数个数不同。 1.6 内联函数的展开、重载函数的确定均在编译阶段进行。 1.7 静态局部变量存储在全局数据区,在程序运行时候建立,生命期为整个程序 ,如定义 时未显式地初始化,则其初值为0。局部变量存储在栈区,在块或函数开始运行时候建立,生命期为块或函数,如定义时未显式地初始化,则其初值为随机数。 2.简答题 2.1 函数的作用是什么?如何定义函数?什么叫函数原型? 2.2 什么叫形式参数?什么叫实际参数?C++函数参数有什么不同的传递方式?请写一个验 证程序说明。 2.3 C++函数通过什么方式传递返回值?若返回引用类型时,是否可以返回一个算术表达式? 为什么? 2.4 变量的生存期和变量作用域有什么区别?请举例说明。 2.5 静态局部变量有什么特点?编写一个应用程序,说明静态局部变量的作用。 3.选择题 3.1正确的函数定义形式为(A )。 A.void fun(void) B.double fun(int x;int y) C.int fun(int=0,int); D.double fun(int x,y) 3.2 C++语言中规定函数的返回值的类型是由(D)。 A.return语句中的表达式类型决定 B.调用该函数时的主调函数类型决定 C.调用该函数时系统临时决定 D.定义该函数时所指定的函数类型决定 3.3 若有函数调用语句:fun(a+b,(x,y),(x,y,z));此调用语句中的实参个数为(A)。 A.3 B.4 C.5 D.6 3.4 C++中,关于默认形参值,正确的描述是(C)。 A.设置默认形参值时,形参名不能缺省 B.只能在函数定义时设置默认形参值 C.应该先从右边的形参开始向左边依次设置 D.应该全部设置 3.5 若同时定义了如下函数,fun(8,3.1)调用的是下列哪个函数(D)。 A.void fun(float,int) B.void fun(double,int) 《C语言程序设计》课程教案表 printf(“%d,%o”,a,a); 输出结果为:-1,177777 这是因为-1在内存中以补码形式存放(见图3-2)。八进制数为从低位开始,以三位一组划分为一个八进制数。 3)x格式符。以十六进制数无符号形式输出整数。 例如: int a=-1; printf(“%x,%o,%d”,a,a,a); 输出结果为:ffff,177777,-1 十六进制数为从低位开始,见图3-2,以四位一组划分为一个数。 4)u格式符。以十进制数无符号形式输出整数。一个有符号的(int)型数据可以用%d格式输出,也可以用%u格式输出。要注意两类数据的取值范围大小。 例如:无符号数据的输出。 main() { unsigned int x=65535; int y=-1; printf(“x=%d,%o,%x,%u\n”,x,x,x,x); printf(“y=%d,%o,%x,%u\n”,y,y,y,y); } 运行结果为: x=-1,177777,ffff,65535 y=-1,177777,ffff,65535 即-1的二进制形式以无符号形式输出时为整数65535。 5)c格式符。用来输出一个字符。 例如:char x=’A’; printf(“%c,%d\n”,x,x); 运行结果为:A,65 可以看出,一个范围在0~255的整数,既可以用%d格式输出,也可以用%c格式输出。输出该整数或者整数对应ASCII的字符。 6)s格式符。用来输出一个字符串,该格式有以下用法: ①%s例如:printf(“%s”,”HELLO”);运行结果为:HELLO ②%±ms,如果%ms字符串的实际宽度小于m,右对齐,左端补空格,%-ms,字符串左对齐,右端补空格;否则,不受m限制,输出实际宽度。 ③%±m.ns,若%m.ns取字符串左端n个字符,输出在m列的右端,左端补空格;%-m.ns,取字符串左端n个字符,输出在m列的左侧,右侧补空格;若m 1 / 1 第3章 https://www.doczj.com/doc/ee10868621.html, 的内置对象 3.8.1 作业题 1.使用Response 对象,在Default.aspx 上输出系统当前日期和时间。如图1所示: 图1 作业题3-1 2. 创建一个网页Default.aspx, 用户输入姓名、年龄, 如图2所示。单击“确定”按钮后,页面跳转到Welcome.aspx,并显示用户刚才输入的信息,如图3所示。要求只能采用Response 和Request 对象,页面跳转采用GET 请求。 图2 Default.aspx 图3 Welcome.aspx 3. 实现不同身份的用户,登录后进入不同的页面。在Default.aspx 的下拉列表中只有 admin 和user 选项 ,如图4所示。根据登录的用户名,分别进入Admin.aspx 和 User.aspx,并且显示如图5、图6所示的欢迎信息。要求采用Session 对象来实现。 图 4 Default.aspx 图 5 Admin.aspx 图 6 User.aspx 4.在作业题3的基础上分别统计admin 和user 的访问量,要求用Application 对象来实现。如图7——图9所示 图7 Default.aspx 图8 Admin.aspx 图9 User.aspx 5. 如图所示 ,在默认主页输入昵称,进入网站中的另一个页面NewPage, 显示欢迎信息和客户端IP 地址。若是第一次访问,用cookie 存储本次访问的时间。下次再访问时,显示上次访问的时间。要求采用server 对象进行页面跳转并传递参数。如图10——图12所示。 图10 输入昵称 图11 第一次访问时的欢迎信息 图12 非第一次访问时的欢迎信息 见“课后习题源代码”文件夹下的“homework3-1——homework3-5” 且要求m>n。 P=m!/(n!(m-n)!),例如,m=12,n=8时,运行结果为495.000000。 注意:部分源程序给出如下。 请勿改动main函数和其他函数中的任何内容,仅在函数fun的注释语句之间填入所编写的若干语句。 试题程序:*/ #include 入。S=1+1/(1+2)+1/(1+2+3)+…+1/(1+2+3+…+n) 例如,若n的值为11时,函数的值为1.833333。 注意:部分源程序给出如下。 请勿改动main函数和其他函数中的任何内容,仅在函数fun的花括号中填入所编写的若干语句。 试题程序: */ #include 第三章顺序结构程序设计 一、结构化程序设计: 1.程序是命令的有序集合,命令执行的顺序即程序的结构。 2.在结构化程序设计中,把所有程序的逻辑结构归纳为三种:顺序结构、选择结构和循环 结构。 3.结构化程序设计概述: 结构化程序设计的原则:自顶向下→逐步细化→模块化设计(所谓模块化设计,就是按模块组装的方法编程。把一个待开发的软件分解成若干个小的简单部分,称为模块。)→结构化编码(编码俗称编程序)。 二、算法: 1. 算法就是一种在有限的步骤内解决问题或完成任务的方法。 2. 计算机程序就是告诉计算机如何去解决问题或完成任务的一组详细的、逐步执行的指令 集合。 3. 数据时操作的对象,操作的目的是对数据进行加工处理,以得到期望的结果。 4. 算法的流程成图表示法: 起止框:输入/输出操作:判断框:流程线: 5. 基本算法: 累加,累乘,求最大或最小值。 穷举:穷举就是一种重复型算法。它的基本思想是对问题的所有可能状态一一测试,直到找到解或将全部可能状态都测试过为止。 迭代:是一个不断用新值取代变量的旧值,由旧值递推出变量的新值过程。 递归:算法自我调用的过程,一种算法是否称为递归,关键取决于该算法定义中是否有它本身。 排序:是在待排序记录中按照一定次序排列数据的过程。 查找:是在数据列表中确定目标所在位置的过程。(顺序查找:可在任何列表中查找,对半查找:要求列表是有序的) 三、C语句概述: 1. 表达式语句:在各种表达式后加一个分号构成的语句。 2. 函数调用语句:在函数调用的一半形式后加一个分号构成的语句,其作用是完成特定的 功能。一般形式:函数名(实参表); 3. 空语句:只有一个分号的语句称为空语句,其形式如:;空语句在语法上占据一个语 句的位置,但是它不具备任何操作功能。 4. 复合语句:用一对花括号“{}”将多条语句括起来构成的语句体。形式{语句组} 5. 控制语句:C程序设计中用来构成分支结构和循环结构并完成一定控制功能的语句。 ●条件语句:if …else。 ●多分支选择语句:switch ●当型循环语句:while,for ●直到循环型循环语句:do…while ●终止本次循环语句:continue ●终止整个循环或跳出switch语句:break ●无条件转移语句:goto ●函数返回语句:return 四、输入/输出语句: /*习题3 2*/ #include c语言详解(第五版)第三章程序设计项目答案 1.假设买一辆车首付为500dollar。请计算月供。 #include 学号:姓名:成绩: 程序设计基础(C)第三章顺序结构习题 一、选择题 1 若a、b、c、d 都是int 类型变量且初值为0,以下选项中不正确的赋值语句是()。 A) a=b=c=100; B) d++; C) c+b; D) d=(c=22)-(b++); 2 以下选项中不是C 语句的是()。 A) {int i; i++; printf("%d\\n", i); } B) ; C) a=5,c=10 D) { ; } 3 以下合法的C 语言赋值语句是()。 A) A=B=58 B) k=int(a+b); C) a=58,b=58 D) --i; 4 以下程序的输出结果是()。 A) 0 B) 1 C) 3 D)不确定的值 main() { int x=10,y=3; printf("%d\\n", y=x/y); } 5 若变量已正确说明为int 类型,要给a、b、c 输入数据,以下正确的输入语句是()。 A) read(a,b,c); B) scanf("%d%d%d",a,b,c); C) scanf("%D%D%D",&a,&b,&c); D) scanf("%d%d%d",&a,&b,&c); 6 若变量已正确说明为float 类型,要通过以下赋值语句给a 赋予10、b 赋予22、c 赋予33,以下不正确的输入形式是()。 第3章https://www.doczj.com/doc/ee10868621.html,的内置对象 3.8.1 作业题 1.使用Response对象,在Default.aspx上输出系统当前日期和时间。如图1所示: 图1 作业题3-1 2. 创建一个网页Default.aspx,用户输入姓名、年龄,如图2所示。单击“确定” 按钮后,页面跳转到Welcome.aspx,并显示用户刚才输入的信息,如图3所示。要求只能采用Response和Request对象,页面跳转采用GET请求。 图2 Default.aspx 图3 Welcome.aspx 3. 实现不同身份的用户,登录后进入不同的页面。在Default.aspx的下拉列表中只有admin和user选项,如图4所示。根据登录的用户名,分别进入Admin.aspx和User.aspx,并且显示如图5、图6所示的欢迎信息。要求采用Session对象来实现。 图4 Default.aspx 图5 Admin.aspx 图6 User.aspx 4.在作业题3的基础上分别统计admin和user的访问量,要求用Application对象来实现。如图7——图9所示 图7 Default.aspx 图8 Admin.aspx 图9 User.aspx 5. 如图所示,在默认主页输入昵称,进入网站中的另一个页面NewPage,显示欢迎信息和客户端IP地址。若是第一次访问,用cookie存储本次访问的时间。下次再访问时,显示上次访问的时间。要求采用server对象进行页面跳转并传递参数。如图10——图12所示。 图10 输入昵称 图11 第一次访问时的欢迎信息 图12 非第一次访问时的欢迎信息 见“课后习题源代码”文件夹下的“homework3-1——homework3-5” 程序设计基础-C语言(科学出版社教材) 第三章-程序结构教材习题答案 1.0编写程序使整形变量:a=3,b=4,c=5,p=0xfffe,q=0xffff;浮点型变量:x=1.2,y= 2.4,z= 3.6;无符号型变量:u=5127486,n=128765,字符型变量:c1=’a’,c2=’b’; #include printf("x+y=%.2f y+z=%.2f x+z=%.2f\n",x+y,y+z,x+z); printf("u=%8u n=%8u\n",u,n); printf("c1='%c' or %d\n",c1,c1); printf("c2='%c' or %d\n",c2,c2); } 2.0 读入三个双精度数,求出它们的平均值并保留此平均值小数点后二位,最后输出结果。 #include 第三章机械设计编程基础
第三章 最简单的c程序设计
第三章 汇编程序设计
第三章-简单程序设计word版本
matlab程序设计第三章课后习题答案
第三章java程序设计教案
C语言 第三章 顺序结构程序设计期末测试习题与答案
第三章 程序设计基础
jsp编程基础第三章习题
智慧树知到程序设计基础(C语言)测试第三章单元测试参考答案
C++程序设计教程 课后答案第三章 李秉璋
《C语言程序设计》教案第三章程序的控制结构—顺序结构
ASP。net程序设计基础教程第2版03-第三章-课后习题答案.doc
第三章:程序设计
第三章 顺序结构程序设计
c语言程序设计第三章课后答案
c语言详解(第五版)第三章程序设计项目答案
程序设计基础(C)第三章顺序结构习题
ASP。net程序设计基础教程第2版03_第三章-课后习题答案
程序设计基础-c语言-第三章程序结构-教材习题答案-科学出版社