1
banlifeather4 2021-11-24 09:14:15 +08:00
经验来看的话, 不管是单体服务还是分布式服务, 建议 ID 都设计成全局唯一的,增加不了多少成本;
但是不这么搞的话,如果一旦做分表分库等,涉及的数据清洗的工作量应该够你加班 2 个月的( 1 个月,2.am 下班) |
2
allenzhangSB 2021-11-24 09:17:03 +08:00
你这个需求, 最简单实现可以用 redis 的 incr
|
3
bglucas 2021-11-24 09:18:33 +08:00
看起来像是分布式唯一 ID 生成问题?可以参考下 snowflake 和给予 mysql 的号段模式。
|
4
onhao 2021-11-24 09:27:06 +08:00
貌似触发器可以?但是需要警惕用了触发器后 last_insert_id() 获取不到最近插入的 ID
https://wuhao.pw/archives/241/ |
5
dk7952638 2021-11-24 09:33:47 +08:00
借楼一问,现在全局 ID 的开源方案有没有比较靠谱的,最好是可以自增的那种
|
6
jorneyr 2021-11-24 09:54:17 +08:00
全局唯一自增:
1. ID 生成服务 (只用一个服务,不要用集群,性能要高,分段获取,保证全局唯一递增,持久化到 DB) 2. 每个服务需要 ID 时使用 RPC 去 ID 生成服务实时拿取,每次只拿一个 (RPC 保证效率) snowflake 等只能是趋势递增。 |
7
gibber OP @allenzhangSB mysql 存储过程也可以调用 redis 吗?
|
8
xsm1890 2021-11-24 10:34:33 +08:00
可行。但如果只是用 mysql 的存储过程生成的话,这个点可能会成为系统的性能瓶颈。
|
9
clf 2021-11-24 10:34:41 +08:00
在 github 上好像有 snowflake 的 mysql 存储过程实现?(没写过 mysql 的存储过程)可以考虑使用 snowflake 生成的 ID 作为主键。
@dk7952638 #5 目前用的比较多的就是上面说的雪花算法,id bigint ,唯一需要注意的是后端序列化为 json 的时候需要把超过前端 number 范围的数值转为 string ,不然会精度丢失。 |
10
Bigglesworth 2021-11-24 10:40:51 +08:00
如果没有分库分表,业务也不大的话,虽然说全局 ID 啥的更好,但是还是按需来嘛,可以写个类似 sequence 的存储过程,后台程序和存储过程都可以调一下生成 ID ,生成规则你可以按月啥的自增。
|
11
yidinghe 2021-11-24 11:19:01 +08:00
参考一下这个项目:
https://github.com/yiding-he/mysql-sequence-generator 在数据库中建一个表,各个服务都可以并发的用这张表生成全局 ID ,原理也是利用 last_insert_id() |
12
jinzhongyuan 2021-11-24 14:13:47 +08:00
以前在小公司就是存储过程生成订单号
|
13
allenzhangSB 2021-11-24 14:35:13 +08:00
@gibber 没必要一定要在 MySQL 侧做吧, 代码中插入前最后一步调用下 redis 生成个序号, 插入前做好校验, 避免插入失败就可以了
|
14
uSy62nMkdH 2021-11-24 14:49:10 +08:00
你这种需求直接建一个仅有 ID 的表就行了吧,每次需要的时候 insert 并返回 ID 即可。如果有分库分表,在单调自增序列前加一个数据标识。
考虑引入中间件的话,雪花、美团 leaf ,或者 zk+redis 自建。 |
15
fengpan567 2021-11-24 15:14:21 +08:00
snowflake 不合适吗?用存储过程,分库分表的时候不就扯淡了
|
16
gibber OP @allenzhangSB 是的, 我知道利用 redis 很好做到唯一编号, 主要这个业务还有另外一个需求就是利用存储过程插入数据,所以要考虑到数据库端和程序同时并发
|
17
gibber OP @uSy62nMkdH 流水号是每月重置,你说的这种方法可以实现吗?
|
18
gavindexu 2021-11-24 20:29:18 +08:00 via iPhone
用触发器 在插入前执行一个?
|
19
5wunian 2021-11-24 21:17:17 +08:00
避免避免,之前的项目里是在创建的时候单独请求一个唯一 ID,创建的时候带上。虽然浪费了部分未提交的 ID ,但是避免了并发限制。
|
20
crclz 2021-11-25 00:39:54 +08:00
仅仅考虑楼主提出的需求,提出以下解决方案:
表 X(年月 int, 流水号 int)。例如(202111, 1) def GenerateOrderId() -> str: 年月 = 获取当前年月() num=( update 表 X set 流水号=流水号+1 returning 流水号) return 格式化(年月,num ) 如果数据库并发不够,可以流水号=流水号+10 之类的,然后服务端将生成的 id 全局缓存起来。 这样做不会错的,我司就是这样干的。 |
21
uSy62nMkdH 2021-11-25 16:18:48 +08:00
@gibber 为什么不行呢? prefix 是自定义的,suffix 按表里的 ID 递增,两个组装起来就是你要的 ID 了。
|