用PHP操纵Oracle的LOB类型的数据

oracle|数据

《PHP+Oracle(OCI) 初步》中讲了如何用PHP中的OCI函数来连接Oracle数据库,执行一些SQL查询及关闭数据库连接。本文将讲述另一个难度稍大的问题:用PHP的OCI函数来操纵Oracle的LOB字段。阅读本文需要《PHP+Oracle(OCI) 初步》一文中的知识。

用过Oracle的人都知道,Oracle有一种数据类型叫VARCHAR2,用来表示不定长的字符串。VARCHAR2也是Oracle公司推荐使用的类型。但使用VARCHAR2有个问题:最大只能表示4000个字符,也就相当于2000个汉字。如果你的程序中某个字符的值要大于20002个汉字,用VARCHAR2就不能满足要求了。这时候,你有两个选择,一是用多个VARCHAR2来表示,二是用LOB字段。这里我们来看看第二个办法。

先来大体了解一下Oracle的LOB字段。Oracle的LOB类型分为三种:BLOB,CLOB和BFILE。CLOB称为字符LOB,BLOB和BFILE是用来存储二进制数据的。CLOB和BLOB的最大长度是4GB,它们把值存放在Oracle数据库中。BFILE和BLOB类似,但它把数据放在外部的文件中,所以它又称为外部BLOB(External BLOB)。
我想,我们对MYSQL应该都不会陌生。MYSQL中也有类似的数据类型,如TEXT和BLOB。在PHP的MYSQL函数中,对TEXT/BLOB的操作是直接的,就象其它类型的数据一样。但在Oracle中,情况就不一样了。Oracle把LOB当作一种特殊的数据类型来处理,在操作上不能用常规的方法。比如,不能在INSERT语句中直接把值插入到LOB字段中,也不能用LIKE进行查找。

下面就通过几个例子来说明如何用PHP的OCI函数来插入,取出和查询LOB数据。

插入

不能直接用INSERT语句向LOB字段中插入值。一般情况下,有如下的几步:
1 先分析一个INSERT语句,返回一个LOB的描述符
2 用OCI函数生成一个本地的LOB对象
3 将LOB对象绑定到LOB描述符上
4 执行INSERT语句
5 给LOB对象赋值
6 释放LOB对象和SQL语句句柄

下面的这个例子是把用户上传的图片文件存放到BLOB(或BFILE中,操作稍有不同)中。
首先要建一个表,结构如下:
CREATE TABLE PICTURES (
ID NUMBER,
DESCRIPTION VARCHAR2(100),
MIME VARCHAR2(128),
PICTURE BLOB
);
如果要实现ID的自动增加,再建一个SEQUENCE:
CREATE SEQUENCE PIC_SEQ;

然后是用来处理数据的PHP程序代码。
<?php

//建立Oracle数据库连接
$conn = OCILogon($user, $password, $SID);
//提交SQL语句给Oracle
//在这里要注意的两点:一是用EMPTY_BLOB()函数。这是Oracle的内部函数,返回一个LOB的定位符。在插入LOB时,只能用这个办法先生成一个空的LOB定位符,然后对这个定位符进行操作。EMPTY_BLOB()函数是针对BLOB类型的,对应于CLOB的是EMPTY_CLOB()。二是RETURNING后面的部分,把picture返回,让PHP的OCI函数能够处理。
$stmt = OCIParse($conn,"INSERT INTO PICTURES (id, description, picture)
VALUES (pic_seq.NEXTVAL, '$description', '$lob_upload_type', EMPTY_BLOB()) RETURNING picture INTO :PICTURE");
//生成一个本地LOB对象的描述符。注意函数的第二个参数:OCI_D_LOB,表示生成一个LOB对象。其它可能的还有OCI_D_FILE和OCI_D_ROWID,分别对应于BFILE和ROWID对象。
$lob = OCINewDescriptor($conn, OCI_D_LOB);
//将生成的LOB对象绑定到前面SQL语句返回的定位符上。
OCIBindByName($stmt, ':PICTURE', &$lob, -1, OCI_B_BLOB);
OCIExecute($stmt);
//向LOB对象中存入数据。因为这里的源数据是一个文件,所以直接用LOB对象的savefile()方法。LOB对象的其它方法还有:save()和load(),分别用来保存和取出数据。但BFILE类型只有一个方法就是save()
if($lob->savefile($lob_upload)){
OCICommit($conn);
echo "上传成功<br>";
}else{
echo "上传失败<br>";
}
//释放LOB对象
OCIFreeDesc($lob);
OCIFreeStatement($stmt);
OCILogoff($conn);

?>

还有一个要注意的地方:LOB字段的值最少要1个字符,所以在save()或savefile()之前,要确保值不能为空。否则,Oracle会出错。

取出

对一个LOB中取出数据,有两种办法。一是生成一个LOB对象,然后绑定到一条SELECT语句返回的定位符上,再用LOB对象的load()方法取出数据;二是直接用PHP的OCIFetch***函数。第一种方法比第二种方法要麻烦得多,所以我直接说说第二种方法。

还是用上面的表。

<?php
$conn = OCILogon($user, $password, $SID);
$stmt = OCIParse($conn,"SELECT * FROM PICTURES WHERE ID=$pictureid");
OCIExecute($stmt);
//秘密就在PCIFetchInfo的第三个参数上:OCI_RETURN_LOBS。第三个参数是FETCH的模式,如果OCI_RETURN_LOBS,就直接把LOB的值放到结果数组中,而不是LOB定位符,也就不用LOB对象的load()方法了。
if (OCIFetchInto($stmt, $result, OCI_ASSOC+OCI_RETURN_LOBS))
{
echo "Content-type: " . StripSlashes($result[MIME]);
echo StripSlashes($result[PICTURE]);
}
OCIFreeStatement($stmt);
OCILogoff($conn);
?>

这个程序用来显示放在LOB中的数据(图片)。调用方法(假设脚本名是getpicture.php):
<IMG SRC="getpicture.php?pictureid=99" ALT="放在Oracle LOB中的图片">

查询

前面已经提了下,对于Oracle的LOB字段是不能用LIKE进行匹配的。怎么办呢?其实并不复杂,Oracle有一个匿名的程序包,叫DBMS_LOB,里面有所有的操作LOB所需的过程。

假设有象这样一个表:
CREATE TABLE ARTICLES (
ID NUMBER,
TITLE VARCHAR2(100),
CONTENT CLOB
);

文章的内容放在CONTENT字段中。

现在我们要找出所以内容中包含"PHP中文用户"的文章,可以这么来做:

<?php
$conn = OCILogon($user, $password, $SID);
//WHERE子句中用了DBMS_LOB.INSTR过程。它有四个参数,前面两个分别表示LOB的定位符(可以直接用字段表示)和要查找的字符串;后面两个分别表示开始的偏移量和出现的次数。要注意的是必须判断它的返回值,也就是要大于0。
$stmt = OCIParse($conn,"SELECT * FROM ARTICLES WHERE DBMS_LOB.INSTR(CONTENT, 'PHP中文用户', 1, 1) > 0");
OCIExecute($stmt);
if (OCIFetchInto($stmt, $result, OCI_ASSOC+OCI_RETURN_LOBS))
{
...
}
OCIFreeStatement($stmt);
OCILogoff($conn);
?>

Oracle还提供了许多用来操作LOB数据的过程,如LENGTH, SUBSTR等等。至于它们的详细用法,可以考虑Oracle的开发手册。

关于对Oracle数据库中的LOB类型的数据的操作,就说这么多了。由于我接触Oracle时间不长,本文中可能还会有错误,欢迎大家批评指正。 

时间: 2024-09-13 02:49:24

用PHP操纵Oracle的LOB类型的数据的相关文章

通过JDBC操纵Oracle数据库LOB字段的几种情况分析

oracle|数据|数据库 通过JDBC操纵Oracle数据库LOB字段的几种情况分析纵横软件制作中心 雨亦奇2003-6-10 15:14:19在Oracle中,LOB(Large Object,大型对象)类型的字段现在用得越来越多了.因为这种类型的字段,容量大(最多能容纳4GB的数据),且一个表中可以有多个这种类型的字段,很灵活,适用于数据量非常大的业务领域(如图象.档案等).而LONG.LONG RAW等类型的字段,虽然存储容量也不小(可达2GB),但由于一个表中只能有一个这样类型的字段的

通过JDBC操纵Oracle数据库LOB字段的分析

在Oracle中,LOB(Large Object,大型对象)类型的字段现在用得越来越多了.因为这种类型的字段,容量大(最多能容纳4GB的数据),且一个表中可以有多个这种类型的字段,很灵活,适用于数据量非常大的业务领域(如图象.档案等).而LONG.LONG RAW等类型的字段,虽然存储容量也不小(可达2GB),但由于一个表中只能有一个这样类型的字段的限制,现在已很少使用了.  LOB类型分为BLOB和CLOB两种:BLOB即二进制大型对象(Binary Large Object),适用于存贮非

使用JDBC4.0操作Oracle中BLOB类型的数据方法_oracle

在JDBC4.0推出后,它的从多的特性正在受到广泛地关注.下面通过本文给大家介绍JDBC4.0操作Oracle中BLOB类型的数据的方法. 需要的jar包 使用ojdbc6.jar 在/META-INF/MANIFEST.MF里可以看到Specification-Version: 4.0 建表 create sequence seq_blobmodel_id start with 1 increment by 1 nocache; create table blobmodel ( blobid

Oracle Lob类型存储浅析

  在Oracle中,为数据表字段column和PL/SQL语言,分别提供了多种数据类型,以应对实际开发中的多种类型.Lob类型是Oracle推出一种保存大对象的数据类型.当我们考虑将信息文件(十进制.二进制).图像甚至音频信息采用数据库作为保存载体时,就需要使用lob类型数据.   目前Oracle支持的Lob类型具体包括四个子类型(subtype),分别为CLOB.BLOB.NLOB和BFILE.其中,CLOB.BLOB和NLOB都是将数据保存在数据库内部,而BFILE类型保存的核心是文件指

转:java操纵主要数据库的lob类型数据

2010-04-11 转:java操纵主要数据库的lob类型数据 文章分类:Java编程 Clob和blob的操作主要分为3种:插入,更新和读取显示.  对于插入,可以分为两类.一类是可以直接按照正常的字段处理,一类为必须先插入空clob/blob再更新为真正的内容.  插入: 对于大部分的数据库,在插入lob时都可以通过PreparedStatement.setAsciiStream或PreparedStatement.setBinaryStream直接写入,查到的资料包括: H2数据库:ht

ORACLE中LOB字段的使用和维护

oracle 摘要:本文通过实例介绍了在ORACLE数据库中通过DBMS_LOB包使用和维护LOB数据类型的基本方法. 关键词:ORACLE DBMS_LOB LOB 维护 中图分类号:TP31 1.引言 随着社会的发展,在现代信息系统的开发中,需要存储的已不仅仅是简单的文字信息,同时还包括一些图片和音像资料或者是超长的文本.比如开发一套旅游信息系统,每一个景点都有丰富的图片.音像资料和大量的文字介绍.这就要求后台数据库要有存储这些数据的能力.ORACLE公司在其Oracle8i中通过提供LOB

Oracle获取LOB长度的两种方法效率对比

前两天写了一篇文章,介绍LENGTH等一系列的常规函数一样可以处理LOB类型,有人在BLOG回复中提到,使用LENGTH的效率要比DBMS_LOB.GETLENGTH低,这里进行简单的测试. 建立一个测试表: SQL> CREATE TABLE T_LOB (ID NUMBER, CONTENTS CLOB); Table created. SQL> DECLARE 2     V_LOB CLOB; 3  BEGIN 4        INSERT INTO T_LOB 5     VALU

Oracle的Lob介绍

Lob的定义 像Oracle这种关系型数据库,比较擅长处理结构化的数据,那么对于非结构化的数据,Oracle是怎 么处理和存储的呢?Lob (Large Object)是Oracle专门用来处理半结构化和非结构化数据,它是一个大 对象数据类型,可以存储超过4000字节的字符串.二进制数据. Lob的类型 有两种Lob,非常是Internal Lob和External Lob.所谓Internal Lob是指Lob数据存储在Oracle数 据文件里,External Lob是指Lob数据存储在数据

ibatis操作oracle中CLOB类型的值

问题描述 ibatis操作oracle中CLOB类型的值 页面我是用了Struts标签,ibatis需要操作oracle中的CLOB类型的数据,该怎么操作?ibatis配置文件中需要设置什么样的类型于其对应.java中的实体类我是不是需要定义成CLOB类型呢?> 解决方案 可以配置ParameterMap和ResultMap就可以方便的实现对LOB的读写了,而且不用去实现任何类.只需要配置就可以了. 如: 这是返回的Clob 这是参数里面包含CLob 解决方案二: 解决方案三: 解决方案四: 解