Golang SQL迁移包使用评测
Golang SQL迁移包使用评测 你好!
我一直在寻找一个能够解决我特定问题的迁移包:允许我在迁移过程中运行一些用 Go 实现的复杂逻辑。例如:从外部资源获取数据,执行我无法用纯 SQL 完成的复杂计算。我未能找到这样的包,因此决定自己编写一个来解决这个问题。
我请求大家对我的包进行审查:https://github.com/iamsalnikov/mymigrate
这个包支持 Cobra 命令。理论上,它可以与任何 SQL 数据库配合工作,因为它仅依赖于 Go 标准库中的 sql 包。
如果有人能审查这个包或其部分代码,我将不胜感激。
谢谢!
更多关于Golang SQL迁移包使用评测的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang SQL迁移包使用评测的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
代码审查与使用示例
看了你的 mymigrate 包,这是一个很有价值的工具,特别适合需要在迁移中执行复杂Go逻辑的场景。以下是专业评测和使用示例:
核心优势
- 纯Go迁移逻辑:支持在迁移中执行任意Go代码,这是与传统SQL迁移工具的主要区别
- 标准库依赖:仅依赖
database/sql,兼容所有SQL数据库 - Cobra集成:命令行工具友好,适合现代Go项目结构
代码结构分析
// 你的包结构清晰,以下是一个典型的使用示例:
package main
import (
"database/sql"
"fmt"
"log"
"github.com/iamsalnikov/mymigrate"
_ "github.com/lib/pq" // PostgreSQL驱动
)
func main() {
db, err := sql.Open("postgres", "postgres://user:pass@localhost/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 初始化迁移器
migrator := mymigrate.New(db, "migrations_table")
// 注册迁移
migrator.AddMigration("20240101000000_init", func(tx *sql.Tx) error {
// 复杂逻辑示例:从外部API获取数据
externalData, err := fetchExternalData()
if err != nil {
return err
}
// 执行复杂计算
processedData := complexCalculation(externalData)
// 创建表
_, err = tx.Exec(`
CREATE TABLE IF NOT EXISTS processed_data (
id SERIAL PRIMARY KEY,
data JSONB,
created_at TIMESTAMP DEFAULT NOW()
)
`)
if err != nil {
return err
}
// 插入处理后的数据
for _, item := range processedData {
_, err = tx.Exec(
"INSERT INTO processed_data (data) VALUES ($1)",
item,
)
if err != nil {
return err
}
}
return nil
})
migrator.AddMigration("20240101000001_update_logic", func(tx *sql.Tx) error {
// 另一个迁移示例:数据转换
rows, err := tx.Query("SELECT id, data FROM processed_data")
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var id int
var data string
if err := rows.Scan(&id, &data); err != nil {
return err
}
// 执行Go逻辑处理
transformed := transformData(data)
_, err = tx.Exec(
"UPDATE processed_data SET data = $1 WHERE id = $2",
transformed, id,
)
if err != nil {
return err
}
}
return rows.Err()
})
// 执行迁移
if err := migrator.Migrate(); err != nil {
log.Fatal("Migration failed:", err)
}
fmt.Println("Migrations completed successfully")
}
// 外部数据获取函数
func fetchExternalData() ([]string, error) {
// 实现从外部API、文件或其他来源获取数据的逻辑
return []string{"data1", "data2", "data3"}, nil
}
// 复杂计算函数
func complexCalculation(data []string) []string {
var result []string
for _, d := range data {
// 执行无法用SQL实现的复杂逻辑
result = append(result, "processed_"+d)
}
return result
}
// 数据转换函数
func transformData(data string) string {
// 复杂的Go逻辑处理
return "transformed_" + data
}
Cobra命令集成示例
// cmd/migrate.go
package cmd
import (
"database/sql"
"fmt"
"log"
"github.com/iamsalnikov/mymigrate"
"github.com/spf13/cobra"
)
var migrateCmd = &cobra.Command{
Use: "migrate",
Short: "Run database migrations",
Run: func(cmd *cobra.Command, args []string) {
db, err := sql.Open("postgres", "postgres://user:pass@localhost/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
migrator := mymigrate.New(db, "schema_migrations")
// 注册所有迁移
registerMigrations(migrator)
if err := migrator.Migrate(); err != nil {
log.Fatal("Migration failed:", err)
}
fmt.Println("✅ Migrations completed")
},
}
func registerMigrations(m *mymigrate.Migrator) {
m.AddMigration("20240101000000_create_users", func(tx *sql.Tx) error {
// 创建用户表并初始化数据
_, err := tx.Exec(`
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE,
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
)
`)
if err != nil {
return err
}
// 从外部服务获取初始用户数据
users, err := fetchInitialUsers()
if err != nil {
return err
}
for _, user := range users {
_, err = tx.Exec(
"INSERT INTO users (id, email, metadata) VALUES ($1, $2, $3)",
user.ID, user.Email, user.Metadata,
)
if err != nil {
return err
}
}
return nil
})
}
事务处理示例
// 展示事务中的错误处理和回滚
m.AddMigration("20240101000002_complex_transaction", func(tx *sql.Tx) error {
// 开始复杂操作
result, err := performComplexOperation()
if err != nil {
return err // 自动回滚
}
// 批量插入
for i := 0; i < len(result.Items); i += 100 {
batch := result.Items[i:min(i+100, len(result.Items))]
stmt, err := tx.Prepare("INSERT INTO items (name, value) VALUES ($1, $2)")
if err != nil {
return err
}
defer stmt.Close()
for _, item := range batch {
if _, err := stmt.Exec(item.Name, item.Value); err != nil {
return err
}
}
}
// 更新统计信息
stats := calculateStatistics(result)
_, err = tx.Exec(
"UPDATE system_stats SET last_processed = $1, total_items = $2",
stats.LastProcessed, stats.TotalItems,
)
return err
})
测试示例
// migration_test.go
package mymigrate_test
import (
"database/sql"
"testing"
"github.com/iamsalnikov/mymigrate"
_ "github.com/mattn/go-sqlite3"
)
func TestMigrationWithGoLogic(t *testing.T) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatal(err)
}
defer db.Close()
migrator := mymigrate.New(db, "test_migrations")
var migrationExecuted bool
migrator.AddMigration("test_migration", func(tx *sql.Tx) error {
// 测试复杂的Go逻辑
_, err := tx.Exec("CREATE TABLE test (id INTEGER PRIMARY KEY, data TEXT)")
if err != nil {
return err
}
// 执行Go计算
computedValue := computeTestValue()
_, err = tx.Exec("INSERT INTO test (data) VALUES (?)", computedValue)
if err != nil {
return err
}
migrationExecuted = true
return nil
})
if err := migrator.Migrate(); err != nil {
t.Fatalf("Migration failed: %v", err)
}
if !migrationExecuted {
t.Error("Migration was not executed")
}
// 验证数据
var count int
err = db.QueryRow("SELECT COUNT(*) FROM test").Scan(&count)
if err != nil {
t.Fatal(err)
}
if count != 1 {
t.Errorf("Expected 1 row, got %d", count)
}
}
func computeTestValue() string {
// 复杂的Go逻辑
return "computed_value"
}
你的包成功解决了在数据库迁移中执行复杂Go逻辑的需求,设计简洁且实用。事务支持确保了迁移的原子性,Cobra集成使其易于在命令行工具中使用。对于需要数据转换、外部API集成或复杂计算的迁移场景,这是一个很好的解决方案。

