知乎專欄 | 多維度架構 | 微信號 netkiller-ebook | QQ群:128659835 請註明“讀者” |
你是是不是在開發中常常遇到,刪除了資料庫記錄後,發現該記錄對應的圖片沒有刪除,或者刪除了圖片,資料庫中仍有數據存在,你的網站臟數據(圖片)成幾何數增長,閲讀下文這裡為你提供了一個完美決方案。
我以電商網站為例,一般的網站產品數據存放在資料庫中,商品圖片是上傳到檔案伺服器,然後通過http伺服器瀏覽商品圖片。這是最基本的也是最常見做法。
稍複雜的方案是,如果圖片數量龐大,會使用分散式檔案系統方案。但是這些方案都不能保證數據的完整性,極易產生臟數據(垃圾數據)。臟數據是指當你刪除了資料庫表中的記錄後,圖片仍然存在,或者手工刪除了圖片,而資料庫中的記錄仍然存在。
將圖片放入資料庫中存放在BLOB的方法可以解決臟數據問題,典型的案例是公安的身份證系統。但這種方案的前提是,圖片不能太大,數量不多,訪問量不大。 這顯然不適合電商網站。
2009年我在走秀網工作,商品圖片與縮圖檔案900GB到2012離職已經有10TB,每天有成百上千的商品上架下架,很多商品下架後永遠不會再上架,這些批量下架的商品數據不會刪除,僅僅標記為刪除,總是期望以後能繼續使用,實際上再也不會有人過問,另一方面隨着品類經理頻繁更換,員工離職,這些商品會石沉大海,再也無人問均。這些商品所對應的圖片也就臟數據主要來源。新的品類經理上任後,會重新拍照,上傳新圖片。
總之,刪除資料庫中的數據不能將圖片刪除就會產生臟數據。很多採用刪除數據的時候去檢查圖片如果存在先刪除圖片,再刪除數據的方法。這種方案也非完美解決方案,存在這圖片先被刪除,程序出錯SQL沒有運行,或者反之。
mysql plugin 開發 udf。我寫幾個function
UDF
檢查圖片是否存在.
刪除圖片.
更改圖片檔案名.
md5sum 主要用戶圖片是否被更改過.
移動圖片的位置
有了上面的function後你就可以在begin,commit,rollback 直接穿插使用,實現在事物處理期間做你愛做的事。
編譯UDF你需要安裝下面的軟件包
sudo apt-get install pkg-config sudo apt-get install libmysqlclient-dev sudo apt-get install gcc gcc-c++ make automake autoconf
https://github.com/netkiller/mysql-image-plugin
編譯udf,最後將so檔案複製到 /usr/lib/mysql/plugin/
git clone https://github.com/netkiller/mysql-image-plugin.git cd mysql-image-plugin/src gcc -I/usr/include/mysql -I./ -fPIC -shared -o image.so image.c sudo mv image.so /usr/lib/mysql/plugin/
裝載
create function image_check returns boolean soname 'images.so'; create function image_remove returns boolean soname 'images.so'; create function image_rename returns boolean soname 'images.so'; create function image_md5sum returns string soname 'images.so'; create function image_move returns string soname 'images.so';
卸載
drop function image_check; drop function image_remove; drop function image_rename; drop function image_md5sum; drop function image_move;
插入圖片流程,上傳圖片後,通過插件檢查圖片是否正確上傳,然後插入記錄
begin; IF image_check('/path/to/images.jpg') THEN insert into images(product_id,thumbnail,original) values(1000,'thumbnail/path/to/images.jpg','original/path/to/images.jpg'); commit; ELSE image_remove('/path/to/images.jpg'); END IF rollback;
刪除商品採用image_move 方案,當出現異常rollback後還可以還原被刪除的圖片
begin; IF image_check('/path/to/images.jpg') THEN select thumbnail,original into @thumbnail,@original from images where id='1000' for delete; delete from images where id='1000'; select image_move(@thumbnail,'recycle/path/to/'); select image_move(@original,'recycle/path/to/'); commit; END IF rollback; select image_move('recycle/path/to/images.jpg','path/to/images.jpg');
我們可以使用EVENT定時刪除資源回收筒內的圖片
image_remove('recycle/path/to/images.jpg');
通過觸發器更能保證數據完整性
1. insert 觸發器的任務: 插入記錄的時候通過image_check檢查圖片是否正常上傳,如果非沒有上傳,數據插入失敗。 2. delete 觸發器的任務: 檢查刪除記錄的時候,首先去刪除圖片,刪除成功再刪除該記錄。
觸發器進一步優化
1. insert 觸發器的任務: 插入記錄的時候通過image_check檢查圖片是否正常上傳,如果非沒有上傳,數據插入失敗。如果上傳成功再做image_md5sum 進行校驗100% 正確後插入記錄 2. delete 觸發器的任務: 檢查刪除記錄的時候,首先去改圖片檔案名,然後刪除該記錄,最後刪除圖片,刪除成功。如果中間環境失敗 記錄會rollback,圖片會在次修改檔案名改回來。100% 保險