OCI编程高级篇(三) 批量执行
访问www.tomcoding.com网站,学习Oracle内部数据结构,详细文档说明,下载Oracle的exp/imp,DUL,logminer,ASM工具的源代码,学习高技术含量的内容。
前面我们讨论了数组插入数据的过程,实际上Oracle还是一条条的执行数组中的元素,只不过是一次性的提供了多条数据而已。当数据单条执行时,如果出现了错误,我们确切的知道是那一条出了错,修改数据后再执行就可以了。但是数组插入让我们遇到了问题,数组中的数据只要有一条出现了错误,整个数组插入操作就会报错,并且错误行后面的数据不会再执行,这时只能先回滚掉所有的操作,然后找出错误数据行,修正后,再重新执行数组操作。如果数组中有多条错误,那会严重影响效率,并且程序员处理这些错误也会非常头痛。
那么有没有什么好的方法来避免上面的麻烦呢?答案是肯定的,OCI提供了一种机制,叫做执行的批量错误模式,在这一模式下,OCI会执行数组中的每一条数据,然后收集错误行的信息,OCI程序可以返回每个错误行的出错信息,然后修正数据,只需要重新执行错误行数据就可以了。
批量错误模式的处理步骤如下。
1. 分配OCI语句。
2. 准备SQL语句文本。
3. 绑定数组数据。
4. 执行语句,使用OCI_BATCH_ERRORS模式。
5. 获取出错行的数量,使用OCI_ATTR_NUM_DML_ERRORS调用OCIAttrGet()函数。
6. 获取每个错误的错误码和错误信息文本
7. 处理错误。
在第六步中用到了一个函数OCIParamGet()用于取得每个错误的错误句柄。
sword OCIParamGet ( const void *hndlp,
ub4 htype,
OCIError *errhp,
void **parmdpp,
ub4 pos );
hndlp是一个输入参数,是要获取参数的句柄,我们在这里使用错误句柄。
htype是一个输入参数,是句柄的类型,这里是OCI_HTYPE_ERROR。
errhp是一个输入/输出参数,是一个错误句柄,用于OCIErrorGet()取回错误信息。
parmdpp是一个输出参数,参数值,在这里我们要取回一个错误句柄。
pos是一个输入参数,这里是错误的位置号,从0开始。
还是用前面数组插入的例子,看看用OCI_BATCH_ERRORS模式怎样处理错误。
OCIEnv *envhp = NULL; OCIError *errhp = NULL; OCIServer *svrhp = NULL; OCISession *usrhp = NULL; OCISvcCtx *svchp = NULL; OCIStmt *smthp = NULL; OCIError *errhp1 = NULL; OCIError *errhp2 = NULL; /* 数组插入10条数据 */ int insert_array_batch(void){ int i; sword rc; int slen; ub4 num_errs; ub4 row_off; sb4 ecode; sb2 ind_id[10]; sb2 ind_name[10]; sb2 ind_addr[10]; ub2 alen_id[10]; ub2 alen_name[10]; ub2 alen_addr[10]; ub2 rcode_id[10]; ub2 rcode_name[10]; ub2 rcode_addr[10]; int32_t id[10]; char name[10][32]; char addr[10][256]; OCIBind *bndp; char sqltxt[1024]; char errmsg1[16384]; /* 分配OCI语句句柄 */ rc = OCIHandleAlloc( (void *)envhp, (void **)&smthp, OCI_HTYPE_STMT, 0, (void **)NULL ); if (rc != OCI_SUCCESS) { fprintf(stderr, "OCIHandleAlloc() - allocate statement handle error !\n"); return (-1); } /* 生成SQL语句文本 */ strcpy(sqltxt, "INSERT INTO test_tab (ID, NAME, ADDR) VALUES (:1, :2, :3)"); slen = strlen(sqltxt); /* 准备语句 */ if (check_oci_error(errhp, OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen, OCI_NTV_SYNTAX, OCI_DEFAULT)) < 0) return (-1); /* 绑定第一个占位符ID,绑定数组地址 */ if (check_oci_error(errhp, OCIBindByPos((OCIStmt *)smthp, (OCIBind **)&bndp, errhp, (ub4)1, /* position */ (void *)id, /* valuep */ (sb4)4, /* value_sz */ (ub2)SQLT_INT, /* dty */ (void *)ind_id, /* indp */ (ub2 *)alen_id, /* alenp */ (ub2 *)rcode_id, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DEFAULT) /* mode */ ) < 0) return (-1); /* 指定绑定参数跳过的字节数 */ if (check_oci_error(errhp, OCIBindArrayOfStruct(bndp, sizeof(int32_t), sizeof(sb2), sizeof(ub2), sizeof(ub2)) ) < 0) return (-1); /* 绑定第二个占位符NAME */ if (check_oci_error(errhp, OCIBindByPos((OCIStmt *)smthp, (OCIBind **)&bndp, errhp, (ub4)2, /* position */ (void *)name, /* valuep */ (sb4)30, /* value_sz */ (ub2)SQLT_STR, /* dty */ (void *)ind_name, /* indp */ (ub2 *)alen_name, /* alenp */ (ub2 *)rcode_name, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DEFAULT) /* mode */ ) < 0) return (-1); /* 指定绑定参数跳过的字节数,name定义的长度为32 */ if (check_oci_error(errhp, OCIBindArrayOfStruct(bndp, 32, sizeof(sb2), sizeof(ub2), sizeof(ub2)) ) < 0) return (-1); /* 绑定第三个占位符ADDR */ if (check_oci_error(errhp, OCIBindByPos((OCIStmt *)smthp, (OCIBind **)&bndp, errhp, (ub4)3, /* position */ (void *)addr, /* valuep */ (sb4)200, /* value_sz */ (ub2)SQLT_STR, /* dty */ (void *)ind_addr, /* indp */ (ub2 *)alen_addr, /* alenp */ (ub2 *)rcode_addr, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DEFAULT) /* mode */ ) < 0) return (-1); /* 指定绑定参数跳过的字节数,addr定义的长度为256 */ if (check_oci_error(errhp, OCIBindArrayOfStruct(bndp, 256, sizeof(sb2), sizeof(ub2), sizeof(ub2)) ) < 0) return (-1); /* 赋值绑定的变量数据 */ for (i=0; i<10; i++) { id[i] = i+10; memset(name[i], 'a', 10); memset(addr[i], 'b', 20); name[i][10] = '\0'; addr[i][20] = '\0'; /* 指示符赋值为0,插入非NULL数据 */ ind_id[i] = 0; ind_name[i] = 0; ind_addr[i] = 0; /* 赋值变量的真实数据长度 */ alen_id[i] = sizeof(int32_t); alen_name[i] = strlen(name[i]) + 1; alen_addr[i] = strlen(addr[i]) + 1; } /* 执行OCI语句,注意这里要用OCI_BATCH_ERRORS模式 */ if (check_oci_error(errhp, OCIStmtExecute(svchp, smthp, /* stmthp */ errhp, /* errhp */ 10, /* iters */ 0, /* rowoff */ NULL, /* snap_in */ NULL, /* snap_out */ OCI_BATCH_ERRORS) /* mode */ ) < 0) return (-1); /* 分配错误句柄errhp1,用于取回错误条数 */ if (check_oci_error(errhp, OCIHandleAlloc((const void *)envhp, (void **)&errhp1, OCI_HTYPE_ERROR, 0, (void **)NULL)) < 0) return (-1); if (check_oci_error(errhp, OCIAttrGet (smthp, OCI_HTYPE_STMT, &num_errs, 0, OCI_ATTR_NUM_DML_ERRORS, errhp1)) < 0) return (-1); if (num_errs) { /* 分配错误句柄errhp2 */ if (check_oci_error(errhp, OCIHandleAlloc((const void *)envhp, (void **)&errhp2, OCI_HTYPE_ERROR, 0, (void **)NULL)) < 0) return (-1); for (i=0; i<num_errs; i++) { if (check_oci_error(errhp, OCIParamGet(errhp, OCI_HTYPE_ERROR, errhp1, &errhp2, i)) < 0) return (-1); if (check_oci_error(errhp, OCIAttrGet (errhp2, OCI_HTYPE_ERROR, &row_off, 0, OCI_ATTR_DML_ROW_OFFSET, errhp1)) < 0) return (-1); OCIErrorGet(errhp2, 1, NULL, &ecode, (OraText *)errmsg1, 16383, OCI_HTYPE_ERROR); fprintf(stderr, "row[%d] error: %d-%s\n", row_off, ecode, errmsg1); fprintf(stderr, "ID=%d, NAME=%s, ADDR=%s\n", id[row_off], name[row_off], addr[row_off]); } } /* 提交改变的数据 */ if (check_oci_error(errhp, OCITransCommit(svchp, errhp, OCI_DEFAULT)) < 0) return (-1); return (0); }

浙公网安备 33010602011771号