Github开源生信云平台 DEMO
这个问题在生产环境非常常见,而且不同数据库写法完全不同。
我给你一个按数据库划分的“生产级正确姿势”。
让数据库在 INSERT 时直接返回主键❌ 不要再去 select max(id)❌ 不要手动查
如果你用的是 PostgreSQL(你之前用 $1 占位符,大概率是 PG)
$1
直接用:
INSERT INTO users (nickname) VALUES ($1) RETURNING id;
Go 示例:
var id int64 err := db.QueryRowContext(ctx, "INSERT INTO users (nickname) VALUES ($1) RETURNING id", nickname, ).Scan(&id)
✅ 插入✅ 立即得到 id✅ 并发安全
这是 PG 的标准做法。
MySQL 没有 RETURNING(8.0.21+ 才开始支持部分 returning)
传统方式:
res, err := db.ExecContext(ctx, "INSERT INTO users (nickname) VALUES (?)", nickname, ) id, err := res.LastInsertId()
注意:
SELECT MAX(id) FROM users;
高并发下会:
这是新手常犯错误。
那更简单:
在应用层生成 ID:
id := snowflake.Generate()
然后:
INSERT INTO users (id, nickname) VALUES (?, ?)
优点:
大厂基本都这么做。
例如:
如果你用 uuid 作为主键:
直接应用层生成:
id := uuid.New()
然后插入即可。
不需要再查。
如果插入后马上要插入子表:
tx, _ := db.BeginTx(ctx, nil) var userID int64 err := tx.QueryRowContext(ctx, "INSERT INTO users (nickname) VALUES ($1) RETURNING id", nickname, ).Scan(&userID) _, err = tx.ExecContext(ctx, "INSERT INTO profiles (user_id) VALUES ($1)", userID, ) tx.Commit()
保证一致性。
如果你准备做:
我建议:
应用层生成 int64 雪花ID
这样:
如果你愿意,我可以:
你现在用的是 PostgreSQL 还是 MySQL?