feat(device): 应用图标改存云存储并修复版本号唯一键冲突
This commit is contained in:
1 parent
72770b226a
commit
cbf4f37b94
15 files changed
+526
-133
No files matched your search
+9
-4
@@ -11,11 +11,16 @@
|
||||
-- 约定:
|
||||
-- - 同一 package_name 下 status=1(当前生效)的记录有且仅有一条
|
||||
-- - 历史版本(status=0)仅用于展示与选取锁定,不物理删除
|
||||
-- - 图标文件按 {md5}.{ext} 内容寻址存储,访问路径由后端拼接为 /static/app_icon/{md5}.{ext}
|
||||
-- (该前缀与 WebMvcConfig 注册的静态资源映射一致;内容变更必然导致文件名变更,故可长缓存)
|
||||
-- - 版本号生成规则(必须严格遵守):
|
||||
-- version = 该 package_name 下所有记录的 MAX(version) + 1
|
||||
-- 统计范围必须包含 is_deleted=1 的逻辑删除行,版本号只增不减、永不复用。
|
||||
-- 原因:uk_package_version 不包含 is_deleted,若用「当前生效版本+1」或从 1 重新开始,
|
||||
-- 当前生效记录被删除/缺失时会与残留版本号撞唯一键(Duplicate entry '包名-1')。
|
||||
-- - 图标文件统一存入 storage.type 配置的存储(当前为阿里云 OSS),icon_url 为可直接访问的完整 URL
|
||||
--
|
||||
-- 部署规范:不直连库,由 DBA 执行;先 DROP 再 CREATE 确保结构与实体完全一致
|
||||
-- (DROP 会清空历史图标数据,可由设备端重新上报补齐)。
|
||||
-- 存量库修复:不重建表的场景,先执行 sql/app_icon_version_repair.sql 清理脏数据。
|
||||
-- =============================================================================
|
||||
|
||||
DROP TABLE IF EXISTS `app_icon`;
|
||||
@@ -25,11 +30,11 @@ CREATE TABLE `app_icon`
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`package_name` VARCHAR(255) NOT NULL COMMENT '应用包名(全局唯一维度,同包名多版本共存)',
|
||||
`app_name` VARCHAR(128) DEFAULT NULL COMMENT '应用名称(上报时的展示名,可为空;新版本上报时刷新)',
|
||||
`icon_url` VARCHAR(500) NOT NULL COMMENT '图标访问地址(相对路径,如 /static/app_icon/{md5}.png)',
|
||||
`icon_url` VARCHAR(500) NOT NULL COMMENT '图标访问地址(存储服务返回的完整 URL)',
|
||||
`icon_md5` VARCHAR(64) DEFAULT NULL COMMENT '图标文件MD5(内容指纹,用于去重与换图标检测)',
|
||||
`icon_sha1` VARCHAR(64) DEFAULT NULL COMMENT '图标文件SHA1',
|
||||
`icon_sha256` VARCHAR(64) DEFAULT NULL COMMENT '图标文件SHA256',
|
||||
`version` INT NOT NULL DEFAULT 1 COMMENT '版本号(同包名内自增,从1开始)',
|
||||
`version` INT NOT NULL DEFAULT 1 COMMENT '版本号(同包名内自增,取所有记录含逻辑删除的 MAX(version)+1,不复用)',
|
||||
`status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态(1当前生效 0历史版本)',
|
||||
`locked` TINYINT NOT NULL DEFAULT 0 COMMENT '是否锁定(0未锁定 1已锁定,锁定后不可上传覆盖)',
|
||||
`source` VARCHAR(20) NOT NULL DEFAULT 'device' COMMENT '图标来源(device设备端上报 admin管理端上传)',
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
-- =============================================================================
|
||||
-- app_icon 版本号 / 生效状态 存量数据修复脚本
|
||||
--
|
||||
-- 背景:
|
||||
-- 旧逻辑用「当前生效版本 + 1」生成版本号,无当前生效记录时固定用 1;
|
||||
-- 而删除是逻辑删除(is_deleted=1),且唯一索引 uk_package_version(package_name, version)
|
||||
-- 不包含 is_deleted。当前生效记录被删除或缺失时,再次上传就会撞唯一键:
|
||||
-- Duplicate entry 'com_alibaba_android_rimet-1' for key 'app_icon.uk_package_version'
|
||||
--
|
||||
-- 新逻辑:
|
||||
-- version = 该 package_name 下所有记录(含 is_deleted=1)的 MAX(version) + 1,
|
||||
-- 版本号只增不减、永不复用;上传 / 锁定已按包名加锁并置于同一事务内。
|
||||
--
|
||||
-- 使用说明:
|
||||
-- 1. 本脚本仅用于「已在运行、不重建表」的库;全新部署执行 app_icon.sql 即可。
|
||||
-- 2. 由 DBA 在业务低峰期单独执行,执行前请备份 app_icon 表。
|
||||
-- 3. 诊断语句(第 1 ~ 3 段)先执行确认现状,再执行修复语句(第 4 ~ 5 段)。
|
||||
-- =============================================================================
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 1. 诊断:同一包名存在多条 status=1(会导致 one() 抛 TooManyResultsException)
|
||||
-- -----------------------------------------------------------------------------
|
||||
SELECT package_name, COUNT(*) AS active_cnt
|
||||
FROM app_icon
|
||||
WHERE is_deleted = 0
|
||||
AND status = 1
|
||||
GROUP BY package_name
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 2. 诊断:同一包名有未删除记录,但没有任何 status=1(上传会走「无当前版本」分支)
|
||||
-- -----------------------------------------------------------------------------
|
||||
SELECT package_name, COUNT(*) AS alive_cnt, MAX(version) AS max_version
|
||||
FROM app_icon
|
||||
WHERE is_deleted = 0
|
||||
GROUP BY package_name
|
||||
HAVING SUM(status = 1) = 0;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 3. 诊断:查看具体包名的版本与删除残留
|
||||
-- -----------------------------------------------------------------------------
|
||||
SELECT id, package_name, version, status, locked, is_deleted, update_time
|
||||
FROM app_icon
|
||||
WHERE package_name = 'com_alibaba_android_rimet'
|
||||
ORDER BY is_deleted, version;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 4. 修复多条 status=1:保留 version 最大的一条为当前生效,其余置为历史
|
||||
-- -----------------------------------------------------------------------------
|
||||
UPDATE app_icon a
|
||||
JOIN (SELECT package_name, MAX(version) AS max_version
|
||||
FROM app_icon
|
||||
WHERE is_deleted = 0
|
||||
AND status = 1
|
||||
GROUP BY package_name) t
|
||||
ON a.package_name = t.package_name
|
||||
SET a.status = 0,
|
||||
a.update_time = NOW()
|
||||
WHERE a.is_deleted = 0
|
||||
AND a.status = 1
|
||||
AND a.version < t.max_version;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 5. 修复无 status=1:把未删除记录里版本号最大的一条置为当前生效
|
||||
-- -----------------------------------------------------------------------------
|
||||
UPDATE app_icon a
|
||||
JOIN (SELECT package_name, MAX(version) AS max_version
|
||||
FROM app_icon
|
||||
WHERE is_deleted = 0
|
||||
GROUP BY package_name
|
||||
HAVING SUM(status = 1) = 0) t
|
||||
ON a.package_name = t.package_name
|
||||
AND a.version = t.max_version
|
||||
SET a.status = 1,
|
||||
a.update_time = NOW()
|
||||
WHERE a.is_deleted = 0;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 6. 复核:两条诊断语句均应返回空结果集
|
||||
-- -----------------------------------------------------------------------------
|
||||
SELECT package_name, COUNT(*) AS active_cnt
|
||||
FROM app_icon
|
||||
WHERE is_deleted = 0
|
||||
AND status = 1
|
||||
GROUP BY package_name
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
SELECT package_name, COUNT(*) AS alive_cnt
|
||||
FROM app_icon
|
||||
WHERE is_deleted = 0
|
||||
GROUP BY package_name
|
||||
HAVING SUM(status = 1) = 0;
|
||||
Reference in new issue
Block a user