OcciWrapper使用指南(高性能Oracle访问组件)

时间:2022-03-03 20:14:40

occiwrapper使用指南

  occiwrapper是一个开源的、跨平台的Oracle访问组件, 方便C++开发者们灵活地操作oracle数据库。为了方便使用,组件中的接口形式参考的POCO库的使用方式。occiwrapper采用如下的形式执行SQL语句:

     occiwrapper::Session s = SessionInstance( connection );
s << "truncate table TBL_TEST ", now;

  通过session对象维护一个到oracle的会话。类似于流的操作方式,向session中传入SQL语句,并执行。

  在oracle参数绑定方面,Occiwrapper可以直接将C++变量绑定到oracle参数中,在以后的文档说明中详细介绍。

   occiwrapper::Session s = SessionInstance( info );
  struct tm tm_value;
  s << "insert into TBL_TEST( date_value ) values ( :1 )", use( tm_value ), now;

  同时,对于vector等容量变量,可以灵活地直接绑定到oracle的绑定变量上,同时也可以灵活的将select语句返回的结果绑定到容器中,而且对于使用者来讲,并不用关心类型的对应关系。为了提高存取的性能,写入和读取都采入批量操作的方式,同时采用智能指针自动管理内存缓冲池,最大限度地解放了oracle开发者。

   occiwrapper::Session s = SessionInstance( info );
  vector< int > vec1;
  s << "select A from tbl_test2 t", into( vec1 ), now;

  组件中使用的很多技术都是在工作中一些经验的积累与总结,由于自己认识oracle不够深刻,对C++的理解也可能不够深入,希望大家多多讨论。对于大家发现的Bug,我也会尽快修改,同时热情欢迎大家积极参与库的修改。

  源代码地址:https://github.com/CUCmehp/occiwrapper

1、下载和安装

1.1 第三方组件依赖

  本组件依赖oracle公司的occiOracle C++ Calling Interface动态库支持。连接不同的oracle版本,须要选择不同的occi版本。

  关于occi的详细介绍,请参见oracle公司官方文档

1.2 开发环境

  在Windows系统下,可以通过Visual Studio 2008 SP1或者Visual Studio 2010进行编译。

  在linux系统下,可以通过g++编译器进行编译。

1.3      运行环境

  本组件可跨平台支持WindowsLinux操作系统。

1.4 数据库环境

  test工程中所有测试用例用到的数据库表、存储过程、函数,都可以通过db文件夹中的脚本创建。

  方法:

    (1)通过具有system权限的用户执行脚本create_user.sql

    (2)使用用户occiwapper(密码为occiwrapper)执行occiwrapper.sql

  注:所有测试用例中均使用occiwrapper作为oracle的用户名。

1.5 测试

  所有的测试代码存放在源码的test目录下,在windowslinux(Suse 10, Suse 11openSuse12, redhat 6企业版, Centos 6 )下进行了相关的测试。数据库连接信息的配置文件放在db_config.ini中。

在程序在oracle 11gR212cR1oracle 12.1对应的occi版本下进行了测试。

2、 编译说明

2.1 Windows

  • 使用Visual Studio 2008 SP1工具

  使用Visual Studio 2008直接打开工程occi_wrapper_vs2008.sln,选择DebugRelease进行编译。

  注:要求vs2008 sp1以上,是由于occiwrapper中使用了tr1库,而vs2008SP1版本以上,才开始支持tr1库。

  • Visual Studio 2010

  使用Visual Studio 2010直接打开工程occi_wrapper_vs2010.sln,选择DebugRelease进行编译。

  说明:源码中include/occi_11g目录下,存放着oracle 11.2.0.2 64位数据库对应的头文件,在lib_vs2008lib_vs2010目录下,存放着11.2.0.2版数据库对应的lib库文件。在bin_vs2008bin_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目录下,存放着生成的includelib文件,测试文件存放在test目录下,test目录下的db_config.ini为测试库对应的配置信息。要执行test程序,需先在oracle数据库中执行db文件夹下的脚本。

3.   使用指南

  本部分主要介绍调用occiwrapper组件的方法,包括以下部分:

3.1 Oracle连接

  occiwrapper组件通过类occiwrapper::ConnectionInfo结构来保存oracle连接信息。

     occiwrapper::ConnectionInfo info;
info.ip = "127.0.0.1";
info.port =
info.username = "occiwrapper";
info.password = "occiwrapper";
info.sid = "orcl";

  要建立一个oracle连接,需要先申请一个oracleEnvironment变量,函数内部通过调用OCCIcreateEnvironment函数创建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连接。

     shared_ptr< occiwrapper::Environment > pEnv = occiwrapper::Environment::CreateEnvironment();
assert( pEnv->CreateEnvironment() != NULL );
occiwrapper::ConnectionInfo info;
info.ip = "127.0.0.1";
info.username = "occiwrapper";
info.password = "occiwrapper";
info.sid = "orcl";
assert( occiwrapper::Connection::GetConnection( shared_ptr< occiwrapper::Environment >( pEnv ), info ) != NULL );

  上述代码中,shared_ptrC++ 0x标准中提出的tr1库定义的智能指针,关于C++ 0xtr1库,在此不做介绍,大家可以参见*。

  occiwrapper使用连接池对oracle数据库连接进行管理,对于相同的数据库连接进行复用;同时,通过连接池,对oracle连接进行管理,以下代码给出了如何使用occiwrapper的连接池,取得oracle连接。

      occiwrapper::ConnectionInfo info;
occiwrapper::ConnectionPool connPool;
info.ip = "127.0.0.1";
info.username = "occiwrapper";
info.password = "occiwrapper";
info.sid = "orcl";
shared_ptr< occiwrapper::Connection > p = connPool.GetConnection( info );
assert( p != NULL);
assert( p->GetValidity() == occiwrapper::VALID );
shared_ptr< occiwrapper::Connection > other = connPool.GetConnection( info );
assert( connPool.GetConnMapSize() == );

3.2 创建一个会话

  Session类用来管理客户端与oracle服务器之间的会话连接。通过会话连接,客户端可以灵活的创建出若干Statement来执行SQL命令。

  occiwrapper通过类SessionFactory来创建session会话,SessionFactory是一个以单件形式存在的工厂类,可以动态的创建出Session对象。同时,SessionFactory中内置了一个连接池对象管理oracle连接。关于连接池对象,可以参考3.2节创建一个会话中的介绍。

  以下代码给出了如何使用SessionFactory创建一个Session对象。

     occiwrapper::ConnectionInfo info;
occiwrapper::Session s = occiwrapper::SessionFactory::Instance().Create( info, false );

  为了方使创建Session,也可以使用宏定义。

     occiwrapper::Session s = SessionInstance( info );

3.3      执行DDL语句

  利用Session对象可以方便地执行DDL命令,如下示例演示如何创建一张表,再将它清空,最后删除该表。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet = false;
string strErrMsg = "";
s << "create table tbl_test( x int )", now, bRet, strErrMsg;
s << "truncate table tbl_test", now, bRet, strErrMsg;
s << "drop table tbl_test", now, bRet, strErrMsg;

3.4 执行简单插入

  对于简单的insert操作,指不使用绑定变量的insert操作。如何利用occiwrapper进行绑定变量插入,将在下两节中进行介绍。本节只介绍执行最简单的SQL语句。

  例如,对于一张已知的表TBL_TEST1,该表只含有一个整数字段X。以下的代码数字10004插入到该表中。

   occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
  occiwrapper::Session s = SessionInstance( info );
  bool bRet = false;
  string strErrMsg = "";
  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 Windowsocciwrapper支持的绑定类型定义

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绑定到对应的绑定变量上。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet = false;
string strErrMsg = "";
s << "insert into tbl_test1( x ) values ( :1 )", use( ), now, result, err_msg;
cout << "result: " << result << endl << "error message: " << err_msg << endl;
assert( result );
s << "insert into test_string( id, string_val ) values( :1, :2 )", use( ), use( "CUCmehp" ), now, result, err_msg;
cout << "result: " << result << endl << "error message: " << err_msg << endl;
assert( result );
s << "insert into test_number( id, number_value ) values( :1, :2 )", use( ), use( 3.5 ), now, result, err_msg;
cout << "result: " << result << endl << "error message: " << err_msg << endl;
assert( result );

对于同一个Session也可以多次进行绑定,进行复用,以下代码向表TBL_TEST1中插入09

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet;
string strErrMsg;
s << "truncate table tbl_test1", now;
occiwrapper::Statement stmt = s << "insert into tbl_test1( x ) values( :1 )";
for( int i = ; i < ; ++ i )
{
stmt, use( i ), now, bRet, strErrMsg;
assert( bRet );
}
  • 绑定容器

  绑定容器是指把表中的若干列与一个或多个容器(1.0.0版本仅支持vector容器)相绑定。

  如下图所示,一个表有ABC三列,可以将列A的数据与变量vector<A>进行绑定,将列B、列C的数据绑定到vector< tuple< B, C> >变量中,tuple为元组类型,其定义可以参见C++ 0x标准,定义在库tr1中。

OcciWrapper使用指南(高性能Oracle访问组件)

  利用occiwrapperbatched_use关键字可以灵活的实现上述绑定,以下示例给出了将数组{20,21,22,23,24}所生成的vector,批量插入到表TBL_TEST1中。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet;
string strErrMsg;
int a[] = { , , , , };
vector< int > vec( a, a + );
s << "insert into tbl_test1( x ) values ( :1 )", batched_use( vec ), now, bRet, strErrMsg;
assert(bRet);

  以下示例给出了如何绑定到两个vector或者一个vector<tuple>结构中。表TEST_STRING中含有两个字段IDSTRING_VAL,分别为integervarchar2类型。示例中,首先将一个vector<int>变量和vector<string>变量绑定到这两列上,进行插入操作。然后,将一个vector< tuple<int,string> >变量绑定到这两列上。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet;
string strErrMsg;
int a[] = { , , , , };
vector< int > vec( a, a + );
string strArray[] = { "message1", "message2", "message3", "message4", "message5" };
vector< string > vecStr( strArray, strArray + );
s << "insert into test_string( id, string_val ) values ( :1, :2 )", batched_use( vec ), batched_use( vecStr ), now, bRet, strErrMsg;
assert( bRet );
s << "truncate table test_string", now, bRet;
assert( bRet );
vector< tuple< int, string > > vecTuple;
for( size_t i = ; i < ; ++ i )
{
vecTuple.push_back( make_tuple( vec[ i ], vecStr[ i ] ) );
}
s << "insert into test_string( id, string_val ) values ( :1, :2 )", batched_use( vecTuple ), now, bRet, strErrMsg;
assert( bRet );

3.6 执行update操作

  执行update操作的方式,跟执行DDLselect语句的方式基本相同,同样可以使用绑定变量。以下给出了简单的例子。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet = false;
string strErrMsg = "";
s << "truncate table tbl_test1", now, bRet, strErrMsg;
s << "insert into tbl_test1( x ) values ( 10004 )", now, bRet, strErrMsg;
s << "update tbl_test1 set x = :1 where x = 10004", use( ), now, bRet, strErrMsg;

  示例代码先向表TBL_TEST1中的X字段插入数值10004,然后将数值修改为10005

3.7  CommitRollback

  Occiwrapper支持两种形式的commit操作。在创建Session时,可以指定Commit的类型,isAutoCommit参数为true,则表示每次操作后,自动进行commit,否则需要手工commit或者rollback,操作才能生效。以下代码给出了示例。

     occiwrapper::Session s = occiwrapper::SessionFactory::Instance().Create( info, false );
s << "truncate table tbl_test1", now;
s.Commit();
bool bRet = false;
string strErrMsg = "";
s << "insert into tbl_test1( x ) values ( 10005 )", now, bRet, strErrMsg;
s.Rollback();
occiwrapper::Statement stmt2 = ( s << "insert into tbl_test1( x ) values ( 10005 )" );
for ( int i = ; i < ; ++i)
{
stmt2.execute();
}
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输出。

  下面的代码块给出了上述过程。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet;
string strErrMsg;
int nParIn = ;
string strParOut = "";
s << "begin p_test_procedure( :1,:2 ); end;", use( nParIn, occiwrapper::PAR_IN ), use( strParOut, occiwrapper::PAR_OUT ), now, bRet, strErrMsg;
assert( bRet );
assert( strParOut == "" );

3.9 调用函数

  调用函数的方法与调用存储过程类似,只不过函数有返回值,类型为输出类型。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet;
string strErrMsg = “”;
int a = ;
s << "begin :1 := f_ins_tbl_test1( :2 ); end;", use( a, occiwrapper::PAR_OUT ), use( , occiwrapper::PAR_IN ) , now, bRet, strErrMsg;
assert( bRet );
int b;
s << "begin :1 := f_test2( :2, :3 ); end;", use( a, occiwrapper::PAR_OUT ), use( ), use( b, occiwrapper::PAR_OUT ), now, bRet, strErrMsg;
assert( bRet );

3.10 执行select语句并保存结果

  select操作是SQL操作中最常见的操作之一,将oracle中的数据取到内存中。occiwrapper通过关键字into实现将数据库中的一个字段绑定到一个容器中。

     vector< string > vStr;
vector< struct tm > vDate;
vector< occiwrapper::Int32 > vInt;
vector< float > vFloat;
vector< double > vDouble;
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;
assert( bRet );

  上述代码段将表tbl_batched_table中的数据读取,并存到5组vector变量中。

  occiwrapper内部采用了批量读取的方式,提高了读取的性能,同时内部自动管理批量绑定时所需要内存空间。

  当表中数据量比较大,只取若干条数据时,可以使用Limit关键字。

  下列代码段给出了示例:

     vector< int > vec1;
vector< int > vec2;
// test limit select
s << "select * from tbl_test2 t", into( vec1 ), into( vec2 ), occiwrapper::Limit( ), now;

  occiwrapper在读取时,并没有提供游标的操作(考虑到游标会影响对于底层的封装性),直接将内存中的容器对象(vector)与oracle的数据表进行了绑定。因此,当数据表中的数据量很大时,vector的插入受限于内存,故本组件更适应单表数据量在百万条以下的应用场景。当然,开发者为了防止插入时vector出错内存用尽,如将一个1亿条记录的数据,分100次插入到100Wvector容量中,每次调用批量入库,这样做也是能够成功的。然而,由于没有提供游标相关的操作,该表无法将1亿条记录一次绑定到一组vector中(会std bad allocate异常),从而形成了无法处理的窘境。因此,本组件更适合单表数据量在百万条以下规模的应用。

3.11 处理oracle中的日期类型

  为了处理oracle中的Date类型,occiwrapper对外处理的类型为struct tm类型,即occiwrapper插入和读取的类型都采用struct tm类型。

  示例代码中,给出了如何向表中插入当前时间,并如何将当向时间从oracle数据库中读到一个vector数组中。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
bool bRet;
string strErrMsg;
struct tm tmValue;
time_t nowTime = time( NULL );
localtime_r( &nowTime, &tmValue);
s << "truncate table test_date", now, bRet, strErrMsg;
s << "insert into test_date( date_val ) values ( :1 )", use( tmValue ), now, bRet;
vector< struct tm > vTmDb;
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绑定容器一节中,利用绑定容器变量的方式,已经实现了各种数据的批量入库。

  本节再给出一个含有多种类型数据批量插入的示例:

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
struct tm tm_value;
time_t now_time = time( NULL );
localtime_s( &tm_value, &now_time );
vector< string > vec0;
vec0.push_back( "" );
vec0.push_back( "" );
vector< struct tm > vec1;
vec1.push_back( tm_value );
vec1.push_back( tm_value );
vector< occiwrapper::Int8 > vec2;
vec2.push_back( );
vec2.push_back( );
vector< float > vec3;
vec3.push_back( 0.1 );
vec3.push_back( 0.2 );
vector< double > vec4;
vec4.push_back( );
vec4.push_back( );
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;
assert( bRet );

3.14 批量读取

  当一个表含有大量记录时,需要进行批量读取。Occiwrapper提供了非常便捷的批量读取方式,可以直接把表内的结果读取到容器中,屏闭了复杂的类型绑定和内存操作过程。

  在3.10执行select语句并保存结果一节中,给出了通过一条SQL语句,一次把表内所有的数据读取出来。

  但实际上,常遇到一张表内的数据量达到百万、千万级别,一次根本读不到内存中(out of memory)。此时,就需要多次分批读取。以下给出一段示例代码。

     occiwrapper::ConnectionInfo info( "127.0.0.1", , "occiwrapper", "occiwrapper", "orcl" );
occiwrapper::Session s = SessionInstance( info );
struct tm tm_value;
time_t now_time = time( NULL );
vector< int > vec1;
vector< int > vec2;
// test limit select, getting all of data to the vectors
occiwrapper::Statement stmt = ( s << "select * from tbl_test2 t", into( vec1 ), into( vec2 ), limit( ) );
do
{
vec1.clear();
vec2.clear();
stmt.Execute();
}
while( stmt.HasNext() );

  通过执行上述代码,每次通过调用Execute操作,从表中取10000条记录到vec1和vec2两个容器中。如果不执行vec1.clear()操作,下次调用Execute操作,会再往vec1中追加10000条记录。示例中,并没有对数据进行处理,因此,直接进行了清除。