occiwrapper使用指南
occiwrapper是一个开源的、跨平台的Oracle访问组件, 方便C++开发者们灵活地操作oracle数据库。为了方便使用,组件中的接口形式参考的POCO库的使用方式。occiwrapper采用如下的形式执行SQL语句:
1 occiwrapper::Session s = SessionInstance( connection ); 2 s << "truncate table TBL_TEST ", now;
通过session对象维护一个到oracle的会话。类似于流的操作方式,向session中传入SQL语句,并执行。
在oracle参数绑定方面,Occiwrapper可以直接将C++变量绑定到oracle参数中,在以后的文档说明中详细介绍。
1 occiwrapper::Session s = SessionInstance( info ); 2 struct tm tm_value; 3 s << "insert into TBL_TEST( date_value ) values ( :1 )", use( tm_value ), now;
同时,对于vector等容量变量,可以灵活地直接绑定到oracle的绑定变量上,同时也可以灵活的将select语句返回的结果绑定到容器中,而且对于使用者来讲,并不用关心类型的对应关系。为了提高存取的性能,写入和读取都采入批量操作的方式,同时采用智能指针自动管理内存缓冲池,最大限度地解放了oracle开发者。
1 occiwrapper::Session s = SessionInstance( info ); 2 vector< int > vec1; 3 s << "select A from tbl_test2 t", into( vec1 ), now;
组件中使用的很多技术都是在工作中一些经验的积累与总结,由于自己认识oracle不够深刻,对C++的理解也可能不够深入,希望大家多多讨论。对于大家发现的Bug,我也会尽快修改,同时热情欢迎大家积极参与库的修改。
源代码地址:https://github.com/CUCmehp/occiwrapper
1、下载和安装
1.1 第三方组件依赖
本组件依赖oracle公司的occi(Oracle C++ Calling Interface)动态库支持。连接不同的oracle版本,须要选择不同的occi版本。
关于occi的详细介绍,请参见oracle公司官方文档。
1.2 开发环境
在Windows系统下,可以通过Visual Studio 2008 SP1或者Visual Studio 2010进行编译。
在linux系统下,可以通过g++编译器进行编译。
1.3 运行环境
本组件可跨平台支持Windows和Linux操作系统。
1.4 数据库环境
test工程中所有测试用例用到的数据库表、存储过程、函数,都可以通过db文件夹中的脚本创建。
方法:
(1)通过具有system权限的用户执行脚本create_user.sql。
(2)使用用户occiwapper(密码为occiwrapper)执行occiwrapper.sql。
注:所有测试用例中均使用occiwrapper作为oracle的用户名。
1.5 测试
所有的测试代码存放在源码的test目录下,在windows、linux(Suse 10, Suse 11,openSuse12, redhat 6企业版, Centos 6 )下进行了相关的测试。数据库连接信息的配置文件放在db_config.ini中。
在程序在oracle 11gR2和12cR1(oracle 12.1)对应的occi版本下进行了测试。
2、 编译说明
2.1 Windows
- 使用Visual Studio 2008 SP1工具
使用Visual Studio 2008直接打开工程occi_wrapper_vs2008.sln,选择Debug和Release进行编译。
注:要求vs2008 sp1以上,是由于occiwrapper中使用了tr1库,而vs2008从SP1版本以上,才开始支持tr1库。
- Visual Studio 2010
使用Visual Studio 2010直接打开工程occi_wrapper_vs2010.sln,选择Debug和Release进行编译。
说明:源码中include/occi_11g目录下,存放着oracle 11.2.0.2 64位数据库对应的头文件,在lib_vs2008和lib_vs2010目录下,存放着11.2.0.2版数据库对应的lib库文件。在bin_vs2008和bin_vs2010目录下,存放着对应的dll文件。
若需要使用其它版本的occi库版本,则将上述文件替换为需要使用的occi库文件。
2.2 Linux
linux下使用,需要先下载oracle occi库对应的头文件和动态库文件。在oracle数据库的OCI/lib目录下,通常可以找到这些文件。若未安装oracle数据库,则可以从官网上下载:http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html
头文件对应文件包为:instantclient-sdk-linux.x64-*.*.*.*.*.zip
库文件对应文件包为:instantclient-basic-linux.x64-*.*.*.*.*.zip
只需要选择需要的oracle版本,下载对就的文件就可以,然后解压,记得将so文件放在系统运行时扫描的目录,如/usr/local/lib、/usr/lib等目录,也可以将so的目录添加到/etc/ld.so.conf配置文件中。
下载occiwrapper.tar.gz包,并在linux下解压,执行以下命令:
tar -zxvf occiwrapper.tar.gz
genConfigure.sh生成可执行的权限,使用以下命令:
chmod +x genConfigure.sh
运行此命令,运行的格式如下:
./genConfigure.sh --occi-include=occi_include_path_value --occi-lib=occi_lib_path_value
其中occi_include_path_value对应着occi头文件的目录,occi_lib_path_value对应着occi库文件的目录,比如头文件放在/u01/install/oracle_client/instantclient_12_1/sdk/include/,库文件存放在/u01/install/oracle_client/instantclient_12_1/,则执行的命令为:
./genConfigure.sh --occi-include=/u01/install/oracle_client/instantclient_12_1/sdk/include/ --occi-lib=/u01/install/oracle_client/instantclient_12_1/
成功执行后,目录下会生成configure文件,然后执行./configure,默认安装在/usr/local目录下,也可以自己指定安装的目录,执行:
./configure --prefix=/usr/local/occiwrapper
编译程序,执行make命令。
make
最后进行安装,执行
make install
执行成功后,在/usr/local/occiwrapper目录下,存放着生成的include和lib文件,测试文件存放在test目录下,test目录下的db_config.ini为测试库对应的配置信息。要执行test程序,需先在oracle数据库中执行db文件夹下的脚本。
3. 使用指南
本部分主要介绍调用occiwrapper组件的方法,包括以下部分:
- oracle连接;
- 创建一个会话;
- 执行DDL语句;
- 执行简单插入;
- 使用绑定变量插入;
- 执行update操作;
- Commit与Rollback;
- 执行存储过程;
- 调用函数;
- 执行select语句并保存结果;
- 处理oracle中的日期类型
- 关于NULL值的处理;
3.1 Oracle连接
occiwrapper组件通过类occiwrapper::ConnectionInfo结构来保存oracle连接信息。
1 occiwrapper::ConnectionInfo info; 2 info.ip = "127.0.0.1"; 3 info.port = 1521 4 info.username = "occiwrapper"; 5 info.password = "occiwrapper"; 6 info.sid = "orcl";
要建立一个oracle连接,需要先申请一个oracle的Environment变量,函数内部通过调用OCCI的createEnvironment函数创建Environment。
oracle::occi::Environment::createEnvironment( oracle::occi::Environment::THREADED_MUTEXED );
参数取值默认使用了THREADED_MUTEXED,关于OCCI创建Environment的参数有如下定义:
DEFAULT: not thread safe, not in object mode;
THREADED_MUTEXED: thread safe, mutexed internally by OCCI;
THREADED_UN-MUTEXED: thread safe, client responsible for mutexing;
OBJECT: uses object features
occiwrapper组件通过封装Environment,将Environment的创建与销毁同发者隔离起来,开发者不需要关心何时去关闭Environment。
通过类Connection可以方便的管理oracle的数据库连接,该类屏封了默认构造函数和拷贝构造函数。只能通过静态方法GetConnection得到一个数据库连接。
以下示例完整的给出了,如何创建一个oracle连接。
1 shared_ptr< occiwrapper::Environment > pEnv = occiwrapper::Environment::CreateEnvironment(); 2 assert( pEnv->CreateEnvironment() != NULL ); 3 occiwrapper::ConnectionInfo info; 4 info.ip = "127.0.0.1"; 5 info.username = "occiwrapper"; 6 info.password = "occiwrapper"; 7 info.sid = "orcl"; 8 assert( occiwrapper::Connection::GetConnection( shared_ptr< occiwrapper::Environment >( pEnv ), info ) != NULL );
上述代码中,shared_ptr为C++ 0x标准中提出的tr1库定义的智能指针,关于C++ 0x和tr1库,在此不做介绍,大家可以参见维基百科。
occiwrapper使用连接池对oracle数据库连接进行管理,对于相同的数据库连接进行复用;同时,通过连接池,对oracle连接进行管理,以下代码给出了如何使用occiwrapper的连接池,取得oracle连接。
1 occiwrapper::ConnectionInfo info; 2 occiwrapper::ConnectionPool connPool; 3 info.ip = "127.0.0.1"; 4 info.username = "occiwrapper"; 5 info.password = "occiwrapper"; 6 info.sid = "orcl"; 7 shared_ptr< occiwrapper::Connection > p = connPool.GetConnection( info ); 8 assert( p != NULL); 9 assert( p->GetValidity() == occiwrapper::VALID ); 10 shared_ptr< occiwrapper::Connection > other = connPool.GetConnection( info ); 11 assert( connPool.GetConnMapSize() == 1 );
3.2 创建一个会话
Session类用来管理客户端与oracle服务器之间的会话连接。通过会话连接,客户端可以灵活的创建出若干Statement来执行SQL命令。
occiwrapper通过类SessionFactory来创建session会话,SessionFactory是一个以单件形式存在的工厂类,可以动态的创建出Session对象。同时,SessionFactory中内置了一个连接池对象管理oracle连接。关于连接池对象,可以参考3.2节创建一个会话中的介绍。
以下代码给出了如何使用SessionFactory创建一个Session对象。
1 occiwrapper::ConnectionInfo info; 2 occiwrapper::Session s = occiwrapper::SessionFactory::Instance().Create( info, false );
为了方使创建Session,也可以使用宏定义。
1 occiwrapper::Session s = SessionInstance( info );
3.3 执行DDL语句
利用Session对象可以方便地执行DDL命令,如下示例演示如何创建一张表,再将它清空,最后删除该表。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet = false; 4 string strErrMsg = ""; 5 s << "create table tbl_test( x int )", now, bRet, strErrMsg; 6 s << "truncate table tbl_test", now, bRet, strErrMsg; 7 s << "drop table tbl_test", now, bRet, strErrMsg;
3.4 执行简单插入
对于简单的insert操作,指不使用绑定变量的insert操作。如何利用occiwrapper进行绑定变量插入,将在下两节中进行介绍。本节只介绍执行最简单的SQL语句。
例如,对于一张已知的表TBL_TEST1,该表只含有一个整数字段X。以下的代码数字10004插入到该表中。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet = false; 4 string strErrMsg = ""; 5 s << "insert into tbl_test1( x ) values ( 10004 )", now, bRet, strErrMsg;
Session执行的结果会被保存bRet中,若执行出错,在strErrMsg中输出出错原因。
3.5 使用绑定变量进行插入
绑定变量是oracle编程中一个重要的使用技巧。通过绑定变量的使用,能够显著的提高多次执行同一条SQL语句的性能。在此不在赘述。
下面分两类进行介绍,包括绑定简单变量和绑定容器。
- 绑定简单变量
绑定简单变量,将简单数据类型变量,如int, float, double, string, struct tm等绑定到oracle的绑定变量上。
下表给出了occiwrapper支持的绑定类型
表1 Windows下occiwrapper支持的绑定类型定义
occiwrapper 类型定义 |
操作系统类型 |
Int8 |
signed char |
UInt8 |
unsigned char |
Int16 |
signed short |
UInt16 |
unsigned short |
Int32 |
int |
UInt32 |
unsigned int |
Int64 |
signed __int64 |
UInt64 |
unsigned __int64 |
float |
float |
double |
double |
struct tm |
struct tm |
std::string |
std::string |
表2 Linux下occiwrapper支持的绑定类型定义
occiwrapper 类型定义 |
操作系统类型 |
Int8 |
signed char |
UInt8 |
unsigned char |
Int16 |
signed short |
UInt16 |
unsigned short |
Int32 |
int |
UInt32 |
unsigned int |
Int64 |
signed long |
UInt64 |
signed long long |
float |
float |
double |
double |
struct tm |
struct tm |
std::string |
std::string |
occiwrapper通过use关键字进行简单变量绑定。如执行use(1),将数字1绑定到对应的绑定变量上; 执行use(“hello world”)将字符串hello world绑定到对应的绑定变量上。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet = false; 4 string strErrMsg = ""; 5 s << "insert into tbl_test1( x ) values ( :1 )", use( 2 ), now, result, err_msg; 6 cout << "result: " << result << endl << "error message: " << err_msg << endl; 7 assert( result ); 8 s << "insert into test_string( id, string_val ) values( :1, :2 )", use( 2 ), use( "CUCmehp" ), now, result, err_msg; 9 cout << "result: " << result << endl << "error message: " << err_msg << endl; 10 assert( result ); 11 s << "insert into test_number( id, number_value ) values( :1, :2 )", use( 1 ), use( 3.5 ), now, result, err_msg; 12 cout << "result: " << result << endl << "error message: " << err_msg << endl; 13 assert( result );
对于同一个Session也可以多次进行绑定,进行复用,以下代码向表TBL_TEST1中插入0到9。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet; 4 string strErrMsg; 5 s << "truncate table tbl_test1", now; 6 occiwrapper::Statement stmt = s << "insert into tbl_test1( x ) values( :1 )"; 7 for( int i = 0; i < 10; ++ i ) 8 { 9 stmt, use( i ), now, bRet, strErrMsg; 10 assert( bRet ); 11 }
- 绑定容器
绑定容器是指把表中的若干列与一个或多个容器(1.0.0版本仅支持vector容器)相绑定。
如下图所示,一个表有A、B、C三列,可以将列A的数据与变量vector<A>进行绑定,将列B、列C的数据绑定到vector< tuple< B, C> >变量中,tuple为元组类型,其定义可以参见C++ 0x标准,定义在库tr1中。
利用occiwrapper的batched_use关键字可以灵活的实现上述绑定,以下示例给出了将数组{20,21,22,23,24}所生成的vector,批量插入到表TBL_TEST1中。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet; 4 string strErrMsg; 5 int a[5] = { 20, 21, 22, 23, 24 }; 6 vector< int > vec( a, a + 5 ); 7 s << "insert into tbl_test1( x ) values ( :1 )", batched_use( vec ), now, bRet, strErrMsg; 8 assert(bRet);
以下示例给出了如何绑定到两个vector或者一个vector<tuple>结构中。表TEST_STRING中含有两个字段ID、STRING_VAL,分别为integer和varchar2类型。示例中,首先将一个vector<int>变量和vector<string>变量绑定到这两列上,进行插入操作。然后,将一个vector< tuple<int,string> >变量绑定到这两列上。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet; 4 string strErrMsg; 5 int a[5] = { 20, 21, 22, 23, 24 }; 6 vector< int > vec( a, a + 5 ); 7 string strArray[5] = { "message1", "message2", "message3", "message4", "message5" }; 8 vector< string > vecStr( strArray, strArray + 5 ); 9 s << "insert into test_string( id, string_val ) values ( :1, :2 )", batched_use( vec ), batched_use( vecStr ), now, bRet, strErrMsg; 10 assert( bRet ); 11 s << "truncate table test_string", now, bRet; 12 assert( bRet ); 13 vector< tuple< int, string > > vecTuple; 14 for( size_t i = 0; i < 5; ++ i ) 15 { 16 vecTuple.push_back( make_tuple( vec[ i ], vecStr[ i ] ) ); 17 } 18 s << "insert into test_string( id, string_val ) values ( :1, :2 )", batched_use( vecTuple ), now, bRet, strErrMsg; 19 assert( bRet );
3.6 执行update操作
执行update操作的方式,跟执行DDL和select语句的方式基本相同,同样可以使用绑定变量。以下给出了简单的例子。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet = false; 4 string strErrMsg = ""; 5 s << "truncate table tbl_test1", now, bRet, strErrMsg; 6 s << "insert into tbl_test1( x ) values ( 10004 )", now, bRet, strErrMsg; 7 s << "update tbl_test1 set x = :1 where x = 10004", use( 10005 ), now, bRet, strErrMsg;
示例代码先向表TBL_TEST1中的X字段插入数值10004,然后将数值修改为10005。
3.7 Commit与Rollback
Occiwrapper支持两种形式的commit操作。在创建Session时,可以指定Commit的类型,isAutoCommit参数为true,则表示每次操作后,自动进行commit,否则需要手工commit或者rollback,操作才能生效。以下代码给出了示例。
1 occiwrapper::Session s = occiwrapper::SessionFactory::Instance().Create( info, false ); 2 s << "truncate table tbl_test1", now; 3 s.Commit(); 4 bool bRet = false; 5 string strErrMsg = ""; 6 s << "insert into tbl_test1( x ) values ( 10005 )", now, bRet, strErrMsg; 7 s.Rollback(); 8 occiwrapper::Statement stmt2 = ( s << "insert into tbl_test1( x ) values ( 10005 )" ); 9 for ( int i = 0; i < 2; ++i) 10 { 11 stmt2.execute(); 12 } 13 s.Commit();
首先创建一个不会自动提交的Session对象,然后向表中插入数值10005,但并不提交,反而撤销。此时,用PL/SQL工具查看该表,发现表为空。连续执行两次insert操作后,提交。此时,表中有两条记录。
3.8 执行存储过程
对于oracle存储过程,有输入参数与输出参数之分,输入参数是向oracle中传入的参数,而输出参数是从oracle中传出的参数。在使用use关键字是,附加PAR_IN指定参数为输入参数,附加PAR_OUT指定参数为输出参数。
在下面的例子中,存储过程p_test_procedure含有两个参数,第一个参数为int类型,第二个参数为varchar2,函数实现了将int参数转化为string后,由参数2输出。
下面的代码块给出了上述过程。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet; 4 string strErrMsg; 5 int nParIn = 1000; 6 string strParOut = ""; 7 s << "begin p_test_procedure( :1,:2 ); end;", use( nParIn, occiwrapper::PAR_IN ), use( strParOut, occiwrapper::PAR_OUT ), now, bRet, strErrMsg; 8 assert( bRet ); 9 assert( strParOut == "1000" );
3.9 调用函数
调用函数的方法与调用存储过程类似,只不过函数有返回值,类型为输出类型。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet; 4 string strErrMsg = “”; 5 int a = 0; 6 s << "begin :1 := f_ins_tbl_test1( :2 ); end;", use( a, occiwrapper::PAR_OUT ), use( 2, occiwrapper::PAR_IN ) , now, bRet, strErrMsg; 7 assert( bRet ); 8 int b; 9 s << "begin :1 := f_test2( :2, :3 ); end;", use( a, occiwrapper::PAR_OUT ), use( 2 ), use( b, occiwrapper::PAR_OUT ), now, bRet, strErrMsg; 10 assert( bRet );
3.10 执行select语句并保存结果
select操作是SQL操作中最常见的操作之一,将oracle中的数据取到内存中。occiwrapper通过关键字into实现将数据库中的一个字段绑定到一个容器中。
1 vector< string > vStr; 2 vector< struct tm > vDate; 3 vector< occiwrapper::Int32 > vInt; 4 vector< float > vFloat; 5 vector< double > vDouble; 6 s << "select string_value, date_value, int_value, float_value, number_value from test_batched_table", into( vStr ), into( vDate ), into( vInt ), into( vFloat ), into( vDouble ), now, bRet, strErrMsg; 7 assert( bRet );
上述代码段将表tbl_batched_table中的数据读取,并存到5组vector变量中。
occiwrapper内部采用了批量读取的方式,提高了读取的性能,同时内部自动管理批量绑定时所需要内存空间。
当表中数据量比较大,只取若干条数据时,可以使用Limit关键字。
下列代码段给出了示例:
1 vector< int > vec1; 2 vector< int > vec2; 3 // test limit select 4 s << "select * from tbl_test2 t", into( vec1 ), into( vec2 ), occiwrapper::Limit( 3 ), now;
occiwrapper在读取时,并没有提供游标的操作(考虑到游标会影响对于底层的封装性),直接将内存中的容器对象(vector)与oracle的数据表进行了绑定。因此,当数据表中的数据量很大时,vector的插入受限于内存,故本组件更适应单表数据量在百万条以下的应用场景。当然,开发者为了防止插入时vector出错内存用尽,如将一个1亿条记录的数据,分100次插入到100W的vector容量中,每次调用批量入库,这样做也是能够成功的。然而,由于没有提供游标相关的操作,该表无法将1亿条记录一次绑定到一组vector中(会std bad allocate异常),从而形成了无法处理的窘境。因此,本组件更适合单表数据量在百万条以下规模的应用。
3.11 处理oracle中的日期类型
为了处理oracle中的Date类型,occiwrapper对外处理的类型为struct tm类型,即occiwrapper插入和读取的类型都采用struct tm类型。
示例代码中,给出了如何向表中插入当前时间,并如何将当向时间从oracle数据库中读到一个vector数组中。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 bool bRet; 4 string strErrMsg; 5 struct tm tmValue; 6 time_t nowTime = time( NULL ); 7 localtime_r( &nowTime, &tmValue); 8 s << "truncate table test_date", now, bRet, strErrMsg; 9 s << "insert into test_date( date_val ) values ( :1 )", use( tmValue ), now, bRet; 10 vector< struct tm > vTmDb; 11 s << "select date_val from test_date", into( vTmDb ), now, bRet, strErrMsg;
3.12 关于NULL值的处理
当数据库表中取出空值时,occiwrapper在向容器中插入时,用默认值进行处理。下表给出了各种类型的默认值。
occiwrapper 类型定义 |
默认值 |
Int8 |
0 |
UInt8 |
0 |
Int16 |
0 |
UInt16 |
0 |
Int32 |
0 |
UInt32 |
0 |
Int64 |
0 |
UInt64 |
0 |
float |
0 |
double |
0 |
struct tm |
1900-1-1 0:0:0 |
std::string |
“” |
如果不想用上表中的默认值,则推荐在select语句中使用nvl函数进行显示指定。
3.13 批量插入
在3.5绑定容器一节中,利用绑定容器变量的方式,已经实现了各种数据的批量入库。
本节再给出一个含有多种类型数据批量插入的示例:
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 struct tm tm_value; 4 time_t now_time = time( NULL ); 5 localtime_s( &tm_value, &now_time ); 6 vector< string > vec0; 7 vec0.push_back( "123456" ); 8 vec0.push_back( "222222" ); 9 vector< struct tm > vec1; 10 vec1.push_back( tm_value ); 11 vec1.push_back( tm_value ); 12 vector< occiwrapper::Int8 > vec2; 13 vec2.push_back( 1 ); 14 vec2.push_back( 2 ); 15 vector< float > vec3; 16 vec3.push_back( 0.1 ); 17 vec3.push_back( 0.2 ); 18 vector< double > vec4; 19 vec4.push_back( 10000 ); 20 vec4.push_back( 100 ); 21 s << "insert into test_batched_table( string_value, date_value, int_value, float_value, number_value ) values ( :1, :2, :3, :4, :5 )", batched_use( vec0 ), batched_use( vec1 ), batched_use( vec2 ), batched_use( vec3 ), batched_use( vec4 ), now, bRet, strErrMsg; 22 assert( bRet );
3.14 批量读取
当一个表含有大量记录时,需要进行批量读取。Occiwrapper提供了非常便捷的批量读取方式,可以直接把表内的结果读取到容器中,屏闭了复杂的类型绑定和内存操作过程。
在3.10执行select语句并保存结果一节中,给出了通过一条SQL语句,一次把表内所有的数据读取出来。
但实际上,常遇到一张表内的数据量达到百万、千万级别,一次根本读不到内存中(out of memory)。此时,就需要多次分批读取。以下给出一段示例代码。
1 occiwrapper::ConnectionInfo info( "127.0.0.1", 1521, "occiwrapper", "occiwrapper", "orcl" ); 2 occiwrapper::Session s = SessionInstance( info ); 3 struct tm tm_value; 4 time_t now_time = time( NULL ); 5 vector< int > vec1; 6 vector< int > vec2; 7 // test limit select, getting all of data to the vectors 8 occiwrapper::Statement stmt = ( s << "select * from tbl_test2 t", into( vec1 ), into( vec2 ), limit( 10000 ) ); 9 do 10 { 11 vec1.clear(); 12 vec2.clear(); 13 stmt.Execute(); 14 } 15 while( stmt.HasNext() );
通过执行上述代码,每次通过调用Execute操作,从表中取10000条记录到vec1和vec2两个容器中。如果不执行vec1.clear()操作,下次调用Execute操作,会再往vec1中追加10000条记录。示例中,并没有对数据进行处理,因此,直接进行了清除。
小人本潜水在思源的贴边 ID又多 又有钱 快活乐无边 谁知道站总监 他蛮横不留情面 他勾结站长目无天 占我ID夺我钱 我马甲跟他来翻脸 反被他来把经验减 我同学骂他欺新人 反被他捉进了小黑屋里面 874了一百遍啊一百遍 啊 最后他咬舌自尽 遗恨人间 他还将我和马甲赶出了思源 流落在人间 我为求回思源 无奈行乞在贴前 谁知道站总监他实在太阴险 知道此情形竟派人来暗算将我发文狂删到0篇 小人ID强 残命独留全 可怜马甲他 竟遭删 为求养ID 惟有傍人卖身自作践 一面苦赚钱 一面写诗篇 发誓把名气显 手刃总监意志坚啊 从此总监ID念心间 我永铭记此仇不供戴天 |