mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-10 06:46:04 +08:00
refactor(region): base_city_adjacent 改用 MyBatis-Plus 管理并清空升级脚本
CityAdjacent 实体补 @TableName/@TableId(id bigserial DB 自增), Mapper 继承 MPJBaseMapper, 新增 CityAdjacentManager(BaseManager), 删除裸 @Select SQL; 同步清空 update-tables.sql 升级脚本。
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
-- ========================================
|
||||
-- adapay_direct_key_config 直连密钥配置结构调整
|
||||
-- 开发阶段: Adapay 商户身份由 app_id + apiKey + RSA 私钥承载
|
||||
-- 无需独立商户号字段, 移除 merchant_no; 新增 sandbox 沙箱环境列与唯一索引
|
||||
-- ========================================
|
||||
|
||||
-- 1. 删除 Adapay 商户号列(身份由 app_id 承载; 该列旧版仅存商户身份快照, 直接删除)
|
||||
ALTER TABLE "public"."adapay_direct_key_config" DROP COLUMN IF EXISTS "merchant_no";
|
||||
|
||||
-- 2. 新增沙箱环境列(默认非沙箱, 双环境并存: 同一通道商户同一环境密钥唯一)
|
||||
ALTER TABLE "public"."adapay_direct_key_config" ADD COLUMN IF NOT EXISTS "sandbox" bool DEFAULT false;
|
||||
COMMENT ON COLUMN "public"."adapay_direct_key_config"."sandbox" IS '是否沙箱环境';
|
||||
|
||||
-- 3. 唯一索引: 同一通道商户同一环境密钥唯一(存量数据存在重复时建索引会失败, 需先清理)
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "uk_adapay_direct_key_config_sandbox" ON "public"."adapay_direct_key_config" USING btree (
|
||||
"channel_mch_no" "pg_catalog"."text_ops" ASC NULLS LAST,
|
||||
"sandbox" "pg_catalog"."bool_ops" ASC NULLS LAST
|
||||
) WHERE deleted = false;
|
||||
COMMENT ON INDEX "public"."uk_adapay_direct_key_config_sandbox" IS '同一通道商户同一环境密钥唯一';
|
||||
|
||||
-- ===== pay_trade 增加支付通道冗余字段 =====
|
||||
-- 冗余自容器 product→channel, 用于按接入通道维度看资金/报表免 JOIN; 与 pay_transfer_trade 口径对齐
|
||||
ALTER TABLE "public"."pay_trade" ADD COLUMN "channel" varchar(32) COLLATE "pg_catalog"."default";
|
||||
COMMENT ON COLUMN "public"."pay_trade"."channel" IS '支付通道(冗余自容器 product→channel; 创建即终值; 权威在容器 channel)';
|
||||
|
||||
-- 存量数据回填: 从业务容器反向填充 channel
|
||||
-- 普通支付容器(normal)
|
||||
UPDATE "public"."pay_trade" t
|
||||
SET "channel" = c."channel"
|
||||
FROM "public"."pay_normal_order" c
|
||||
WHERE t."container_id" = c."id"
|
||||
AND t."trade_type" = 'normal'
|
||||
AND t."channel" IS NULL;
|
||||
|
||||
-- 网关支付容器(gateway)
|
||||
UPDATE "public"."pay_trade" t
|
||||
SET "channel" = c."channel"
|
||||
FROM "public"."pay_gateway_order" c
|
||||
WHERE t."container_id" = c."id"
|
||||
AND t."trade_type" = 'gateway'
|
||||
AND t."channel" IS NULL;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package cn.daxpay.open.platform.system.dao.region;
|
||||
|
||||
import cn.daxpay.open.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.daxpay.open.platform.system.entity.region.CityAdjacent;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/// # 城市接壤关系
|
||||
///
|
||||
/// 纯关系表(无审计列), 仅供地理围栏 balanced 策略邻市容错查询;
|
||||
/// 数据由 update-datas.sql 脚本机器生成导入, 运行期仅提供读取能力。
|
||||
@Repository
|
||||
public class CityAdjacentManager extends BaseManager<CityAdjacentMapper, CityAdjacent> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package cn.daxpay.open.platform.system.dao.region;
|
||||
|
||||
import cn.daxpay.open.platform.system.entity.region.CityAdjacent;
|
||||
import com.github.yulichang.base.MPJBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/// # 城市接壤关系
|
||||
///
|
||||
/// 纯关系表(无审计列), 仅供地理围栏 balanced 策略邻市容错查询。
|
||||
@Mapper
|
||||
public interface CityAdjacentMapper extends MPJBaseMapper<CityAdjacent> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package cn.daxpay.open.platform.system.entity.region;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/// # 城市接壤关系
|
||||
///
|
||||
/// 纯关系载体, 供地理围栏 balanced 策略邻市容错查询。
|
||||
/// 该表为机器生成的纯导入型字典表(约2000行静态数据, 双向存储), id 用 [IdType#AUTO] 走 DB 自增(bigserial),
|
||||
/// 不走应用层雪花; 无审计列。
|
||||
@Data
|
||||
@TableName("base_city_adjacent")
|
||||
public class CityAdjacent {
|
||||
|
||||
/// 主键ID(DB 自增, 纯关系表数据导入专用)
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/// 城市编码
|
||||
private String cityCode;
|
||||
|
||||
/// 相邻城市编码
|
||||
private String adjacentCityCode;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package cn.daxpay.open.platform.system.service.region;
|
||||
|
||||
import cn.daxpay.open.platform.system.dao.region.CityAdjacentManager;
|
||||
import cn.daxpay.open.platform.system.entity.region.CityAdjacent;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/// # 城市接壤关系服务
|
||||
///
|
||||
/// 启动后首次访问时一次性把全量接壤关系载入内存(约千级行, 静态数据), 构建城市编码 → 邻市编码集合的多重映射,
|
||||
/// 供地理围栏 balanced 策略查询邻市。行政数据稳定, 无需运行期失效。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ChinaRegionAdjacencyService {
|
||||
|
||||
private final CityAdjacentManager cityAdjacentManager;
|
||||
|
||||
/// 接壤关系多重映射(惰性加载, 一经加载不再变更)
|
||||
private volatile Map<String, Set<String>> adjacencyMap;
|
||||
|
||||
/// 查询指定城市的所有接壤邻市编码
|
||||
///
|
||||
/// @param cityCode 城市编码(base_city.code, 4位)
|
||||
/// @return 邻市编码集合, 无记录返回空集
|
||||
public Set<String> findAdjacentCityCodes(String cityCode) {
|
||||
if (StrUtil.isBlank(cityCode)) {
|
||||
return Set.of();
|
||||
}
|
||||
return getAdjacencyMap().getOrDefault(cityCode, Set.of());
|
||||
}
|
||||
|
||||
/// 惰性加载全量接壤关系并构建多重映射(双重检查锁定)
|
||||
private Map<String, Set<String>> getAdjacencyMap() {
|
||||
Map<String, Set<String>> local = this.adjacencyMap;
|
||||
if (local != null) {
|
||||
return local;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (this.adjacencyMap != null) {
|
||||
return this.adjacencyMap;
|
||||
}
|
||||
long start = System.currentTimeMillis();
|
||||
Map<String, Set<String>> map = new HashMap<>();
|
||||
for (CityAdjacent row : cityAdjacentManager.findAll()) {
|
||||
// 双向插入: 数据源可能只存单方向(a,b), 内存映射同时建 a→b 与 b→a,
|
||||
// 使 findAdjacentCityCodes(cityCode) 对任意一端查询都返回完整邻市集合
|
||||
map.computeIfAbsent(row.getCityCode(), k -> new HashSet<>()).add(row.getAdjacentCityCode());
|
||||
map.computeIfAbsent(row.getAdjacentCityCode(), k -> new HashSet<>()).add(row.getCityCode());
|
||||
}
|
||||
this.adjacencyMap = map;
|
||||
log.info("城市接壤关系载入完成: {} 条邻接记录, {} 个城市, 耗时 {}ms",
|
||||
map.values().stream().mapToInt(Set::size).sum(),
|
||||
map.size(), System.currentTimeMillis() - start);
|
||||
return map;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user