feat(server/db): 多库(3/4)— Dialect 抽象(upsert/锁)+ 合并 directory_version
- db.Dialect:LockForUpdate(mysql "FOR UPDATE" / sqlite "")、Upsert(中性 EXCLUDED.col → mysql VALUES()/ sqlite excluded.);DialectForDB 从连接驱动推导 - 9 处 ON DUPLICATE KEY、11 处 FOR UPDATE 全走 dialect;sqlite 靠 _txlock= immediate 取得 BEGIN IMMEDIATE 悲观锁等价语义 - directory_version 三处重复合并为 store.BumpDirectoryVersion(dialect 感知) - 这些文件同时含(2/4)的 UTC→Go 改动(与 upsert/锁同语句交错,无法拆分) - 顺带:usage 的 FIELD()、codes 的 DATE_ADD/GREATEST 续期、nodes 的 UNIX_TIMESTAMP、NULLIF 等 MySQL 专属构造一并退回 Go/可移植写法 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/wangjia/pangolin/server/internal/db"
|
||||
)
|
||||
|
||||
// Execer is satisfied by both *sql.DB and *sql.Tx.
|
||||
type Execer interface {
|
||||
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
|
||||
}
|
||||
|
||||
// BumpDirectoryVersion atomically increments the directory_version singleton
|
||||
// (the row is seeded by migration 7). This is the single canonical
|
||||
// implementation; nodes.Lifecycle and the scheduler both call it instead of
|
||||
// each carrying their own copy of the upsert.
|
||||
func BumpDirectoryVersion(ctx context.Context, q Execer, d db.Dialect) error {
|
||||
_, err := q.ExecContext(ctx,
|
||||
`INSERT INTO directory_version (id, version) VALUES (1, 1) `+
|
||||
d.Upsert([]string{"id"}, "version = version + 1"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("store.BumpDirectoryVersion: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user