此實現為用java訪問mysql的blob,對圖片進行存取
創新互聯從2013年開始,先為長汀等服務建站,長汀等地企業,進行企業商務咨詢服務。為長汀企業網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。
/**
* Title: BlobPros.java
* Project: test
* Description: 把圖片存入mysql中的blob字段,并取出
* Call Module: mtools數據庫中的tmp表
* File: C:downloadsluozsh.jpg
* Copyright: Copyright (c) 2003-2003
* Company: uniware
* Create Date: 2002.12.5
* @Author: ChenQH
* @version 1.0 版本*
*
* Revision history
* Name Date Description
* ---- ---- -----------
* Chenqh 2003.12.5 對圖片進行存取
*
* note: 要把數據庫中的Blob字段設為longblob
*
*/
//package com.uniware;
import java.io.*;
import java.util.*;
import java.sql.*;
public class BlobPros
{
private static final String URL = "jdbc:mysql://10.144.123.63:3306/mtools?user=windpassword=123useUnicode=true";
private Connection conn = null;
private PreparedStatement pstmt = null;
private ResultSet rs = null;
private File file = null;
public BlobPros()
{
}
/**
* 向數據庫中插入一個新的BLOB對象(圖片)
* @param infile 要輸入的數據文件
* @throws java.lang.Exception
*/
public void blobInsert(String infile) throws Exception
{
FileInputStream fis = null;
try
{
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
conn = DriverManager.getConnection(URL);
file = new File(infile);
fis = new FileInputStream(file);
//InputStream fis = new FileInputStream(infile);
pstmt = conn.prepareStatement("insert into tmp(descs,pic) values(?,?)");
pstmt.setString(1,file.getName()); //把傳過來的第一個參數設為文件名
//pstmt.setBinaryStream(2,fis,(int)file.length()); //這種方法原理上會丟數據,因為file.length()返回的是long型
pstmt.setBinaryStream(2,fis,fis.available()); //第二個參數為文件的內容
pstmt.executeUpdate();
}
catch(Exception ex)
{
System.out.println("[blobInsert error : ]" + ex.toString());
}
finally
{
//關閉所打開的對像//
pstmt.close();
fis.close();
conn.close();
}
}
/**
* 從數據庫中讀出BLOB對象
* @param outfile 輸出的數據文件
* @param picID 要取的圖片在數據庫中的ID
* @throws java.lang.Exception
*/
public void blobRead(String outfile,int picID) throws Exception
{
FileOutputStream fos = null;
InputStream is = null;
byte[] Buffer = new byte[4096];
try
{
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
conn = DriverManager.getConnection(URL);
pstmt = conn.prepareStatement("select pic from tmp where id=?");
pstmt.setInt(1,picID); //傳入要取的圖片的ID
rs = pstmt.executeQuery();
rs.next();
file = new File(outfile);
if(!file.exists())
{
file.createNewFile(); //如果文件不存在,則創建
}
fos = new FileOutputStream(file);
is = rs.getBinaryStream("pic");
int size = 0;
/* while(size != -1)
{
size = is.read(Buffer); //從數據庫中一段一段的讀出數據
//System.out.println(size);
if(size != -1) //-1表示讀到了文件末
fos.write(Buffer,0,size);
} */
while((size = is.read(Buffer)) != -1)
{
//System.out.println(size);
fos.write(Buffer,0,size);
}
}
catch(Exception e)
{
System.out.println("[OutPutFile error : ]" + e.getMessage());
}
finally
{
//關閉用到的資源
fos.close();
rs.close();
pstmt.close();
conn.close();
}
}
public static void main(String[] args)
{
try
{
BlobPros blob = new BlobPros();
//blob.blobInsert("C:Downloadsluozsh1.jpg");
blob.blobRead("c:/downloads/1.jpg",47);
}
catch(Exception e)
{
System.out.println("[Main func error: ]" + e.getMessage());
}
}
}
存圖片的路徑只需要最后的 \microMsg.2.jpg (之前的一截存數據庫浪費空間)
之前的一截,用配置文件寫好,跟網絡訪問路徑對應就好了,
你就把一張圖片當成一個servlet來看待就好了
記得在web服務器上配置訪問路徑跟圖片路徑的映射關系,不是自己的電腦,沒有例子
表格顯示控件是刷新率比較慢的一類控件,的確容易造成閃爍,有如下幾個辦法改善閃爍:
a) 如果系統對采樣率要求不高,加一個延時,一般延時300ms或以上時,就不會閃爍了
b) 如果系統無法延時這么長時間,請在前面板的【表格顯示控件】上單擊右鍵,選第一行【顯示項】,把【垂直滾動條】和【水平滾動條】的勾選去掉,會明顯改善閃爍。
c) 還有一個方法就是加一個CASE結構,把【表格】放在【CASE】里面,每隔500ms才刷新一次表格。
另一個方法是使用字符串顯示控件。這個控件刷新速度非???,不會有任何閃爍,但是有兩個缺點,第一是需要把字符串預先連接起來,第二是沒有表格線。
下面是附圖:
圖1.a :延時300毫秒
圖1.b :取消垂直和水平滾動條
圖1.c :每500次循環刷新表格一次
圖2 :用字符串顯示控件代替表格
下圖是效果:
商品圖片,用戶上傳的頭像,其他方面的圖片。目前業界存儲圖片有兩種做法:
1、 把圖片直接以二進制形式存儲在數據庫中
一般數據庫提供一個二進制字段來存儲二進制數據。比如MySQL中有個blob字段。Oracle數據庫中是blob或bfile類型
2、 圖片存儲在磁盤上,數據庫字段中保存的是圖片的路徑。
一、圖片以二進制形式直接存儲在數據庫中
第一種存儲實現(PHP語言):
大體思路:
1、將讀取到的圖片用php程序轉化成二進制形式。再結合insert into 語句插入數據表中的blob類型字段中去。
3、 從數據庫取出圖片展示的時候。則是直接發送圖片內容
4、
$row=mysql_fetch_object($result);
Header( "Content-type: image/gif");
echo $row-this_image;
實現代碼如下:
$PicturePath = ‘/tmp/xxxjgjgj.jpg’;//假設這是上傳的圖片,php放在一個臨時文件夾。腳本執行完畢后自動刪除了。
$imgStream = fread(fopen($PicturePath, "r");
$blob_img = fread(fopen($imgStream, "r"), filesize($PicturePath));
$sql =” INSERT INTO Images (this_image) VALUES ($blob_img)";
注:this_image就是數據表中一個blob字段類型的字段
================取出展示圖片代碼
$result=mysql_query("SELECT * FROM Images WHERE PicNum=$PicNum") or die("Cant perform Query");
$row=mysql_fetch_object($result);
Header( "Content-type: image/gif");
echo $row- this_image;
總結:處理代碼感覺還真比較麻煩。其實,我從來沒用過在數據庫中以二進制存儲圖片的做法。我們用得更多的是存儲圖片的路徑,實際圖片是在磁盤上保存的(圖片二進制放到數據庫,把數據庫的負擔弄重了)。
據我了解,互聯網環境中,大訪問量,數據庫速度和性能方面很重要。一般在數據庫存儲圖片的做法比較少,更多的是將圖片路徑存儲在數據庫中,展示圖片的時候只需要連接磁盤路徑把圖片載入進來即可。因為圖片是屬于大字段。一張圖片可能1m到幾m。
有個原則:圖片盡量不要存儲在數據庫中(是指不要二進制形式保存到字段,而只保存圖片的路徑)。這樣的大字段數據會加重數據庫的負擔,拖慢數據庫。在大并發訪問的情況下很重要。這是一個經驗。去看看dba對數據庫性能調優方面的分析都能得到這個答案的:就是圖片不要存儲在數據庫中。
就像這個規則一樣:文章分為標題、作者、添加時間、更新時間、文章內容、文章關鍵字
文章內容一般是比較長的。經常使用text字段去存儲。文章的內容就屬于大字段。一般文章內容可以拆分到單獨一個表中去。不要與文章信息存儲在一張表里面。
我理解的原理是:mysql中一張表的數據是全部在一個數據文件中的。如果大字段的數據也存儲在里面。程序展示列表,比如文章列表。這個時候根本不需要展示文章內容的。但是仍然會影響速度,數據庫查找數據其實就是掃描那個數據文件,文件容量越小,速度就會越快(為什么單表的容量在1g-2g的時候基本上要分表了)。拆分出去到一張單獨的表,就是單獨的文件了。我覺得,舉一反三,相互獨立,分離的思想不僅在系統開發中用到,在現實生活中經常存在的。相互混合,就會造成相互影響。小巧,簡潔是一種思想。
可以看看這篇翻譯的文章,
http//developer.51cto.com/art/201211/364472.htm
作者建議,三種東西永遠不要放到數據庫里,圖片,文件,二進制數據。作者的理由是,
對數據庫的讀/寫的速度永遠都趕不上文件系統處理的速度
數據庫備份變的巨大,越來越耗時間
對文件的訪問需要穿越你的應用層和數據庫層
把圖片縮略圖存到數據庫里?很好,那你就不能使用nginx或其它類型的輕量級服務器來處理它們了。
給自己行個方便吧,在數據庫里只簡單的存放一個磁盤上你的文件的相對路徑,或者使用S3(備注:亞馬遜云服務)或CDN之類的服務。
============================================================
關于mysql中的blob類型
bolb像int型那樣,分為blob、MEDIUMBLOB、LONGBLOB。其實就是從小到大,
blob 容量為64KB ,MEDIUMBLOB 容量為16M,LONGBLOB 容量為4G。
說實話,圖片用這樣子存儲用得還真少。使用php函數serialize進行序列化的值,我看到有人存入這個字段中去。
php手冊:serialize返回字符串,此字符串包含了表示 value 的字節流,可以存儲于任何地方。
mysql中blob字段存儲圖片有個通信大小的設置:
圖片要傳輸給mysql存儲起來,那么需要涉及到數據通信。mysql中有個配置是限制通信數據大小的。
my.conf配置文件中的max_allowed_packet,mysql默認的值是1M。
好多圖片尤其是原始圖可能不止1m。傳輸的數據(也就是圖片)超過這個設置大小。結果就會出錯
呵呵,限制挺多。感覺好麻煩。這樣子明顯占用與mysql交互的通信時間嘛。延長響應時長了。我直接丟個圖片路徑”images/xxxx”給mysql。沒這么耗費資源。
其實所謂的性能,最關鍵是數據庫性能。因為隨著數據庫數據量增大,大部分時間耗費是在php,Java等語言等待數據庫返回數據的過程中耗費時間。
網站訪問量大了后,具體的語言不是瓶頸,瓶頸都在數據庫。用c,,php,java,net都能操作mysql數據庫獲取數據。語言之間可能存在速度執行差異,但是其實這種差別已經很小了。至少我覺得,給予用戶感覺不到明顯。執行相差0.0001秒用戶感覺并沒有明顯的區別。可能說,大并發(很多用戶同時訪問)的時候,就會體現到差別了。其實我覺得,大并發訪問是數據庫瓶頸。等待數據庫給予數據。沒達到一定級別實在體現不了差別。數據庫數據量達到一定級別。語言相差0.001s會給予用戶體驗上的差別。我想,這也是為什么php很適合做web開發了。解析頁面速度快(解釋型語言,不需要編譯)??梢杂胘ava來與數據庫打交道獲取數據。php不直接操作數據庫,而是調用java提供的數據接口,獲取數據,馬上展示在頁面中。這是利用了php的頁面執行速度快的一個優勢。
備份圖片數據和遷移數據方便
圖片以二進制形式存儲在數據庫,有一個好處:備份的時候方便。直接備份數據庫,圖片也跟著備份。換句話說,遷移環境的時候是方便。
而圖片放在磁盤上的話,數據庫中存儲的只是圖片路徑。備份數據庫后。磁盤上的圖片也要跟著備份才行。
不過我覺得,備份這個好處不是很明顯。圖片在磁盤上,備份磁盤也沒很大的事情。打包壓縮也可以了?;ヂ摼W環境畢竟與傳統的軟件開發不同,web開發比較關注網站速度。也就是數據庫的速度。就像互聯網開發中,有時候為了速度,用空間換時間的做法比較普遍,所以往往在設計數據庫的時候并不一定遵循傳統數據庫設計三大范式。
數據庫中保存的是圖片路徑的話,在web開發環境下,其實有個更好處,就是cdn加速。就是下面要進行總結的地方。
二、數據庫中保存圖片路徑
一般是這樣子的:
按照年月日生成路徑。具體是按照年月日還是按照年月去生成路徑,根據自己需要(不一定是按照日期去生成)。
理解為什么要分散到多個文件夾中去才是關鍵,涉及到一個原理就明白了:
操作系統對單個目錄的文件數量是有限制的。當文件數量很多的時候。從目錄中獲取文件的速度就會越來越慢。所以為了保持速度,才要按照固定規則去分散到多個目錄中去。
圖片分散到磁盤路徑中去。數據庫字段中保存的是類似于這樣子的”images/2012/09/25/ 1343287394783.jpg”
原來上傳的圖片文件名稱會重新命名保存,比如按照時間戳來生成,1343287394783. jpg。這樣子是為了避免文件名重復,多個人往同一個目錄上傳圖片的時候會出現。
反正用什么樣的規則命名圖片,只要做到圖片名稱的唯一性即可。
比如網站的并發訪問量大,目錄的生成分得月細越好。比如精確到小時,一個小時都可以是一個文件夾。同時0.001秒有兩個用戶同時在上傳圖片(因為那么就會往同一個小時文件夾里面存圖片)。因為時間戳是精確到秒的。為了做到圖片名稱唯一性而不至于覆蓋,生成可以在在時間戳后面繼續加毫秒微秒等。總結的規律是,并發訪問量越大。就越精確就好了。
我現在還沒碰到需要這么精細的。概率比較少。
有個方面總結一下:為什么保存的磁盤路徑,是”images/2012/09/25/1343287394783.jpg”,而不是” /images/2012/09/25/ 1343287394783.jpg”(最前面帶有斜杠)
我的理解:
連那個斜杠都不要。這里也是做到方便以后系統擴展。
在頁面中需要取出圖片路徑展示圖片的時候,如果是相對路徑,則可以使用”./”+”images/2012/09/25/1343287394783.jpg”進行組裝。
如果需要單獨的域名(比如做cdn加速的時候)域名,img1.xxx.com,img2.xxx.com這樣的域名,
直接組裝 “http//img1.xxx.com/”+”images/2012/09/25/1343287394783.jpg”
當然數據庫是可以在前面加斜杠/保存起來,/images/2012/09/25/ 1343287394783.jpg
其實不方便統一。比如相對路徑載入圖片的時候,則是”.”+” /images/2012/09/25/ 1343287394783.jpg”
可能我還沒體會到壞處,以后會遇到問題的。不過,遵循慣例不加斜杠” images/2012/09/25/ 1343287394783.jpg”就對了。
涉及到一個新問題:為什么大部分系統都不會域名保存進去,像這樣子http//wwwxxx.com/images/2012/09/25/1343287394783.jpg保存到數據庫中
曾經與一個上海的網友聊天,他也是習慣不會把域名保存數據庫中過去。但當時我們兩聊的時候,他對”域名保存進去的做法”與”不保存域名進去”也沒有一個明確利弊。他就覺得,沒有什么明顯的區別啊。
了解的知識越多,越有利于我們做決定。可能就是一個”感覺區別不是很大”的影響下,去做一個決定,反而對后面是比較大的影響的。至少是增加自己的工作量了。
其實把域名保存進去,也不是什么滔天大罪的事情。但凡是經驗豐富的開發人員都不會這樣子做。這是一個經驗積累出來的,所以上海那個網友也對此并沒有明顯的概念很正常,他說他不知道cdn方面的(當然覺得存個域名進去沒什么大不了的)。需要了解cdn知識,什么情況下會用到cdn知識。
雖然是做開發人員,不需要關注運維和服務器之類的知識。不過了解一些就有利于理解了。
這里涉及到cdn加速。
關于cdn原理(就是內容分發網絡)
cdn,我理解其本質就是為了解決距離遠產生的速度問題,使用就近的服務。
從中國請求美國一臺服務器上的圖片。一般比較慢,因為距離這么遠,網絡傳輸是存在損耗的,距離越遠,傳輸的時間就越長。一般會看到瀏覽器左下角顯示:“已響應,正在傳輸數據..”。這不是服務器本身問題了。實際上服務器早就響應請求,把數據發給客戶端,但是網絡問題,就一直在傳輸,沒傳完了。
在中國,是南北距離遠的問題。南北還會涉及到跨網,南方用戶使用電信居多,北方用戶網通居多。兩個線路需要跨越,會有時間延遲。北京到廣州的距離,如果直接請求
cdn加速就是適應這個需求產生的:現在不請求美國的服務器。直接在中國安放節點(節點是比較籠統的詞語,可以理解成一臺服務器,也可以理解成一個機房,就是一個點嘛),請求距離近的節點。這樣子就不需要那么遠的距離了。
記得以前在長沙的網站,團購以城市分站的形式。北京和長沙用的是同一套程序。服務器在長沙。北京用戶訪問北京站的時候,實際上需要遠距離訪問長沙的服務器。速度怎么都快不起來。跟服務器性能完全沒關系。當時不懂這些。不清楚怎么折騰。看那本《前端優化技巧》,想辦法去做js代碼壓縮,瀏覽器緩存之類的。實際上瞎折騰。不是說這些前端優化不重要,哲學上有主次矛盾之分,瓶頸在哪里就去突破哪里。沒解決主要矛盾,問題并不會迎刃而解。當時也不是數據庫瓶頸。如果去優化數據庫。也不會明顯改善。就那點數據量。根本就達不到瓶頸。哪里談得上主要矛盾。隨著后來去其他公司工作,接觸一些東西,類似不找瓶頸的優化例子發生在身邊好幾次了,先沒找到瓶頸就瞎去優化。我的同事可能是抱著多多益善的心態去做的,但主要矛盾(技術上說是瓶頸)沒找到,也沒改善。
當時如果沒想到是距離問題。也就不會想到cdn,當時其實我根本不知道cdn服務。我只知道,google這些網站肯定在中國部署的服務器,要不然,中國用戶還去訪問美國的服務器,那再好的服務器都會速度慢的。
由于自己搭建cdn環境和機房的資金比較大(需要大量的服務器),也需要人力維護。反正一般的公司弄不起,其實根本不劃算。淘寶以前用商用的cdn服務,后來商用的扛不住了,就搭建了自己的cdn網。我不知道新浪有沒有自己搭建,但其實我覺得跟淘寶的特點有關,店鋪很多,無論是商品還是交易記錄總計起來商品很多的圖片,圖片都是靜態的部分,cdn本來就是用來做靜態的(圖片,css,js等)請求分發用的。
我之前在網上看到一句話,cdn網絡不是一般的公司玩得起的。
一般的公司自己搭建cdn網絡成本高,所以就有商業的cdn提供付費租用服務,這是一項很成熟的業務,很多這樣的公司,大部分全國性的互聯網公司都會使用到cdn。
總結:cdn服務。對于靜態內容是非常適合的。所以像商品圖片,隨著訪問量大了后,租用cdn服務,只需要把圖片上傳到他們的服務器上去。
例子:北京訪問長沙服務器,距離太遠。我完全可以把商品圖片,放到北京的云服務(我覺得現在提供給網站使用的云存儲其實就是cdn,給網站提供分流和就近訪問)上去。這樣子北京用戶訪問的時候,實際上圖片就是就近獲取。不需要很長距離的傳輸。
自己用一個域名img.xxxcom來載入圖片。這個域名解析到北京的云服務上去。
做法:數據庫中保存的是” images/2012/09/25/1343287394783.jpg”,
這些圖片實際上不存儲在web服務器上。上傳到北京的cdn服務器上去。
我從數據庫取出來,直接”img.xxxcom/”+” images/2012/09/25/1343287394783.jpg”
比如如果還有多個,就命名img1.xxcom、img2.xxcom
反正可以隨便。所以如果把域名直接保存進去。就顯得很麻煩了。遷移麻煩。
像淘寶,凡客,亞馬遜這些電子商務網站,我們看到請求的時候,下面往往會有
img1.xxx.cdncom
img2.xxx.cdncom
其實他們保存在數據庫中的是相對路徑。有些是不需要在數據庫保存的,縮略圖可以實時訪問的時候用程序生成(節省很多存儲空間)
實際上,把域名保存在數據庫中,非常不利于系統遷移。一旦換個域名的話,原來保存在數據庫中的是“wwwabc.om/images/xxxxxx“,因為路徑都在數據庫中寫死了。下回換個域名就用不了了。那個時候自己去寫sql語句批量更新字段吧。
幾個術語:
icp,Internet Content Provider,也就是網絡內容提供者。聯想到我們運營一個網站需要icp備案了嗎?你自己運營網站,你就是icp服務商
IDC(Internet Data Center),互聯網數據中心。IDC的概念,目前還沒有一個統一的標準。通俗點,就是提供機房托管(服務器租用和托管),域名注冊之類的。
關于淘寶的圖片存儲
了解到:淘寶以前使用了商用的存儲。但是沒法滿足需求。據說,到2010年,淘寶網后端保存著286億張圖片。商用的系統系統沒法滿足需求的時候。他們就自己開發了一個tfs。大規模的小文件在磁盤上讀取,需要磁盤磁頭頻繁的尋道和換道。大并發情況下和大量的操作確實很麻煩。其實借鑒了當時google公布的gfs設計論文。google有相冊服務。為每個用戶提供上傳圖片存儲。
估計,google是率先實現這種小文件網絡存儲系統的。
有個觀點比較好:對于老板們而言,往往覺得,用錢能解決的都不算問題。但問題在于,你遇到的問題,別人都沒遇到過。那這個時候你就沒有經驗可以參考或者直接拿來使用。只有自己參考一些思路去創造技術了。
三、關于圖片進行云存儲(cdn加速)
曾經看過這個,這個是比較適合創業公司的。價格相對便宜
https//wwwupyun.com/
介紹提到,我們在全國各地部署了55個CDN節點,500多臺服務器,電信,聯通,移動和教育網的4線帶寬。
其實,現在的云存儲本質就是一個cdn服務商。你把靜態的圖片上傳到他提供的服務器上去(ftp方式上傳或者api形式編寫程序上傳)。他為你做就近節點訪問。
計費方式:按照流量付費,99元購買100g。怎么算流量。每次訪問文件的大小累加,比如一個1m的文件,訪問一次流量就加1m。
我個人理解,對于圖片的量不大的情況下,使用這種云服務,好處不是節省存儲空間。你自己的服務器100g的空間可能創業型公司都沒用完,不是什么存儲空間不夠用,然后去用云存儲。以前我對cdn比較模糊,有這么點理解,或者以為是分散網站web服務器流壓力,服務器分流。這些好處是有的。但是,只要理解了cdn產生的背景和解決的關鍵問題后,就會明白云存儲關鍵好處在于:給用戶就近節點訪問,加速。
我覺得,如果不是出于這個考慮,或者達不到這樣的目的。用其他方案也完全可以替代。何必使用云存儲呢?就是你無非有實力做到全國多個節點去部署服務,才需要租用cdn來幫你,畢竟他們是規模產生的效益,專注于解決這個領域。
背景
MySQL 一直以來都有 TEXT、BLOB 等類型用來存儲圖片、視頻等大對象信息。比如一張圖片,隨便一張都 5M 以上。視頻也是,隨便一部視頻就是 2G 以上。
假設用 MySQL 來存放電影視頻等信息,一部是 2G,那么存儲 1000 部就是 2TB,2TB 也就是 1000 條記錄而已,但是對數據庫性能來說,不僅僅是看記錄數量,更主要的還得看占用磁盤空間大小??臻g大了,所有以前的經驗啥的都失效了。
所以一般來說存放這類信息,也就是存儲他們的存放路徑,至于文件本身存放在哪里,那這就不是數據庫考慮的范疇了。數據庫只關心怎么來的快,怎么來的小。
舉例
雖然不推薦 MySQL 這樣做,但是也得知道 MySQL 該怎么做才行,做到心里有數。比如下面一張微信圖片,大概 5M 的樣子。
root@ytt:/var/lib/mysql-files# ls -sihl 微信圖片_20190711095019.jpg274501 5.4M -rw-r--r-- 1 root root 5.4M Jul 11 07:17 微信圖片_20190711095019.jpg
拷貝 100 份這樣的圖片來測試
root@ytt:/var/lib/mysql-files# for i in `seq 1 100`; do cp 微信圖片_20190711095019.jpg "$i".jpg;done;
root@ytt:/var/lib/mysql-files# ls
100.jpg ? 17.jpg ?25.jpg ?33.jpg ?41.jpg ?4.jpg ? 58.jpg ?66.jpg ?74.jpg ?82.jpg ?90.jpg ?99.jpg ?f8.tsv
10.jpg ? ?18.jpg ?26.jpg ?34.jpg ?42.jpg ?50.jpg ?59.jpg ?67.jpg ?75.jpg ?83.jpg ?91.jpg ?9.jpg ? 微信圖片_20190711095019.jpg
1111.jpg ?19.jpg ?27.jpg ?35.jpg ?43.jpg ?51.jpg ?5.jpg ? 68.jpg ?76.jpg ?84.jpg ?92.jpg ?f1.tsv
11.jpg ? ?1.jpg ? 28.jpg ?36.jpg ?44.jpg ?52.jpg ?60.jpg ?69.jpg ?77.jpg ?85.jpg ?93.jpg ?f2.tsv
12.jpg ? ?20.jpg ?29.jpg ?37.jpg ?45.jpg ?53.jpg ?61.jpg ?6.jpg ? 78.jpg ?86.jpg ?94.jpg ?f3.tsv
13.jpg ? ?21.jpg ?2.jpg ? 38.jpg ?46.jpg ?54.jpg ?62.jpg ?70.jpg ?79.jpg ?87.jpg ?95.jpg ?f4.tsv
14.jpg ? ?22.jpg ?30.jpg ?39.jpg ?47.jpg ?55.jpg ?63.jpg ?71.jpg ?7.jpg ? 88.jpg ?96.jpg ?f5.tsv
15.jpg ? ?23.jpg ?31.jpg ?3.jpg ? 48.jpg ?56.jpg ?64.jpg ?72.jpg ?80.jpg ?89.jpg ?97.jpg ?f6.tsv
16.jpg ? ?24.jpg ?32.jpg ?40.jpg ?49.jpg ?57.jpg ?65.jpg ?73.jpg ?81.jpg ?8.jpg ? 98.jpg ?f7.tsv
我們建三張表,分別用 LONGBLOB、LONGTEXT 和 VARCHAR 來存儲這些圖片信息
mysql show create table tt_image1G
*************************** 1. row ***************************
Table: tt_image1
Create Table: CREATE TABLE `tt_image1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`image_file` longblob,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql show create table tt_image2G
*************************** 1. row ***************************
Table: tt_image2
Create Table: CREATE TABLE `tt_image2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`image_file` longtext,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql show create table tt_image3G
*************************** 1. row ***************************
Table: tt_image3
Create Table: CREATE TABLE `tt_image3` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`image_file` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
我們來給三張表插入 100 張圖片(插入前,建議把 max_allowed_packet 設置到最大)
tt_image1
root@ytt:/var/lib/mysql-files# for i in `seq 1 100`;
do mysql -S /var/run/mysqld/mysqld.sock -e "insert into ytt.tt_image1(image_file)
values (load_file('/var/lib/mysql-files/$i.jpg'))";done;
tt_image2
root@ytt:/var/lib/mysql-files# for i in `seq 1 100`;
do mysql -S /var/run/mysqld/mysqld.sock -e "insert into ytt.tt_image2(image_file)
values (hex(load_file('/var/lib/mysql-files/$i.jpg')))";done;
tt_image3
root@ytt:/var/lib/mysql-files# aa='begin;';for i in `seq 1 100`;
do aa=$aa"insert into ytt.tt_image3(image_file) values
('/var/lib/mysql-files/$i.jpg');";
done;aa=$aa'commit;';mysql -S /var/run/mysqld/mysqld.sock -e "`echo $aa`";
檢查下三張表記錄數
mysql select 'tt_image1' as name ,count(*) from tt_image1 union allselect 'tt_image2',count(*) from tt_image2 union all select 'tt_image3', count(*) from tt_image3;+-----------+----------+| name ? ? ?| count(*) |+-----------+----------+| tt_image1 | ? ? ?100 || tt_image2 | ? ? ?100 || tt_image3 | ? ? ?100 |+-----------+----------+3 rows in set (0.00 sec)
看下文件大小,可以看到實際大小排名,LONGTEXT 字段存儲的最大,LONGBLOB 字段縮小到一半,最小的是存儲圖片路徑的表 tt_image3。所以這里從存儲空間來看,存放路徑最占優勢。
root@ytt:/var/lib/mysql/ytt# ls -silhS tt_image*274603 1.1G -rw-r----- 1 mysql mysql 1.1G Jul 11 07:27 tt_image2.ibd274602 545M -rw-r----- 1 mysql mysql 544M Jul 11 07:26 tt_image1.ibd274605 ?80K -rw-r----- 1 mysql mysql 112K Jul 11 07:27 tt_image3.ibd
那么怎么把圖片取出來呢?
tt_image3 肯定是最容易的
mysql select * from tt_image3;+----+----------------------------+| id | image_file ? ? ? ? ? ? ? ? |+----+----------------------------+| ?1 | /var/lib/mysql-files/1.jpg |+----+----------------------------+...100 rows in set (0.00 sec)
tt_image1 直接導出來二進制文件即可,下面我寫了個存儲過程,導出所有圖片。
mysql DELIMITER $$mysql USE `ytt`$$mysql DROP PROCEDURE IF EXISTS `sp_get_image`$$mysql CREATE DEFINER=`ytt`@`localhost` PROCEDURE `sp_get_image`()mysql BEGIN ? ? ?DECLARE i,cnt INT DEFAULT 0; ? ? ?SELECT COUNT(*) FROM tt_image1 WHERE 1 INTO cnt; ? ? ?WHILE i cnt DO ? ? ? ?SET @stmt = CONCAT('select image_file from tt_image1 ?limit ',i,',1 into dumpfile ''/var/lib/mysql-files/image',i,'.jpg'''); ? ? ? ?PREPARE s1 FROM @stmt; ? ? ? ?EXECUTE s1; ? ? ? ?DROP PREPARE s1; ? ? ?SET i = i + 1; ? ? ?END WHILE; ? ? ?END$$mysql DELIMITER ;mysql call sp_get_image;
tt_image2 類似,把 select 語句里 image_file 變為 unhex(image_file) 即可。
總結
這里我舉了個用 MySQL 來存放圖片的例子,總的來說有以下三點:
占用磁盤空間大(這樣會帶來各種各樣的功能與性能問題,比如備份,寫入,讀取操作等)
使用不易
還是推薦用文件路徑來代替實際的文件內容存放
自己把路徑中的\換成\\
即C:\ABC\A.jpg 換成 C:\\ABC\\A.jpg
否則\及其后面的字符 合起來 會被當成轉義符
名稱欄目:cmysql怎么存圖片的簡單介紹
鏈接分享:http://vcdvsql.cn/article48/hepjhp.html
成都網站建設公司_創新互聯,為您提供靜態網站、小程序開發、Google、電子商務、全網營銷推廣、自適應網站
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯