From 4b91241e4b5ce01e3c958c797c055c4f49df032c Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期四, 04 六月 2026 15:53:50 +0800
Subject: [PATCH] feat(database): 添加附件数据迁移脚本从common_file到storage_blob_storage_attachment
---
doc/update_blob_file.sh | 32 ++++
doc/20260604_common_file迁移到storage_blob_storage_attachment.sql | 283 ++++++++++++++++++++++++++++++++++++++++
doc/update_file_size.sh | 49 +++++++
3 files changed, 364 insertions(+), 0 deletions(-)
diff --git "a/doc/20260604_common_file\350\277\201\347\247\273\345\210\260storage_blob_storage_attachment.sql" "b/doc/20260604_common_file\350\277\201\347\247\273\345\210\260storage_blob_storage_attachment.sql"
new file mode 100644
index 0000000..569b72c
--- /dev/null
+++ "b/doc/20260604_common_file\350\277\201\347\247\273\345\210\260storage_blob_storage_attachment.sql"
@@ -0,0 +1,283 @@
+-- ============================================================
+-- 闄勪欢鏁版嵁杩佺Щ鑴氭湰锛氫粠 common_file 杩佺Щ鍒� storage_blob + storage_attachment
+-- 鎵ц鍓嶈澶囦唤鏁版嵁锛�
+-- ============================================================
+
+-- 璇存槑锛�
+-- 1. common_file 琛細鏃ч檮浠惰〃锛屽寘鍚枃浠朵俊鎭�
+-- 2. storage_blob 琛細鏂版枃浠跺疄浣撹〃锛屽瓨鍌ㄦ枃浠跺厓淇℃伅
+-- 3. storage_attachment 琛細鏂伴檮浠跺叧鑱旇〃锛屽叧鑱斾笟鍔¤褰曚笌鏂囦欢
+
+-- 鏃ц〃瀛楁璇存槑锛�
+-- common_file.id - 涓婚敭ID
+-- common_file.common_id - 鍏宠仈涓氬姟ID
+-- common_file.name - 鏂囦欢鍚嶇О
+-- common_file.url - 鏂囦欢璺緞
+-- common_file.type - 涓氬姟绫诲瀷锛堟暣鏁版灇涓撅級
+-- common_file.file_size - 鏂囦欢澶у皬
+-- common_file.create_time, update_time, create_user, dept_id
+
+-- 鏂拌〃瀛楁璇存槑锛�
+-- storage_blob.id - 涓婚敭ID
+-- storage_blob.resource_key - 璧勬簮鍞竴鏍囪瘑锛堝彲鐢ㄥ師ID鎴朥UID锛�
+-- storage_blob.content_type - MIME绫诲瀷锛堥渶鏍规嵁鏂囦欢鎵╁睍鍚嶆帹鏂級
+-- storage_blob.original_filename- 鍘熷鏂囦欢鍚�
+-- storage_blob.uid_filename - 鍞竴鏂囦欢鍚嶏紙鍙敤鍘焠ame鎴栫敓鎴愶級
+-- storage_blob.byte_size - 鏂囦欢澶у皬
+-- storage_blob.path - 鏂囦欢璺緞
+
+-- storage_attachment.id - 涓婚敭ID
+-- storage_attachment.record_type- 璁板綍绫诲瀷锛堝瓧绗︿覆鏋氫妇锛�
+-- storage_attachment.record_id - 鍏宠仈涓氬姟ID
+-- storage_attachment.application- 鏂囦欢鐢ㄩ�旓紙榛樿 'file'锛�
+-- storage_attachment.storage_blob_id - 鍏宠仈 storage_blob.id
+-- storage_attachment.deleted - 閫昏緫鍒犻櫎鏍囪
+-- storage_attachment.create_time, update_time
+
+-- ============================================================
+-- 绫诲瀷鏄犲皠锛氭棫 type(int) -> 鏂� record_type(string)
+-- 鏍规嵁 FileNameType 鏋氫妇瀹氫箟鏄犲皠鍏崇郴
+-- ============================================================
+
+-- 鏃х被鍨嬫灇涓惧�硷細
+-- 1 = SALE (閿�鍞�)
+-- 2 = PURCHASE (閲囪喘)
+-- 3 = INVOICE (鍙戠エ)
+-- 4 = PURCHASELEDGER (閲囪喘鍙拌处)
+-- 5 = MEASURING (璁¢噺鍣ㄥ叿鍙拌处)
+-- 6 = MEASURINGRecord (璁¢噺鍣ㄥ叿鍙拌处璁板綍)
+-- 7 = ApproveNode (鍗忓悓瀹℃壒鑺傜偣瀹℃牳)
+-- 8 = ApproveProcess (鍗忓悓瀹℃壒涓绘暟鎹�)
+-- 9 = SHIP (鍙戣揣鍙拌处)
+-- 10 = INSPECTION_PRODUCTION_BEFORE (鐢熶骇鍓嶅贰妫�)
+-- 11 = INSPECTION_PRODUCTION_AFTER (鐢熶骇鍚庡贰妫�)
+-- 12 = INSPECTION (宸℃)
+-- 13 = APP
+
+-- 鏂扮被鍨嬪搴旂殑 record_type 瀛楃涓诧紙鏍规嵁 RecordTypeEnum 鎺ㄦ柇锛夛細
+-- 1 -> 'sales_ledger'
+-- 2 -> 'purchase_ledger'
+-- 3 -> 'invoice_ledger'
+-- 4 -> 'purchase_ledger_file'
+-- 5 -> 'measuring_instrument_ledger'
+-- 6 -> 'measuring_instrument_ledger_record'
+-- 7 -> 'approve_node'
+-- 8 -> 'approve_process'
+-- 9 -> 'shipping_info'
+-- 10 -> 'inspection_task'
+-- 11 -> 'inspection_task'
+-- 12 -> 'inspection_task'
+-- 13 -> 'common_file'锛堥�氱敤绫诲瀷鍏滃簳锛�
+
+-- ============================================================
+-- 姝ラ1锛氳縼绉绘枃浠舵暟鎹埌 storage_blob
+-- 娉ㄦ剰锛歜yte_size 鍏堜娇鐢� common_file.file_size锛屽悗缁渶瑕佸湪鏈嶅姟鍣ㄤ笂鏇存柊瀹為檯澶у皬
+-- ============================================================
+
+INSERT INTO storage_blob (
+ resource_key,
+ content_type,
+ original_filename,
+ uid_filename,
+ byte_size,
+ path
+)
+SELECT
+ CONCAT('legacy_', cf.id) AS resource_key,
+ CASE
+ -- 鏍规嵁鏂囦欢鎵╁睍鍚嶆帹鏂� MIME 绫诲瀷
+ WHEN LOWER(cf.name) LIKE '%.jpg' OR LOWER(cf.name) LIKE '%.jpeg' THEN 'image/jpeg'
+ WHEN LOWER(cf.name) LIKE '%.png' THEN 'image/png'
+ WHEN LOWER(cf.name) LIKE '%.gif' THEN 'image/gif'
+ WHEN LOWER(cf.name) LIKE '%.bmp' THEN 'image/bmp'
+ WHEN LOWER(cf.name) LIKE '%.webp' THEN 'image/webp'
+ WHEN LOWER(cf.name) LIKE '%.pdf' THEN 'application/pdf'
+ WHEN LOWER(cf.name) LIKE '%.doc' THEN 'application/msword'
+ WHEN LOWER(cf.name) LIKE '%.docx' THEN 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ WHEN LOWER(cf.name) LIKE '%.xls' THEN 'application/vnd.ms-excel'
+ WHEN LOWER(cf.name) LIKE '%.xlsx' THEN 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ WHEN LOWER(cf.name) LIKE '%.ppt' THEN 'application/vnd.ms-powerpoint'
+ WHEN LOWER(cf.name) LIKE '%.pptx' THEN 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
+ WHEN LOWER(cf.name) LIKE '%.txt' THEN 'text/plain'
+ WHEN LOWER(cf.name) LIKE '%.zip' THEN 'application/zip'
+ WHEN LOWER(cf.name) LIKE '%.rar' THEN 'application/x-rar-compressed'
+ WHEN LOWER(cf.name) LIKE '%.mp4' THEN 'video/mp4'
+ WHEN LOWER(cf.name) LIKE '%.mp3' THEN 'audio/mpeg'
+ WHEN LOWER(cf.name) LIKE '%.xml' THEN 'application/xml'
+ ELSE 'application/octet-stream'
+ END AS content_type,
+ cf.name AS original_filename,
+ -- 浠� url 涓埅鍙栨渶鍚庣殑鏂囦欢鍚嶉儴鍒�
+ -- url 绀轰緥: /javaWork/product-inventory-management/file/prod/uploads2026-05-19/1652_1779177065596_61abcb44.jpg
+ -- 鎴彇缁撴灉: 1652_1779177065596_61abcb44.jpg
+ CASE
+ WHEN cf.url IS NOT NULL AND cf.url != '' THEN
+ SUBSTRING_INDEX(cf.url, '/', -1)
+ ELSE cf.name
+ END AS uid_filename,
+ COALESCE(cf.file_size, 0) AS byte_size,
+ cf.url AS path
+FROM common_file cf
+WHERE NOT EXISTS (
+ SELECT 1 FROM storage_blob sb WHERE sb.resource_key = CONCAT('legacy_', cf.id)
+);
+
+-- ============================================================
+-- 姝ラ1.5锛氬湪Linux鏈嶅姟鍣ㄤ笂鏇存柊瀹為檯鏂囦欢澶у皬
+-- 鐩存帴澶嶅埗浠ヤ笅鍐呭鍒版湇鍔″櫒鎵ц
+-- ============================================================
+
+-- 鍦ㄦ湇鍔″櫒涓婃墽琛屼互涓嬪懡浠ゅ垱寤鸿剼鏈細
+-- cat > update_blob_file.sh << 'EOF'
+-- #!/bin/bash
+-- FILE_ROOT="/javaWork/product-inventory-management/file/prod"
+-- OUTPUT_SQL="update_blob_file_size.sql"
+-- DB_USER="root"
+-- DB_PASS="xd@123456.."
+-- DB_NAME="product_inventory_management"
+-- echo "寮�濮嬫壂鎻忕洰褰�: $FILE_ROOT"
+-- echo "-- 鏇存柊鏂囦欢澶у皬 SQL" > "$OUTPUT_SQL"
+-- find "$FILE_ROOT" -type f | while read filepath; do
+-- filesize=$(stat -c%s "$filepath" 2>/dev/null || echo "0")
+-- filename=$(basename "$filepath")
+-- filename_escaped=$(echo "$filename" | sed "s/'/''/g")
+-- echo "UPDATE storage_blob SET byte_size = $filesize WHERE uid_filename = '$filename_escaped';" >> "$OUTPUT_SQL"
+-- done
+-- echo "SQL鏂囦欢宸茬敓鎴�: $OUTPUT_SQL"
+-- docker exec -i mysql mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$OUTPUT_SQL"
+-- echo "鏇存柊瀹屾垚!"
+-- EOF
+--
+-- 鐒跺悗鎵ц锛�
+-- chmod +x update_blob_file.sh && ./update_blob_file.sh
+
+-- ============================================================
+-- 姝ラ2锛氳縼绉婚檮浠跺叧鑱旀暟鎹埌 storage_attachment
+-- ============================================================
+
+INSERT INTO storage_attachment (
+ create_time,
+ update_time,
+ deleted,
+ record_type,
+ record_id,
+ application,
+ storage_blob_id
+)
+SELECT
+ cf.create_time,
+ cf.update_time,
+ 0 AS deleted,
+ CASE cf.type
+ WHEN 1 THEN 'sales_ledger'
+ WHEN 2 THEN 'purchase_ledger'
+ WHEN 3 THEN 'invoice_ledger'
+ WHEN 4 THEN 'purchase_ledger_file'
+ WHEN 5 THEN 'measuring_instrument_ledger'
+ WHEN 6 THEN 'measuring_instrument_ledger_record'
+ WHEN 7 THEN 'approve_node'
+ WHEN 8 THEN 'approve_process'
+ WHEN 9 THEN 'shipping_info'
+ WHEN 10 THEN 'inspection_task'
+ WHEN 11 THEN 'inspection_task'
+ WHEN 12 THEN 'inspection_task'
+ WHEN 13 THEN 'common_file'
+ ELSE 'common_file'
+ END AS record_type,
+ cf.common_id AS record_id,
+ 'file' AS application,
+ sb.id AS storage_blob_id
+FROM common_file cf
+INNER JOIN storage_blob sb ON sb.resource_key = CONCAT('legacy_', cf.id)
+WHERE NOT EXISTS (
+ SELECT 1 FROM storage_attachment sa
+ WHERE sa.storage_blob_id = sb.id
+);
+
+-- ============================================================
+-- 姝ラ3锛氶獙璇佽縼绉荤粨鏋�
+-- ============================================================
+
+-- 妫�鏌ヨ縼绉绘暟閲忔槸鍚︿竴鑷�
+SELECT
+ 'common_file 鍘熷璁板綍鏁�' AS description,
+ COUNT(*) AS count
+FROM common_file
+UNION ALL
+SELECT
+ 'storage_blob 杩佺Щ璁板綍鏁�' AS description,
+ COUNT(*) AS count
+FROM storage_blob
+WHERE resource_key LIKE 'legacy_%'
+UNION ALL
+SELECT
+ 'storage_attachment 杩佺Щ璁板綍鏁�' AS description,
+ COUNT(*) AS count
+FROM storage_attachment sa
+WHERE EXISTS (
+ SELECT 1 FROM storage_blob sb
+ WHERE sb.id = sa.storage_blob_id
+ AND sb.resource_key LIKE 'legacy_%'
+);
+
+-- 鎸夌被鍨嬬粺璁¤縼绉绘暟閲�
+SELECT
+ cf.type AS old_type,
+ CASE cf.type
+ WHEN 1 THEN 'sales_ledger'
+ WHEN 2 THEN 'purchase_ledger'
+ WHEN 3 THEN 'invoice_ledger'
+ WHEN 4 THEN 'purchase_ledger_file'
+ WHEN 5 THEN 'measuring_instrument_ledger'
+ WHEN 6 THEN 'measuring_instrument_ledger_record'
+ WHEN 7 THEN 'approve_node'
+ WHEN 8 THEN 'approve_process'
+ WHEN 9 THEN 'shipping_info'
+ WHEN 10 THEN 'inspection_task'
+ WHEN 11 THEN 'inspection_task'
+ WHEN 12 THEN 'inspection_task'
+ WHEN 13 THEN 'common_file'
+ ELSE 'unknown'
+ END AS new_record_type,
+ COUNT(*) AS count
+FROM common_file cf
+GROUP BY cf.type
+ORDER BY cf.type;
+
+-- ============================================================
+-- 姝ラ4锛氭暟鎹牎楠岋紙鎵ц鍓嶆鏌ユ槸鍚︽湁寮傚父鏁版嵁锛�
+-- ============================================================
+
+-- 妫�鏌ユ槸鍚︽湁 common_id 涓虹┖鐨勮褰�
+SELECT COUNT(*) AS 'common_id涓虹┖鐨勮褰曟暟' FROM common_file WHERE common_id IS NULL;
+
+-- 妫�鏌ユ槸鍚︽湁 name 涓虹┖鐨勮褰�
+SELECT COUNT(*) AS 'name涓虹┖鐨勮褰曟暟' FROM common_file WHERE name IS NULL OR name = '';
+
+-- 妫�鏌ユ槸鍚︽湁 url 涓虹┖鐨勮褰�
+SELECT COUNT(*) AS 'url涓虹┖鐨勮褰曟暟' FROM common_file WHERE url IS NULL OR url = '';
+
+-- ============================================================
+-- 姝ラ5锛氳縼绉诲畬鎴愬悗鐨勬竻鐞嗭紙璋ㄦ厧鎵ц锛佸缓璁厛澶囦唤鏁版嵁锛�
+-- ============================================================
+
+-- 澶囦唤 common_file 琛紙鍙�夛級
+-- CREATE TABLE common_file_backup AS SELECT * FROM common_file;
+
+-- 娓呯┖ common_file 琛紙纭杩佺Щ鏃犺鍚庢墽琛岋級
+-- TRUNCATE TABLE common_file;
+
+-- 鎴栬�呭垹闄ゅ凡杩佺Щ鐨勮褰�
+-- DELETE FROM common_file WHERE EXISTS (
+-- SELECT 1 FROM storage_blob sb
+-- WHERE sb.resource_key = CONCAT('legacy_', common_file.id)
+-- );
+
+-- ============================================================
+-- 娉ㄦ剰浜嬮」锛�
+-- 1. 鎵ц鍓嶅姟蹇呭浠� common_file 琛ㄦ暟鎹�
+-- 2. 寤鸿鍦ㄦ祴璇曠幆澧冨厛楠岃瘉杩佺Щ鑴氭湰鐨勬纭��
+-- 3. 杩佺Щ瀹屾垚鍚庯紝妫�鏌ユ枃浠舵槸鍚﹁兘姝e父璁块棶
+-- 4. 纭涓氬姟鍔熻兘姝e父鍚庯紝鍐嶈�冭檻娓呯悊鏃ф暟鎹�
+-- 5. resource_key 浣跨敤 'legacy_' + 鍘烮D 鐨勬牸寮忥紝渚夸簬杩芥函鍜屽幓閲�
+-- ============================================================
\ No newline at end of file
diff --git a/doc/update_blob_file.sh b/doc/update_blob_file.sh
new file mode 100644
index 0000000..4da5849
--- /dev/null
+++ b/doc/update_blob_file.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+# 鏂囦欢瀛樺偍鏍圭洰褰�
+FILE_ROOT="/javaWork/product-inventory-management/file/prod"
+
+# 杈撳嚭SQL鏂囦欢鍚�
+OUTPUT_SQL="update_blob_file_size.sql"
+
+# 鏁版嵁搴撻厤缃�
+DB_USER="root"
+DB_PASS="xd@123456.."
+DB_NAME="product_inventory_management"
+
+echo "寮�濮嬫壂鎻忕洰褰�: $FILE_ROOT"
+echo "-- 鏇存柊鏂囦欢澶у皬 SQL" > "$OUTPUT_SQL"
+echo "-- 鐢熸垚鏃堕棿: $(date '+%Y-%m-%d %H:%M:%S')" >> "$OUTPUT_SQL"
+echo "" >> "$OUTPUT_SQL"
+
+# 鎵弿鐩綍涓嬫墍鏈夋枃浠跺苟鐢熸垚鏇存柊SQL
+find "$FILE_ROOT" -type f | while read filepath; do
+ filesize=$(stat -c%s "$filepath" 2>/dev/null || echo "0")
+ filename=$(basename "$filepath")
+ filename_escaped=$(echo "$filename" | sed "s/'/''/g")
+ echo "UPDATE storage_blob SET byte_size = $filesize WHERE uid_filename = '$filename_escaped';" >> "$OUTPUT_SQL"
+done
+
+echo "SQL鏂囦欢宸茬敓鎴�: $OUTPUT_SQL"
+echo "姝e湪鎵цSQL鏇存柊..."
+
+docker exec -i mysql mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$OUTPUT_SQL"
+
+echo "鏇存柊瀹屾垚!"
\ No newline at end of file
diff --git a/doc/update_file_size.sh b/doc/update_file_size.sh
new file mode 100644
index 0000000..254937c
--- /dev/null
+++ b/doc/update_file_size.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# ============================================================
+# 鏇存柊 storage_blob 琛ㄧ殑鏂囦欢澶у皬瀛楁
+# 鎵弿鏂囦欢鐩綍鑾峰彇瀹為檯鏂囦欢澶у皬锛岀敓鎴愭洿鏂癝QL
+# ============================================================
+
+# 鏂囦欢瀛樺偍鏍圭洰褰曪紙鏍规嵁瀹為檯璺緞淇敼锛�
+FILE_ROOT="/javaWork/product-inventory-management/file/prod"
+
+# 杈撳嚭SQL鏂囦欢鍚�
+OUTPUT_SQL="update_blob_file_size.sql"
+
+echo "寮�濮嬫壂鎻忕洰褰�: $FILE_ROOT"
+echo "-- 鏇存柊鏂囦欢澶у皬 SQL" > "$OUTPUT_SQL"
+echo "-- 鐢熸垚鏃堕棿: $(date '+%Y-%m-%d %H:%M:%S')" >> "$OUTPUT_SQL"
+echo "" >> "$OUTPUT_SQL"
+
+# 缁熻璁℃暟
+count=0
+
+# 鎵弿鐩綍涓嬫墍鏈夋枃浠跺苟鐢熸垚鏇存柊SQL
+find "$FILE_ROOT" -type f | while read filepath; do
+ # 鑾峰彇鏂囦欢澶у皬锛堝瓧鑺傦級
+ filesize=$(stat -c%s "$filepath" 2>/dev/null || echo "0")
+
+ # 鑾峰彇鏂囦欢鍚嶏紙鏈�鍚庝竴娈佃矾寰勶級
+ filename=$(basename "$filepath")
+
+ # 杞箟鏂囦欢鍚嶄腑鐨勫崟寮曞彿锛圫QL璇硶瑕佹眰锛�
+ filename_escaped=$(echo "$filename" | sed "s/'/''/g")
+
+ # 鐢熸垚鏇存柊SQL
+ echo "UPDATE storage_blob SET byte_size = $filesize WHERE uid_filename = '$filename_escaped';" >> "$OUTPUT_SQL"
+
+ # 璁℃暟锛堝瓙shell涓棤娉曚紶閫掞紝浠呯敤浜庢樉绀鸿繘搴︼級
+ echo "宸插鐞�: $filename ($filesize bytes)"
+done
+
+echo ""
+echo "=========================================="
+echo "SQL鏂囦欢宸茬敓鎴�: $OUTPUT_SQL"
+echo "=========================================="
+echo ""
+echo "鎵ц鏂规硶:"
+echo " mysql -u鐢ㄦ埛鍚� -p瀵嗙爜 鏁版嵁搴撳悕 < $OUTPUT_SQL"
+echo ""
+echo "鎴栬�呭厛妫�鏌QL鍐呭:"
+echo " cat $OUTPUT_SQL"
\ No newline at end of file
--
Gitblit v1.9.3