Files
nl-game-api/cmd/dbtool/main.go
2026-08-14 13:17:03 +08:00

129 lines
3.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// dbtool 数据库初始化工具:读取 sql/init.sql 并逐条执行
// 用法(在 nl-game-api-gin 目录下go run ./cmd/dbtool -f ../sql/init.sql
// 连接参数复用 config.yaml 中的 mysql 配置(不指定库名,脚本自带 CREATE DATABASE
package main
import (
"database/sql"
"flag"
"fmt"
"log"
"os"
"strings"
_ "github.com/go-sql-driver/mysql"
"nl-game-api-gin/internal/config"
)
func main() {
file := flag.String("f", "../sql/init.sql", "SQL 脚本路径")
conf := flag.String("c", "config.yaml", "配置文件路径")
flag.Parse()
if err := config.Load(*conf); err != nil {
log.Fatalln("配置加载失败:", err)
}
raw, err := os.ReadFile(*file)
if err != nil {
log.Fatalln("读取 SQL 文件失败:", err)
}
// 服务器级 DSN不带库名multiStatements 关闭、逐条执行便于定位错误
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8mb4&parseTime=false",
config.C.MySQL.User, config.C.MySQL.Password, config.C.MySQL.Host, config.C.MySQL.Port)
db, err := sql.Open("mysql", dsn)
if err != nil {
log.Fatalln("连接 MySQL 失败:", err)
}
defer db.Close()
// 限制单连接:保证 USE xiaoyouxi 对后续语句生效
db.SetMaxOpenConns(1)
if err := db.Ping(); err != nil {
log.Fatalln("MySQL 无法连通,请确认服务已启动且账号密码正确:", err)
}
stmts := splitSQL(string(raw))
log.Printf("共解析出 %d 条语句,开始执行…\n", len(stmts))
for i, s := range stmts {
if _, err := db.Exec(s); err != nil {
head := s
if len(head) > 80 {
head = head[:80] + "…"
}
log.Fatalf("第 %d 条语句执行失败: %v\n语句开头: %s", i+1, err, head)
}
}
log.Println("✅ 数据库初始化完成(库名 xiaoyouxi含种子数据与超管 liqi")
}
// splitSQL 把脚本按分号拆成独立语句:跟踪引号与注释状态,避免误切字符串内的分号
func splitSQL(text string) []string {
var stmts []string
var sb strings.Builder
inSingle, inDouble, inBacktick, inLineComment := false, false, false, false
runes := []rune(text)
for i := 0; i < len(runes); i++ {
ch := runes[i]
// 行注释:遇到换行结束(注释内容不写入语句)
if inLineComment {
if ch == '\n' {
inLineComment = false
}
continue
}
// 检测行注释起始(不在任何引号内)
if !inSingle && !inDouble && !inBacktick && ch == '-' && i+1 < len(runes) && runes[i+1] == '-' {
inLineComment = true
i++
continue
}
// 引号状态翻转MySQL 字符串内以 \' 转义,需要跳过转义符)
switch {
case inSingle:
if ch == '\\' && i+1 < len(runes) {
sb.WriteRune(ch)
i++
sb.WriteRune(runes[i])
continue
}
if ch == '\'' {
inSingle = false
}
case inDouble:
if ch == '\\' && i+1 < len(runes) {
sb.WriteRune(ch)
i++
sb.WriteRune(runes[i])
continue
}
if ch == '"' {
inDouble = false
}
case inBacktick:
if ch == '`' {
inBacktick = false
}
default:
if ch == '\'' {
inSingle = true
} else if ch == '"' {
inDouble = true
} else if ch == '`' {
inBacktick = true
} else if ch == ';' {
// 语句结束
stmt := strings.TrimSpace(sb.String())
if stmt != "" {
stmts = append(stmts, stmt)
}
sb.Reset()
continue
}
}
sb.WriteRune(ch)
}
// 收尾:最后一条可能没有分号
if tail := strings.TrimSpace(sb.String()); tail != "" {
stmts = append(stmts, tail)
}
return stmts
}