是否达到 4,000 字节的极限? 我们先来了解一下 LOB...... SELECT DISTINCT <lob_type> ORDER BY <lob_type> GROUP BY <lob_col> 将 LOB 类型列用于表连接、 UNION、 INTERSECTION 和 MINUS 语句也是非法的。 在 LOB 使用的其他方面存在更多限制,例如,您不能将 LOB 用作主键列。 有关详细信息,请再次参阅 Oracle 数据库应用程序开发人员指南 - 大型对象。 CLOB 和字符集 数据库的默认字符集由参数 NLS_CHARACTERSET 定义,应使用该字符集对位于 CLOB 中的文本进行编码。 使用以下 SQL 确定数据库字符集编码:SELECT value FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET' 鉴于 PHP 中缺乏对 NCLOB 的支持,因此您可能需要考虑将 Unicode 编码(如 UTF-8)用作数据库字符,这可以通过以下语句实现(假设您有足够的权限): ALTER DATABASE CHARACTER SET UTF8 注意: 在您不了解影响的情况下不要尝试该操作,尤其是如果现有数据或应用程序代码使用其他字符集。 有关更多信息, 请参阅 Oracle 全球化支持指南和 全球化 Oracle PHP 应用程序概述。 PHP OCI8 扩展在全局 PHP 命名空间中注册一个称作“OCI-Lob”的 PHP 类。 当您执行 SELECT 语句时(例如,其中的某一列的类型为 LOB),PHP 将把它自动绑定到 OCI-Lob 对象实例。 引用 OCI-Lob 对象后,可以调用类似 load() 和 save() 这样的方法来访问或修改 LOB 的内容。 可用的 OCI-Lob 方法将取决于 PHP 的版本,PHP5 特别提供了 read() 、 seek() 和 append() 等方法。 PHP 手册对提供可用 OCI-Lob 方法的 PHP 版本号介绍得不够明确,因此,如果您存在疑问,可以使用以下脚本进行确认。 <?php foreach (get_class_methods('OCI-Lob') as $method ) { print "OCI-Lob::$method()\n"; } ?> 在我的系统上运行 PHP 5.0.5 时,我获得了以下方法列表: OCI-Lob::load() OCI-Lob::tell() OCI-Lob::truncate() OCI-Lob::erase() OCI-Lob::flush() OCI-Lob::setbuffering() OCI-Lob::getbuffering() OCI-Lob::rewind() OCI-Lob::read() OCI-Lob::eof() OCI-Lob::seek() OCI-Lob::write() OCI-Lob::append() OCI-Lob::size() OCI-Lob::writetofile() OCI-Lob::writetemporary() OCI-Lob::close() OCI-Lob::save() OCI-Lob::savefile() OCI-Lob::free() 实际上,PHP 4.x OCI8 扩展只支持读取或写入完整的 LOB,这是 Web 应用程序中最常见的用法。 PHP5 对此进行了扩展,从而可以读取和写入 LOB 的“块”,同时还使用 setBuffering() 和 getBuffering() 方法支持 LOB 缓冲。 PHP5 还提供了独立函数oci_lob_is_equal() 和 oci_lob_copy() 。 此处的示例将使用新的 PHP5 OCI 函数名(例如,用 oci_parse 代替 OCIParse )。 这些示例使用以下序列和表: CREATE SEQUENCE mylobs_id_seq NOMINVALUE NOMAXVALUE NOCYCLE CACHE 20 NOORDER INCREMENT BY 1; CREATE TABLE mylobs ( id NUMBER PRIMARY KEY, mylob CLOB ) 注意,此处的大多数示例都使用 CLOB,但同一逻辑几乎完全可以应用于 BLOB。 插入 LOB <?php // connect to DB etc... $sql = "INSERT INTO mylobs ( id, mylob ) VALUES ( mylobs_id_seq.NEXTVAL, --Initialize as an empty CLOB EMPTY_CLOB() ) RETURNING --Return the LOB locator mylob INTO :mylob_loc"; $stmt = oci_parse($conn, $sql); // Creates an "empty" OCI-Lob object to bind to the locator $myLOB = oci_new_descriptor($conn, OCI_D_LOB); // Bind the returned Oracle LOB locator to the PHP LOB object oci_bind_by_name($stmt, ":mylob_loc", $myLOB, -1, OCI_B_CLOB); // Execute the statement using , OCI_DEFAULT - as a transaction oci_execute($stmt, OCI_DEFAULT) or die ("Unable to execute query\n"); // Now save a value to the LOB if ( !$myLOB->save('INSERT: '.date('H:i:s',time())) ) { // On error, rollback the transaction oci_rollback($conn); } else { // On success, commit the transaction oci_commit($conn); } // Free resources oci_free_statement($stmt); $myLOB->free(); // disconnect from DB etc. ?> 注意该示例如何使用事务,它使用 OCI_DEFAULT 常量指示 oci_execute 等待 oci_commit 或 oci_rollback 。 这一点很重要,因为我在 INSERT 中分两个阶段执行操作 - 首先创建行,然后更新 LOB。 注意,如果我使用了 BLOB 类型,则唯一需要更改(假设有一个 BLOB 列)的就是 oci_bind_by_name 调用: oci_bind_by_name($stmt, ":mylob_loc", $myLOB, -1, OCI_B_BLOB); 或者,您也可以直接绑定字符串而不必指定 LOB 类型; <?php // etc. $sql = "INSERT INTO mylobs ( id, mylob ) VALUES ( mylobs_id_seq.NEXTVAL, :string ) "; $stmt = oci_parse($conn, $sql); $string = 'INSERT: '.date('H:i:s',time()); oci_bind_by_name($stmt, ':string', $string); oci_execute($stmt) or die ("Unable to execute query\n"); // etc. ?> 该方法极大地简化了代码,并且在要写入 LOB 的数据相对较小的情况下比较合适。 相反,如果要将大型文件的内容传送到 LOB 中, 则可以遍历该文件的内容,方法是对 PHP LOB 对象调用 write() 和 flush() 以写入较小的块,而不是在单个实例中将整个文件保存在内存中。 <?php // etc. $sql = "SELECT * FROM mylobs ORDER BY Id "; $stmt = oci_parse($conn, $sql); oci_execute($stmt) or die ("Unable to execute query\n"); while ( $row = oci_fetch_assoc($stmt) ) { print "ID: {$row['ID']}, "; // Call the load() method to get the contents of the LOB print $row['MYLOB']->load()."\n"; } // etc. ?> 可以进一步简化以上代码,方法是使用 OCI_RETURN_LOBS 常量(与 oci_fetch_array() 结合使用)并指示它用 LOB 对象的值替换这些对象: while ( $row = oci_fetch_array($stmt, OCI_ASSOC+OCI_RETURN_LOBS) ) { print "ID: {$row['ID']}, {$row['MYLOB']}\n"; } 更新 LOB 要使用 UPDATE 更新 LOB,也可以在 SQL 中使用“ RETURNING”命令(与上面的 INSERT 示例一样),但一个更简单的方法是使用SELECT ... FOR UPDATE: <?php // etc. $sql = "SELECT mylob FROM mylobs WHERE id = 3 FOR UPDATE /* locks the row */ "; $stmt = oci_parse($conn, $sql); // Execute the statement using OCI_DEFAULT (begin a transaction) oci_execute($stmt, OCI_DEFAULT) or die ("Unable to execute query\n"); // Fetch the SELECTed row if ( FALSE === ($row = oci_fetch_assoc($stmt) ) ) { oci_rollback($conn); die ("Unable to fetch row\n"); } // Discard the existing LOB contents if ( !$row['MYLOB']->truncate() ) { oci_rollback($conn); die ("Failed to truncate LOB\n"); } // Now save a value to the LOB if ( !$row['MYLOB']->save('UPDATE: '.date('H:i:s',time()) ) ) { // On error, rollback the transaction oci_rollback($conn); } else { // On success, commit the transaction oci_commit($conn); } // Free resources oci_free_statement($stmt); $row['MYLOB']->free(); // etc. ?> 与 INSERT 一样,我需要使用事务执行 UPDATE。 一个重要的额外步骤是调用 truncate() 。 使用 save() 更新 LOB 时,它将替换 LOB 的内容,范围从开头一直到新数据的长度。 这意味着较旧的内容(如果它比新内容长)可能仍保留在 LOB 中。 对于 PHP 4.x(其中未提供 truncate()),以下替换解决方案使用 Oracle 的 EMPTY_CLOB() 函数删除 LOB 中的任何现有内容,然后将新数据保存到其中。 $sql = "UPDATE mylobs SET mylob = EMPTY_CLOB() WHERE id = 2403 RETURNING mylob INTO :mylob "; $stmt = OCIParse($conn, $sql); $mylob = OCINewDescriptor($conn,OCI_D_LOB); OCIBindByName($stmt,':mylob',$mylob, -1, OCI_B_CLOB); // Execute the statement using OCI_DEFAULT (begin a transaction) OCIExecute($stmt, OCI_DEFAULT) or die ("Unable to execute query\n"); if ( !$mylob->save( 'UPDATE: '.date('H:i:s',time()) ) ) { OCIRollback($conn); die("Unable to update lob\n"); } OCICommit($conn); $mylob->free(); OCIFreeStatement($stmt); 使用 BFILES 使用 BFILE 类型时, INSERT 和 UPDATE 将该文件在数据库服务器(可能与 Web 服务器不在同一计算机上)的文件系统中的位置告知 Oracle,而不是传递文件内容。 使用 SELECT 语句,您可以通过 Oracle 读取 BFILE 的内容(如果您愿意),也可以调用 DBMS_LOB 程序包中的函数和过程来获取有关文件的信息。 BFILE 的主要优点是能够直接从文件系统中访问原始文件,同时仍然可以使用 SQL 定位文件。 例如,这意味着 Web 服务器可以直接提供映射,而我可以跟踪包含 BFILES 的表与“users”表(指示哪些用户上载了文件)之间的关系。 在示例中,我首先需要更新上面使用的表模式; ALTER TABLE mylobs ADD( mybfile BFILE ) 然后,我需要使用 Oracle 注册一个目录别名(这需要管理权限)并授予对该目录的读取权限: CREATE DIRECTORY IMAGES_DIR AS '/home/harryf/public_html/images' GRANT READ ON DIRECTORY IMAGES_DIR TO scott 我现在可以使用 INSERT 插入一些如下所示的 BFILE 名称: <?php // etc. // Build an INSERT for the BFILE names $sql = "INSERT INTO mylobs ( id, mybfile ) VALUES ( mylobs_id_seq.NEXTVAL, /* Pass the file name using the Oracle directory reference I created called IMAGES_DIR */ BFILENAME('IMAGES_DIR',:filename) )"; $stmt = oci_parse($conn, $sql); // Open the directory $dir = '/home/harryf/public_html/images'; $dh = opendir($dir) or die("Unable to open $dir"); // Loop through the contents of the directory while (false !== ( $entry = readdir($dh) ) ) { // Match only files with the extension .jpg, .gif or .png if ( is_file($dir.'/'.$entry) && preg_match('/\.(jpg|gif|png)$/',$entry) ) { // Bind the filename of the statement oci_bind_by_name($stmt, ":filename", $entry); // Execute the statement if ( oci_execute($stmt) ) { print "$entry added\n"; } } } 如果需要,我可以通过 Oracle 读取 BFILE 的内容,方法与我在上面选择 CLOB 时所采用的方法相同。 或者,如果我需要获得文件名,则可以直接从文件系统中访问它们,我可以调用如下所示的 DBMS_LOB.FILEGETNAME 过程: <?php // etc. $sql = "SELECT id FROM mylobs WHERE -- Select only BFILES which are not null mybfile IS NOT NULL; $stmt1 = oci_parse($conn, $sql); oci_execute($stmt1) or die ("Unable to execute query\n"); $sql = "DECLARE locator BFILE; diralias VARCHAR2(30); filename VARCHAR2(30); BEGIN SELECT mybfile INTO locator FROM mylobs WHERE id = :id; -- Get the filename from the BFILE DBMS_LOB.FILEGETNAME(locator, diralias, filename); -- Assign OUT params to bind parameters :diralias:=diralias; :filename:=filename; END;"; $stmt2 = oci_parse($conn, $sql); while ( $row = oci_fetch_assoc ($stmt1) ) { oci_bind_by_name($stmt2, ":id", $row['ID']); oci_bind_by_name ($stmt2, ":diralias", $diralias,30); oci_bind_by_name ($stmt2, ":filename", $filename,30); oci_execute($stmt2); print "{$row['ID']}: $diralias/$filename\n"; } // etc. ?> 此外,您可以使用 DBMS_LOB.FILEEXISTS 函数找出操作系统已经删除但在数据库中仍然引用的文件。 php 保存图片二进制到oracle数据库CREATE TABLE "YDCX_USER"."MYLOBS1" ( "ID" NUMBER NOT NULL ENABLE, "MYLOB" BLOB) $conn = oci_connect('用户名', '密码','地址'); //查询blob类型 $sql = "SELECT mylob from mylobs where id=11 "; $stmt = oci_parse($conn, $sql); oci_execute($stmt); //header("Content-type:image/gif"); while ( $row = oci_fetch_assoc($stmt) ) { $aa=$row['MYLOB']->load(); } file_put_contents('11.jpg',$aa); //插入 图片 blob $stmt = oci_parse($conn, "insert into mylobs (id, mylob) values(mylobs_id_seq.NEXTVAL, EMPTY_BLOB()) returning mylob into :the_blob"); $myLOB = oci_new_descriptor($conn, OCI_D_LOB); oci_bind_by_name($stmt, ":the_blob", $myLOB, -1, OCI_B_BLOB); oci_execute($stmt, OCI_DEFAULT) or die ("Unable to execute query\n"); if ( !$myLOB->save(file_get_contents('815151532654147937.jpg')) ) { oci_rollback($conn); } else { oci_commit($conn); } oci_free_statement($stmt); $myLOB->free();
|