一般在資料庫中,我們保存的都只是 int 、 varchar 型別的資料,一是因為現代的關系型資料庫對于這些內容會有很多的優化,二是大部分的索引也無法施加在內容過多的欄位上,比如說 text 型別的欄位就很不適合創建索引,所以,我們在使用資料庫時,很少會向資料庫中存盤很大的內容欄位,但是,MySQL 其實也為我們準備了這種型別的存盤,只是我們平常用得不多而已,今天我們就來學習了解一下使用 PDO 如何操作 MySQL 中的大資料物件,
什么是大資料物件
“大”通常意味著“大約 4kb 或以上”,盡管某些資料庫在資料達到“大”之前可以輕松地處理多達 32kb 的資料,大物件本質上可能是文本或二進制形式的,我們在 PDOStatement::bindParam() 或 PDOStatement::bindColumn() 呼叫中使用 PDO::PARAM_LOB 型別碼可以讓 PDO 使用大資料型別,PDO::PARAM_LOB 告訴 PDO 作為流來映射資料,以便能使用 PHP Streams API 來操作,
對于 MySQL 來說,將欄位型別設定為 blob 即是大物件格式的欄位,而在 bindParam() 或 bindColumn() 時,指定欄位的引數為 PDO::PARAM_LOB 型別,就可以直接以句柄形式獲得這個物件里面的內容,就像 fopen() 一樣地繼續對它進行操作,
CREATE TABLE `zy_blob` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`attach` longblob,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
這是我們測驗用的一個資料表,將 attach 欄位設定為了 longblob 型別,也就是比較大的 blob 型別,這樣我們就可以存盤更多地資訊,畢竟現在的圖片或檔案隨隨便便就是輕松地幾m或幾十m起步的,我們直接使用最大的 blob 型別來進行簡單地測驗,tinyblob 的大小為 255 位元組,blob 型別的大小為 65k ,mediumblob 為 16M ,longblob 為 4G ,
直接操作大資料物件會怎么樣?
我們先來簡單地直接操作大資料物件,看看是什么樣的結果,
$stmt = $pdo->prepare("insert into zy_blob (attach) values (?)");
$fp = fopen('4960364865db53dcb33bcf.rar', 'rb');
$stmt->execute([$fp]);
$stmt = $pdo->query("select attach from zy_blob where id=1");
$file = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($file);
// Array
// (
// [attach] => Resource id #6
// )
在這段代碼中,我們沒有系結欄位,然后直接將 fopen() 打開的檔案存盤到 blob 欄位中,可以看出,在資料庫中,blob 相關的欄位只是存盤了 Resource id #6 這樣的字串,也就是說,在不做任何處理的情況下,$fp 句柄被強制轉換成了字串型別,而句柄型別被強轉的結果就是只會輸出一個資源ID,而 blob 也只是和字符型別的欄位一樣記錄了這個字串而已,
正確的姿勢
接下來我們來看看正確的姿勢,也就是通過 bindParam() 來插入資料,通過 bindColumn() 來讀取資料,
$stmt = $pdo->prepare("insert into zy_blob (attach) values (?)");
$fp = fopen('4960364865db53dcb33bcf.rar', 'rb');
$stmt->bindParam(1, $fp, PDO::PARAM_LOB); // 系結引數型別為 PDO::PARAM_LOB
$stmt->execute();
$stmt = $pdo->prepare("select attach from zy_blob where id=2");
// // $file = $stmt->fetch(PDO::FETCH_ASSOC);
// // print_r($file); // 空的
$stmt->execute();
$stmt->bindColumn(1, $file, PDO::PARAM_LOB); // 系結一列到一個 PHP 變數
$stmt->fetch(PDO::FETCH_BOUND); // 指定獲取方式,回傳 TRUE 且將結果集中的列值分配給通過 PDOStatement::bindParam() 或 PDOStatement::bindColumn() 方法系結的 PHP 變數
print_r($file); // 二進制亂碼內容
$fp = fopen('a.rar', 'wb');
fwrite($fp, $file);
首先,我們通過 bindParam() 系結資料,并指定 PDO::PARAM_LOB 型別之后,就正常地向資料庫里插入了檔案的句柄二進制內容,接著,我們使用 bindColumn() 并且也指定 PDO::PARAM_LOB 型別來獲得查詢出來的資料,直接列印查詢出來的欄位資訊,就可以看到它是二進制的型別內容,最后,我們將這個二進制內容保存成另一個名稱的檔案,
大家可以替換上面的檔案內容,然后執行代碼來看看最后生成的檔案是不是和原來的檔案一樣的,我這里使用的是一個壓縮包檔案,最后生成的 a.rar 檔案和原始檔案大小以及解壓后的內容都是完全一致的,
總結
大資料物件操作的究竟是什么呢?其實就是我們平常要保存的大檔案,我們將這些檔案以二進制流的方式讀取到程式后,再將它們保存在資料庫的欄位中,想想我們平常開發用到的最多的圖片保存就可以用這個來做,但是,此處可以劃重點了,我們更加推薦的還是將檔案直接保存在檔案目錄中,而資料庫中只保存它們的路徑就可以了,資料庫資源是寶貴的,表越大越不利于優化,而且資料庫本身還有快取機制,浪費它的資源來保存這種大型的檔案其實是得不償失的,當然,如果有某些特殊的需要,比如一些私密檔案不想直接在硬碟檔案目錄中保存,或者做為臨時的跨服務器存盤方案都是可以的,
在現代開發中,相信你的公司也不會吝嗇到不去買一個云存盤(七牛、upyun、阿里云OSS),它們不僅僅是能夠做為一個存盤器、網盤,而是有更多的功能,比如圖片的裁剪、水印,贈送的 CDN 、帶寬 、 流量之類的,總之,現代的存盤大家還是盡量上云吧,即使是個人開發,也有不少廠商會提供小流量小資料量情況下的免費使用,這個都比我們自己來要方便很多,
測驗代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202008/source/PDO%E6%93%8D%E4%BD%9C%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1.php
參考檔案:
https://www.php.net/manual/zh/pdo.lobs.php
關注公眾號:【硬核專案經理】獲取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免費得PHP、專案管理學習資料
知乎、公眾號、抖音、頭條搜索【硬核專案經理】
B站ID:482780532
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/285582.html
標籤:PHP
上一篇:學習PDO中的錯誤與錯誤處理模式
