PHP stream_get_contents()从数据库读取LOB时的行为异常
我在一个表中有2条记录,具有相似的CLOB数据。其中每一个都是从查询中解析出来的,然后由php在循环中根据返回的PDO::FETCH_ASSOC读入字符串 在查询返回结果后,看起来是这样的:PHP stream_get_contents()从数据库读取LOB时的行为异常,php,oracle,pdo,Php,Oracle,Pdo,我在一个表中有2条记录,具有相似的CLOB数据。其中每一个都是从查询中解析出来的,然后由php在循环中根据返回的PDO::FETCH_ASSOC读入字符串 在查询返回结果后,看起来是这样的: ID | NAME | DESCRIPTION | LOB_DEFINITION 4409 foo blah blah long text that is stored in a lob ~ 5k characters 4410 foob
ID | NAME | DESCRIPTION | LOB_DEFINITION
4409 foo blah blah long text that is stored in a lob ~ 5k characters
4410 foobar blah blah some other long text stored in a lob ~ 5k characters
我的问题是,一旦我开始循环并读取LOB中的内容,它们不会“重置”,因此,任何和所有读取的对象都将与它读取的第一个LOB具有相同的值:
大概是这样的:
foreach($result as $r) {
$lob = stream_get_contents($r['LOB_DEFINITION']);
echo $r['ID'].'-<i>'.$lob.'</i><HR>';
unset($lob);
}
foreach($r结果){
$lob=stream_get_contents($r['lob_DEFINITION']);
echo$r['ID'].-'.$lob.
;
未结算(lob);
}
结果输出如下所示:
foreach($result as $r) {
$lob = stream_get_contents($r['LOB_DEFINITION']);
echo $r['ID'].'-<i>'.$lob.'</i><HR>';
unset($lob);
}
4409长文本,存储在lob~5k个字符中
4410以lob~5k字符存储的长文本 而不是我期望得到的: 4409长文本,存储在lob~5k个字符中
4410存储在lob~5k字符中的其他一些长文本 我也检查了资源ID,它们是不同的资源
我在这里不知所措。。。有人对这个问题有见解吗?经过几个小时的研究,得出以下结论: 从oracle表(其中一列为clob数据类型)返回多记录集将导致最后检索到的记录clob成为所有检索到的clob的值。这就是导致上述行为的原因 我最终解决这个问题的方法是: 选择我计划使用CLOB的所有记录(不是CLOB本身,只是记录ID) 然后,我循环遍历这些记录ID,并使用单独的数据库调用,使用主键逐个处理CLOB数据,以拉入记录,确保返回的CLOB数据不超过1条。因此,本质上这就是现在正在发生的事情: 从表中检索到我要使用的所有CLOB的ID后,我对它们进行解析:
foreach($result as $r) {
$query = 'select lob_definition from mytable where id = '.$r;
$lobresult = oracleConnection->query($query)->fetchAll(FETCH_COLUM);
$lob = stream_get_contents($lobresult);
echo $r['ID'].'-<i>'.$lob.'</i><HR>';
unset($lob);
}
foreach($r结果){
$query='从id='的mytable中选择lob_定义。$r;
$lobresult=oracleConnection->query($query)->fetchAll(FETCH\u column);
$lob=stream\u get\u contents($lobresult);
echo$r['ID'].-'.$lob.
;
未结算(lob);
}
某种效果解决了我的问题(所有这些都用各种方法抽象出来,但本质上就是这样发生的。这是由于PDO(OCI)中的一个长期缺陷造成的::fetchAll 您不必像Jeffs answer中那样对每一行进行单独的查询。您只需避免fetchAll。根据错误描述中建议的解决方法,我使用以下函数来获取所有LOB:
function fetchAllLOB(PDOStatement $stmt): array
{
$result = [];
while ($row = $stmt->fetch()) {
foreach ($row as $name => $value) {
if (is_resource($value)) {
$row[$name] = stream_get_contents($value);
}
}
$result[] = $row;
}
return $result;
}
为什么…你要使用
stream\u get\u contents()
?我只是想知道。你还没有把结果拉进来吗?为什么你需要stream\u get\u contents()
。这与使用Oracle有关吗?因为我在手册中看到,stream\u get\u contents()
或多或少等同于file\u get\u contents()
,只是它在一个流上运行……我看不出从数据库检索到的资源是如何以任何方式成为一个流的?检索到的LOB是一个流:如果你简单地回显$r['LOB\u DEFINITION'],它将在屏幕上打印一个资源ID。这个资源是一个句柄(类似于文件句柄)这可以也应该通过stream\u get\u内容或类似的内容来阅读。它正在并且已经在我的项目中为其他几个对象工作,但是这是我第一次在它们之间循环工作,似乎有一些有趣的事情在进行。啊哈。不熟悉Oracle/LOB。因此,这个问题。可能是吗关于流在输出内容后没有接收/释放的内容?可能有重置/停止/设置?我看到这里有多个示例和建议:-也许你可以找到一些有用的东西。谢谢!我根据你的建议解决了这个问题。我很高兴它有帮助