我们在Oracle数据库存储的字符数据一般是用 VARCHAR2,最大长度4000,通常情况下能满足存储需求,但是碰到记录日志或者拼接的id集合可能就不够,Oracle提供了大数据类型LOB,最多能容纳4GB,分为BLOB和CLOB两种:BLOB即二进制大型对象,适用于存贮非文本的 字节流 数据,CLOB则用来存储 文本型 的数据。
相当于 Mysql 的 Text,只是没有区分那么细。
如下新建一张日志表:
可以看到数据库里CLOB也是不直接显示的,需要点开编辑。
Oracle在插入时会做隐式转换,默认把字符串转换成 VARCHAR2 类型,一旦字符串长度超过4000就会报 ORA-01704(字符串文字太长)错误,所以需要特殊处理。
PHP调用代码:
//初始化字段
$aInput[$i++] = [
'sql' => "insert into s_log (logid,oprtime,loginfo) values(?,sysdate,empty_clob())",
'var' => [
$iLogId,
]
];
$aInput[$i++] = [
'sql' => "@select loginfo from s_log where logid=? for update",
'var' => [
$iLogId
],
'clob' => [
$p_aParams['info']
]
];
Tuxedo Service封装方法:
通过向OCIDescriptorAlloc()函数传递OCI_DTYPE_LOB作为类型参数来为CLOB分配LOB定位符。
OCIDescriptorAlloc 获取 LOB 字段类型时,缓冲区指针必须是一个指向 OCILobLocator 类型的 LOB
定位符的指针,通过 OCIDescriptorAlloc()函数来分配它。
//CLOB变量做初始化
for(i = 0; i< get_clob_num; i++){
//分配LOB定位符
if (OCIDescriptorAlloc((dvoid *) p_dbconn->env_h, (dvoid **) &clob[i],
(ub4)OCI_DTYPE_LOB, (size_t) 0, (dvoid **) 0)) {
goto result;
}
//建立所选字段和输出缓冲区的结合
if (OCIDefineByPos(db_stmt, &defclob[i], p_dbconn->error_h, (ub4) i+1,
(dvoid *) &clob[i], (sb4) -1, (ub2) SQLT_CLOB,(dvoid *) 0,
(ub2 *) 0, (ub2 *) 0, (ub4) OCI_DEFAULT)) {
goto result;
}
}
//清除原clob字段里面的值
ociretval = OCILobTrim(p_dbconn->svcctx_h,p_dbconn->error_h,clob[i],0);
if(ociretval != OCI_SUCCESS ) {
OCIErrorGet( p_dbconn->error_h, 1, NULL, (ub4*)&db_err.ora_code, (OraText*)db_err.detail,
DEFAULT_TEXTLEN, OCI_HTYPE_ERROR);
goto result;
}
if(nbytes>0) {
//往clob字段里面写入新的值
ociretval = OCILobWrite(p_dbconn->svcctx_h, p_dbconn->error_h, clob[i], &amtp, offset,
(dvoid *) tmp_var,(ub4) nbytes, OCI_ONE_PIECE, (dvoid *)0,
(sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0,(ub2) 0, (ub1) SQLCS_IMPLICIT);
if(ociretval != OCI_SUCCESS ) {
OCIErrorGet( p_dbconn->error_h, 1, NULL, (ub4*)&db_err.ora_code,
(OraText*)db_err.detail, DEFAULT_TEXTLEN, OCI_HTYPE_ERROR);
goto result;
}
}