当前位置: 首页 > wzjs >正文

wordpress多站点批量添加下载谷歌浏览器并安装

wordpress多站点批量添加,下载谷歌浏览器并安装,企业logo图片,九江专业网站建设主键 ID VS 业务 ID 在数据库设计中,除了主键 ID,一般还需要一个具有唯一索引的业务 ID。二者承担的职责不一样,它们共同满足了我们对于 技术实现 和 业务需求 的双重目标 1. 职责分离原则 主键 ID 业务唯一标识 ID 作用 保证数据库层面…

主键 ID VS 业务 ID

在数据库设计中,除了主键 ID,一般还需要一个具有唯一索引的业务 ID。二者承担的职责不一样,它们共同满足了我们对于 技术实现业务需求 的双重目标

1. 职责分离原则

主键 ID

业务唯一标识 ID

作用

保证数据库层面的唯一性

保证业务层面的唯一性

目标

保证数据存储和关联的可靠性

满足业务规则和外部交互需求

特点

无意义、自增/随机、不可变

有具体业务含义、可读、可暴露

eg:

  1. 商品表的主键 ID 可能是 1、2、3,但商品编码(业务唯一标识)可能是00012517271821。前四位是所处的地区码,中间是随机生成的数字,最后四位是新增这个商品的用户 ID 后四位
  2. 订单表的主键 ID 可能是 1、2、3,但订单编码可能是时间戳拼上今天订单的序号:202505220012

2. 使用场景分析

场景一:防止暴露内部信息
  • 问题:直接暴露自增主键ID,可能泄露业务规模(如用户量、订单量),甚至被恶意遍历数据
  • 解决:使用无规律的业务ID(如UUID、哈希值)对外暴露,隐藏自增主键

场景二:分库分表需求
  • 问题:如果需要分库分表,主键ID就无法保证全局唯一性
  • 解决:通过业务ID实现全局唯一(雪花算法生成的分布式 ID、使用自定义序列生成器生成的 ID)

场景三:业务标识符的灵活性
  • 问题:业务唯一标识可能需要动态规则(如订单号包含日期、地区码),而自增主键无法满足
  • 解决:业务唯一标识ID按业务规则生成,主键ID保持默认策略

3. 技术实现对比

主键 ID

业务唯一标识 ID

数据类型

通常为 int/bigint(高效索引)

可能是 varchar(兼容复杂规则)

唯一性范围

表内唯一

全局唯一(跨表、跨系统)

生成方式

自增/随机

程序生成(UUID、雪花算法、业务规则拼接)

修改性

不可变(与数据生命周期绑定)

可能允许修改(如用户重设唯一用户名)

建议:

  1. 主键ID始终存在:作为数据库的“技术锚点”,用于外键关联、索引优化
  2. 业务唯一标识ID按需设计
    1. 若无需业务唯一标识,可省略
    2. 若需暴露或业务规则复杂,必加,并为其添加唯一索引
  1. 查询优化
    1. 内部关联用ID(更快)
    2. 对外接口用业务ID(更安全)

4. 何时不需要用业务 ID ?

  • 纯内部工具表,无暴露需求
  • 业务标识符可直接复用主键(如简单的配置表)

为什么需要自定义序列生成器?

前面有说过业务ID一般是具有具体业务含义的,我们需要支持根据动态规则来生成具有不同业务属性的业务ID

注意:

自定义序列生成器一般用来生成业务 ID ,但也可以用来生成主键 ID。具体实现方式是由多个维度所决定的。例如:公司觉得主键 ID 使用雪花算法生成的 64 位长整型数字比较占用内存,但是又不想新增一个具备实际业务含义的字段,那就可以选择使用自定义序列生成器生成具备业务属性的主键 ID(合二为一)

下面,我将分别实现 单体架构分布式架构 下的序列生成器。它们最大的区别在于分布式架构下的序列生成器可以保证序列在多个不同的数据库之间也不会出现重复的问题,保证全局唯一性


单体架构实现

实现单体架构的序列生成器较为简单,只要想明白两个注意点:

  1. 由于要支持动态规则,所以需要用一张表来存储不同的业务生成序列的对应规则
  2. 我们需要保证业务 ID 唯一,所以每次要记录生成的最后一次数值,确保下次生成的值具有顺序且不重复

想明白了以上两点,我们就来尝试实现吧

实现步骤:

  1. 定义一张表用来配置不同业务的序列生成规则模板
CREATE TABLE `sequence_rule` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增列',`module_id` varchar(50) NOT NULL COMMENT '模块ID',`rule` varchar(100) NOT NULL COMMENT '序列规则',`cuid` int(11) NOT NULL COMMENT '当前流水号',`pref` varchar(50) NOT NULL COMMENT '规则前缀',PRIMARY KEY (`id`),UNIQUE KEY `idx_module_id` (`module_id`)
)  COMMENT='序列规则配置';

注意:模块 ID 要单独建立唯一索引,保证唯一性

  1. 定义一张表用来记录不同序列对应生成的值
CREATE TABLE `sequence_record` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`sequence_key` varchar(64) NOT NULL COMMENT '序列编码',`sequence_value` bigint(20) DEFAULT NULL COMMENT '序列值',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='序列ID记录表';

  1. 定义入口方法 VoucherIdManager.generateIds()
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public List<String> generateIds(ModuleEnum moduleEnum, Long length) {if (moduleEnum == null ||length == null) {throw new BizException(200, "缺失必传参数");}return this.buildIds(moduleEnum, length);
}

  1. 核心逻辑为 buildIds()
/*** 构建 ID** @param moduleEnum 模块枚举* @param length 集合长度* @return List<String>*/
private List<String> buildIds(ModuleEnum moduleEnum, Long length) {List<String> ids = new ArrayList<>();// 1.获取序列规则SequenceRule sequenceRule = sequenceRuleService.getByModuleEnum(moduleEnum);String rule = sequenceRule.getRule().toUpperCase();// 2.生成 ID 前缀// ID 规则为: CO[yy][mm][dd][ID000000]  则第二步会生成 CO20230501 这一串前缀String idPref = this.generateIdPref(rule);log.info("idPref -> [{}]", idPref);// 3.生成唯一值Matcher matcher = SEQUENCE.matcher(rule);if (matcher.find()) {// 如果匹配上了,获取 0 的个数  (0 的个数就意味着要生成的随机数的长度)int zeroLength = matcher.end() - matcher.start() - 4;for (int i = 0; i < length; i++) {Long nextSequence = sequenceManager.getNextSequence(idPref);ids.add(idPref + String.format("%0" + zeroLength + "d", nextSequence));}} else {throw new BizException(200, "序列规则配置错误");}return ids;
}

  1. 定义一个类,将数据库中对应序列的属性保存到内存(此处也可替换成 Redis)
private class SequenceHolder {private String key;/*** 当前序列号,初始化是为 0*/private AtomicLong sequenceValue;/*** 数据库保存的序列号*/private long dbValue;/*** 步长,用来判断序列号是否还在给定的步长范围内*/private long step;public SequenceHolder(long step) {this.step = step;}public long nextValue() {if (sequenceValue == null) {// 初始化this.init();}long sequence = sequenceValue.incrementAndGet();if (sequence > step) {// 意味着分配给它的序列号已经用完,需要重新分配this.nextRound();return this.nextValue();} else {return dbValue + sequence;}}private synchronized void nextRound() {if (sequenceValue.get() > step) {// 重新生成下一个序列号dbValue = SequenceManager.this.nextValue(key, step) - step;sequenceValue = new AtomicLong(0);}}private synchronized void init() {if (sequenceValue != null) {return;}dbValue = SequenceManager.this.nextValue(key, step) - step;sequenceValue = new AtomicLong(0);}}

步长 step 的作用是什么?

步长的意思就是一次返回序列号的长度。例如:step=100,则会修改数据库中对应序列的可用值为当前值 + 100,意味着这段区间已经分配给了当前服务。只要 sequenceValue 没有超过这个步长,则可以安全的使用分配给它的这一段区间。如果超过了,则需要重新获取一个新的区间,此区间长度为 step

  1. 实现序列生成逻辑
/*** @Description 序列生成器* @Author Mr.Zhang* @Date 2025/5/25 19:04* @Version 1.0*/
@Slf4j
@Component
public class SequenceManager {@Autowiredprivate SequenceRecordService sequenceRecordService;private static final Map<String, SequenceHolder> holder = new HashMap<>();/*** 获取下一个序列  确保唯一性** @param identity Key* @return*/@Transactional(propagation = Propagation.NOT_SUPPORTED)public long getNextSequence(String identity) {SequenceHolder sequenceHolder = holder.get(identity);if (sequenceHolder == null) {synchronized (holder) {sequenceHolder = holder.get(identity);if (sequenceHolder == null) {sequenceHolder = new SequenceHolder(1);  // 默认为 1sequenceHolder.setKey(identity);sequenceHolder.init();holder.put(identity, sequenceHolder);}}}return sequenceHolder.nextValue();}/*** 获取下一个序列  确保唯一性** @param sequenceKey Key* @return*/private long nextValue(String sequenceKey, long step) {for (int i = 0; i < 10; i++) {SequenceRecord sequenceRecord = sequenceRecordService.querySequence(sequenceKey);int effectRow = sequenceRecordService.nextValue(sequenceRecord.getSequenceValue() + step, sequenceRecord.getSequenceValue(), sequenceKey);if (effectRow == 1) {return sequenceRecord.getSequenceValue() + step;  // 返回下一个可用值}}throw new BizException(200, "获取序列失败");}
}

单体架构的核心代码就是这些。最主要的思路其实是保证序列生成的唯一性。此实现采用步长 + 乐观锁的方式确保不同的服务拿到的是不同的序列值

单体架构实现完整代码已上传到 github 上,感兴趣的朋友可以配合我的讲解看看具体实现代码

GitHub - nowtostudeyday/sequence-generate: 序列生成器。支持单体架构和分布式架构下的序列生成。支持自定义序列前缀,保证全局唯一性

欢迎 star~~

http://www.dtcms.com/wzjs/316440.html

相关文章:

  • 平台网站建设需要什么技术谷粉搜索谷歌搜索
  • 学前心理学课程建设网站中国搜索引擎份额排行
  • com网站域名seo分析工具有哪些
  • 内蒙古网站建设公司足球比赛直播2021欧冠决赛
  • 什么叫网站建设张家界网站seo
  • 做贸易选哪家网站武汉大学人民医院官网
  • 郑州网站推广¥做下拉去118crseo实战密码
  • 有哪些做产品产业链分析的网站如何优化网页
  • 网站域名注册免费山西网页制作
  • 中企动力官方网站东莞网
  • 提升学历的重要性与意义百度热搜seo
  • 仿起点小说网站开发超级seo助手
  • 网站建设中英文表述百度关键词搜索量排行
  • 餐饮公司做网站好处搜索引擎推广文案
  • 哪个网站能帮助做试卷绍兴seo公司
  • 网站有风险提示怎么办营销推广软文
  • 网站开发报价方案自己怎么开电商平台
  • wordpress配置文件修改铁岭网站seo
  • 可以制作试卷的app关键词优化公司哪家好
  • 义乌制作网站要多少钱seo优化评论
  • 装饰公司网站房地产营销策略有哪些
  • 网站开发的主要阶段哪些网站有友情链接
  • wordpress网站很卡合肥网站推广
  • 邯郸做网站流程自助建站系统哪个好用
  • 厦门网站制作建设盘古百晋广告营销是干嘛
  • 网站数据库怎么做同步吗怎么去做网络推广
  • 网站的购物车怎么做网站交换链接友情链接的作用
  • wordpress 微信模板怎么用泰州百度关键词优化
  • 2015网站建设seo外链友情链接
  • 小县城做婚礼网站热狗seo外包