修复迁移时,数据库未指定的情况下数据库脚本混乱的问题
This commit is contained in:
35
MIGRATION.md
35
MIGRATION.md
@@ -105,14 +105,10 @@ go build -o bin/migrate cmd/migrate/main.go
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 方式2:环境变量(推荐生产环境)
|
#### 方式2:环境变量指定配置文件路径(推荐生产环境)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 使用 DATABASE_URL(最简单)
|
# 使用环境变量指定配置文件路径
|
||||||
export DATABASE_URL="mysql://root:password@localhost:3306/mydb"
|
|
||||||
./bin/migrate up
|
|
||||||
|
|
||||||
# 覆盖配置路径
|
|
||||||
export CONFIG_FILE="/etc/app/config.json"
|
export CONFIG_FILE="/etc/app/config.json"
|
||||||
export MIGRATIONS_DIR="/opt/app/migrations"
|
export MIGRATIONS_DIR="/opt/app/migrations"
|
||||||
./bin/migrate up
|
./bin/migrate up
|
||||||
@@ -122,8 +118,7 @@ export MIGRATIONS_DIR="/opt/app/migrations"
|
|||||||
|
|
||||||
1. 命令行参数 `-config` 和 `-dir`(最高)
|
1. 命令行参数 `-config` 和 `-dir`(最高)
|
||||||
2. 环境变量 `CONFIG_FILE` 和 `MIGRATIONS_DIR`
|
2. 环境变量 `CONFIG_FILE` 和 `MIGRATIONS_DIR`
|
||||||
3. 环境变量 `DATABASE_URL`
|
3. 默认值 `config.json` 和 `migrations`
|
||||||
4. 默认值 `config.json` 和 `migrations`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -185,20 +180,20 @@ services:
|
|||||||
docker-compose exec app ./migrate up
|
docker-compose exec app ./migrate up
|
||||||
```
|
```
|
||||||
|
|
||||||
### 方式3:使用环境变量
|
### 方式3:使用环境变量指定配置文件路径
|
||||||
|
|
||||||
无需配置文件(适用于简单场景):
|
适用于多环境部署,通过环境变量指定不同环境的配置文件:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
build: .
|
build: .
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: mysql://root:password@db:3306/mydb
|
CONFIG_FILE: /app/config.prod.json
|
||||||
|
MIGRATIONS_DIR: /app/migrations
|
||||||
|
volumes:
|
||||||
|
- ./config.prod.json:/app/config.prod.json:ro
|
||||||
command: sh -c "./migrate up && ./server"
|
command: sh -c "./migrate up && ./server"
|
||||||
|
|
||||||
# 注意:DATABASE_URL 的值应该指向你的数据库服务
|
|
||||||
# 例如:mysql://user:pass@your-db-host:3306/dbname
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dockerfile
|
### Dockerfile
|
||||||
@@ -336,10 +331,12 @@ jobs:
|
|||||||
go build -o bin/migrate cmd/migrate/main.go
|
go build -o bin/migrate cmd/migrate/main.go
|
||||||
go build -o bin/server cmd/server/main.go
|
go build -o bin/server cmd/server/main.go
|
||||||
|
|
||||||
|
- name: Create Config File
|
||||||
|
run: |
|
||||||
|
echo '${{ secrets.CONFIG_JSON }}' > config.json
|
||||||
|
|
||||||
- name: Run Migrations
|
- name: Run Migrations
|
||||||
env:
|
run: ./bin/migrate up -config config.json
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
run: ./bin/migrate up
|
|
||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
run: ./bin/server
|
run: ./bin/server
|
||||||
@@ -500,11 +497,11 @@ go build -o bin/migrate cmd/migrate/main.go
|
|||||||
### 3. 生产环境
|
### 3. 生产环境
|
||||||
|
|
||||||
- 编译后部署,先执行迁移再启动应用
|
- 编译后部署,先执行迁移再启动应用
|
||||||
- 使用环境变量管理敏感信息
|
- 使用配置文件管理敏感信息
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go build -o bin/migrate cmd/migrate/main.go
|
go build -o bin/migrate cmd/migrate/main.go
|
||||||
DATABASE_URL="mysql://..." ./bin/migrate up
|
./bin/migrate up -config config.json
|
||||||
./bin/server
|
./bin/server
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ err := migration.RunMigrationsFromConfigWithCommand("config.json", "migrations",
|
|||||||
```
|
```
|
||||||
|
|
||||||
**参数说明**:
|
**参数说明**:
|
||||||
- `configFile`: 配置文件路径,空字符串时自动查找(config.json, ../config.json)或使用环境变量 DATABASE_URL
|
- `configFile`: 配置文件路径,空字符串时自动查找(config.json, ../config.json)
|
||||||
- `migrationsDir`: 迁移文件目录,空字符串时使用默认值 "migrations"
|
- `migrationsDir`: 迁移文件目录,空字符串时使用默认值 "migrations"
|
||||||
- `command`: 命令,支持 "up", "down", "status"
|
- `command`: 命令,支持 "up", "down", "status"
|
||||||
|
|
||||||
|
|||||||
@@ -110,10 +110,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 方式2:环境变量(Docker友好)
|
### 方式2:使用配置文件(推荐)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
DATABASE_URL="mysql://root:password@localhost:3306/mydb" go run migrate.go up
|
# 使用默认配置文件 config.json
|
||||||
|
go run migrate.go up
|
||||||
|
|
||||||
|
# 或指定配置文件路径
|
||||||
|
go run migrate.go up -config /path/to/config.json
|
||||||
```
|
```
|
||||||
|
|
||||||
**Docker 中**:
|
**Docker 中**:
|
||||||
@@ -121,12 +125,13 @@ DATABASE_URL="mysql://root:password@localhost:3306/mydb" go run migrate.go up
|
|||||||
# docker-compose.yml
|
# docker-compose.yml
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
environment:
|
volumes:
|
||||||
DATABASE_URL: mysql://root:password@db:3306/mydb
|
# 挂载配置文件
|
||||||
|
- ./config.json:/app/config.json:ro
|
||||||
command: sh -c "go run migrate.go up && ./app"
|
command: sh -c "go run migrate.go up && ./app"
|
||||||
```
|
```
|
||||||
|
|
||||||
**注意**:Docker 中使用服务名(`db`),不是 `localhost`
|
**注意**:配置文件中的数据库主机应使用服务名(`db`),不是 `localhost`
|
||||||
|
|
||||||
## 更多信息
|
## 更多信息
|
||||||
|
|
||||||
|
|||||||
@@ -789,8 +789,12 @@ func (f *Factory) RunMigrations(migrationsDir string) error {
|
|||||||
return fmt.Errorf("failed to get database: %w", err)
|
return fmt.Errorf("failed to get database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建迁移器
|
// 创建迁移器(传入数据库类型,性能更好)
|
||||||
migrator := migration.NewMigrator(db)
|
dbType := "mysql" // 默认值
|
||||||
|
if f.cfg.Database != nil && f.cfg.Database.Type != "" {
|
||||||
|
dbType = f.cfg.Database.Type
|
||||||
|
}
|
||||||
|
migrator := migration.NewMigratorWithType(db, dbType)
|
||||||
|
|
||||||
// 自动发现并加载迁移文件
|
// 自动发现并加载迁移文件
|
||||||
migrations, err := migration.LoadMigrationsFromFiles(migrationsDir, "*.sql")
|
migrations, err := migration.LoadMigrationsFromFiles(migrationsDir, "*.sql")
|
||||||
@@ -835,8 +839,12 @@ func (f *Factory) GetMigrationStatus(migrationsDir string) ([]migration.Migratio
|
|||||||
return nil, fmt.Errorf("failed to get database: %w", err)
|
return nil, fmt.Errorf("failed to get database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建迁移器
|
// 创建迁移器(传入数据库类型,性能更好)
|
||||||
migrator := migration.NewMigrator(db)
|
dbType := "mysql" // 默认值
|
||||||
|
if f.cfg.Database != nil && f.cfg.Database.Type != "" {
|
||||||
|
dbType = f.cfg.Database.Type
|
||||||
|
}
|
||||||
|
migrator := migration.NewMigratorWithType(db, dbType)
|
||||||
|
|
||||||
// 加载迁移文件
|
// 加载迁移文件
|
||||||
migrations, err := migration.LoadMigrationsFromFiles(migrationsDir, "*.sql")
|
migrations, err := migration.LoadMigrationsFromFiles(migrationsDir, "*.sql")
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ func RunMigrationsFromConfig(configFile, migrationsDir string) error {
|
|||||||
// RunMigrationsFromConfigWithCommand 从配置文件运行迁移(支持命令,黑盒模式)
|
// RunMigrationsFromConfigWithCommand 从配置文件运行迁移(支持命令,黑盒模式)
|
||||||
//
|
//
|
||||||
// 这是最简单的迁移方式,内部自动处理:
|
// 这是最简单的迁移方式,内部自动处理:
|
||||||
// - 配置加载(支持文件、环境变量、默认路径)
|
// - 配置加载(支持配置文件、默认路径)
|
||||||
// - 数据库连接(自动识别数据库类型)
|
// - 数据库连接(自动识别数据库类型)
|
||||||
// - 迁移文件加载和执行
|
// - 迁移文件加载和执行
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
// - configFile: 配置文件路径,支持:
|
// - configFile: 配置文件路径,支持:
|
||||||
// - 空字符串:自动查找(config.json, ../config.json)
|
// - 空字符串:自动查找(config.json, ../config.json)
|
||||||
// - 环境变量 DATABASE_URL:直接使用数据库URL
|
// - 相对路径或绝对路径:指定配置文件路径
|
||||||
// - migrationsDir: 迁移文件目录,支持:
|
// - migrationsDir: 迁移文件目录,支持:
|
||||||
// - 空字符串:使用默认目录 "migrations"
|
// - 空字符串:使用默认目录 "migrations"
|
||||||
// - 相对路径或绝对路径
|
// - 相对路径或绝对路径
|
||||||
@@ -57,9 +57,6 @@ func RunMigrationsFromConfig(configFile, migrationsDir string) error {
|
|||||||
//
|
//
|
||||||
// // 指定配置和迁移目录
|
// // 指定配置和迁移目录
|
||||||
// migration.RunMigrationsFromConfigWithCommand("config.json", "scripts/sql", "up")
|
// migration.RunMigrationsFromConfigWithCommand("config.json", "scripts/sql", "up")
|
||||||
//
|
|
||||||
// // 使用环境变量
|
|
||||||
// // DATABASE_URL="mysql://..." migration.RunMigrationsFromConfigWithCommand("", "migrations", "up")
|
|
||||||
func RunMigrationsFromConfigWithCommand(configFile, migrationsDir, command string) error {
|
func RunMigrationsFromConfigWithCommand(configFile, migrationsDir, command string) error {
|
||||||
// 加载配置
|
// 加载配置
|
||||||
cfg, err := loadConfigFromFileOrEnv(configFile)
|
cfg, err := loadConfigFromFileOrEnv(configFile)
|
||||||
@@ -78,8 +75,8 @@ func RunMigrationsFromConfigWithCommand(configFile, migrationsDir, command strin
|
|||||||
migrationsDir = "migrations"
|
migrationsDir = "migrations"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建迁移器
|
// 创建迁移器(传入数据库类型,性能更好)
|
||||||
migrator := NewMigrator(db)
|
migrator := NewMigratorWithType(db, cfg.Database.Type)
|
||||||
|
|
||||||
// 加载迁移文件
|
// 加载迁移文件
|
||||||
migrations, err := LoadMigrationsFromFiles(migrationsDir, "*.sql")
|
migrations, err := LoadMigrationsFromFiles(migrationsDir, "*.sql")
|
||||||
@@ -122,22 +119,16 @@ func RunMigrationsFromConfigWithCommand(configFile, migrationsDir, command strin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadConfigFromFileOrEnv 从文件或环境变量加载配置
|
// loadConfigFromFileOrEnv 从配置文件加载配置
|
||||||
|
// 支持指定配置文件路径,或自动查找默认路径
|
||||||
func loadConfigFromFileOrEnv(configFile string) (*config.Config, error) {
|
func loadConfigFromFileOrEnv(configFile string) (*config.Config, error) {
|
||||||
// 优先从环境变量加载
|
// 如果指定了配置文件路径,优先使用
|
||||||
if dbURL := os.Getenv("DATABASE_URL"); dbURL != "" {
|
|
||||||
return &config.Config{
|
|
||||||
Database: &config.DatabaseConfig{
|
|
||||||
DSN: dbURL,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试从配置文件加载
|
|
||||||
if configFile != "" {
|
if configFile != "" {
|
||||||
if _, err := os.Stat(configFile); err == nil {
|
if _, err := os.Stat(configFile); err == nil {
|
||||||
return config.LoadFromFile(configFile)
|
return config.LoadFromFile(configFile)
|
||||||
}
|
}
|
||||||
|
// 如果指定的文件不存在,返回错误
|
||||||
|
return nil, fmt.Errorf("配置文件不存在: %s", configFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试默认路径
|
// 尝试默认路径
|
||||||
@@ -148,7 +139,7 @@ func loadConfigFromFileOrEnv(configFile string) (*config.Config, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("未找到配置文件,也未设置环境变量 DATABASE_URL")
|
return nil, fmt.Errorf("未找到配置文件,请指定配置文件路径或确保存在以下文件之一: %v", defaultPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
// connectDB 连接数据库
|
// connectDB 连接数据库
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ type Migrator struct {
|
|||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
migrations []Migration
|
migrations []Migration
|
||||||
tableName string
|
tableName string
|
||||||
|
dbType string // 数据库类型: mysql, postgres, sqlite
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMigrator 创建新的迁移器
|
// NewMigrator 创建新的迁移器
|
||||||
@@ -41,6 +42,25 @@ func NewMigrator(db *gorm.DB, tableName ...string) *Migrator {
|
|||||||
db: db,
|
db: db,
|
||||||
migrations: make([]Migration, 0),
|
migrations: make([]Migration, 0),
|
||||||
tableName: table,
|
tableName: table,
|
||||||
|
dbType: "", // 未指定时为空,会使用兼容模式
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMigratorWithType 创建新的迁移器(指定数据库类型,性能更好)
|
||||||
|
// db: GORM数据库连接
|
||||||
|
// dbType: 数据库类型 ("mysql", "postgres", "sqlite")
|
||||||
|
// tableName: 存储迁移记录的表名,默认为 "schema_migrations"
|
||||||
|
func NewMigratorWithType(db *gorm.DB, dbType string, tableName ...string) *Migrator {
|
||||||
|
table := "schema_migrations"
|
||||||
|
if len(tableName) > 0 && tableName[0] != "" {
|
||||||
|
table = tableName[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Migrator{
|
||||||
|
db: db,
|
||||||
|
migrations: make([]Migration, 0),
|
||||||
|
tableName: table,
|
||||||
|
dbType: dbType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,18 +76,78 @@ func (m *Migrator) AddMigrations(migrations ...Migration) {
|
|||||||
|
|
||||||
// initTable 初始化迁移记录表
|
// initTable 初始化迁移记录表
|
||||||
func (m *Migrator) initTable() error {
|
func (m *Migrator) initTable() error {
|
||||||
// 检查表是否存在
|
// 检查表是否存在(根据数据库类型使用对应的SQL,性能更好)
|
||||||
var exists bool
|
var exists bool
|
||||||
err := m.db.Raw(fmt.Sprintf(`
|
var err error
|
||||||
SELECT EXISTS (
|
|
||||||
SELECT FROM information_schema.tables
|
|
||||||
WHERE table_schema = CURRENT_SCHEMA()
|
|
||||||
AND table_name = '%s'
|
|
||||||
)
|
|
||||||
`, m.tableName)).Scan(&exists).Error
|
|
||||||
|
|
||||||
|
switch m.dbType {
|
||||||
|
case "mysql":
|
||||||
|
// MySQL/MariaDB语法
|
||||||
|
var count int64
|
||||||
|
err = m.db.Raw(fmt.Sprintf(`
|
||||||
|
SELECT COUNT(*) FROM information_schema.tables
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = '%s'
|
||||||
|
`, m.tableName)).Scan(&count).Error
|
||||||
|
if err == nil {
|
||||||
|
exists = count > 0
|
||||||
|
}
|
||||||
|
case "postgres":
|
||||||
|
// PostgreSQL语法
|
||||||
|
err = m.db.Raw(fmt.Sprintf(`
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.tables
|
||||||
|
WHERE table_schema = CURRENT_SCHEMA()
|
||||||
|
AND table_name = '%s'
|
||||||
|
)
|
||||||
|
`, m.tableName)).Scan(&exists).Error
|
||||||
|
case "sqlite":
|
||||||
|
// SQLite语法
|
||||||
|
var count int64
|
||||||
|
err = m.db.Raw(fmt.Sprintf(`
|
||||||
|
SELECT COUNT(*) FROM sqlite_master
|
||||||
|
WHERE type='table' AND name='%s'
|
||||||
|
`, m.tableName)).Scan(&count).Error
|
||||||
|
if err == nil {
|
||||||
|
exists = count > 0
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// 未指定数据库类型时,使用兼容模式(向后兼容)
|
||||||
|
// 按顺序尝试不同数据库的语法
|
||||||
|
var count int64
|
||||||
|
err = m.db.Raw(fmt.Sprintf(`
|
||||||
|
SELECT COUNT(*) FROM information_schema.tables
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = '%s'
|
||||||
|
`, m.tableName)).Scan(&count).Error
|
||||||
|
if err == nil && count > 0 {
|
||||||
|
exists = true
|
||||||
|
} else {
|
||||||
|
var pgExists bool
|
||||||
|
err = m.db.Raw(fmt.Sprintf(`
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.tables
|
||||||
|
WHERE table_schema = CURRENT_SCHEMA()
|
||||||
|
AND table_name = '%s'
|
||||||
|
)
|
||||||
|
`, m.tableName)).Scan(&pgExists).Error
|
||||||
|
if err == nil {
|
||||||
|
exists = pgExists
|
||||||
|
} else {
|
||||||
|
var sqliteCount int64
|
||||||
|
err = m.db.Raw(fmt.Sprintf(`
|
||||||
|
SELECT COUNT(*) FROM sqlite_master
|
||||||
|
WHERE type='table' AND name='%s'
|
||||||
|
`, m.tableName)).Scan(&sqliteCount).Error
|
||||||
|
if err == nil && sqliteCount > 0 {
|
||||||
|
exists = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果查询失败,假设表不存在,尝试创建
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// 如果查询失败,可能是SQLite或其他数据库,尝试直接创建
|
|
||||||
exists = false
|
exists = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,19 +169,57 @@ func (m *Migrator) initTable() error {
|
|||||||
// 注意:这个检查可能在某些数据库中失败,但不影响功能
|
// 注意:这个检查可能在某些数据库中失败,但不影响功能
|
||||||
// 如果字段不存在,记录执行时间时会失败,但不影响迁移执行
|
// 如果字段不存在,记录执行时间时会失败,但不影响迁移执行
|
||||||
var hasExecutionTime bool
|
var hasExecutionTime bool
|
||||||
checkSQL := fmt.Sprintf(`
|
var columnCount int64
|
||||||
SELECT COUNT(*) > 0
|
var checkErr error
|
||||||
FROM information_schema.columns
|
|
||||||
WHERE table_schema = CURRENT_SCHEMA()
|
switch m.dbType {
|
||||||
AND table_name = '%s'
|
case "mysql":
|
||||||
AND column_name = 'execution_time'
|
// MySQL/MariaDB语法
|
||||||
`, m.tableName)
|
checkErr = m.db.Raw(fmt.Sprintf(`
|
||||||
err = m.db.Raw(checkSQL).Scan(&hasExecutionTime).Error
|
SELECT COUNT(*)
|
||||||
if err == nil && !hasExecutionTime {
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = '%s'
|
||||||
|
AND column_name = 'execution_time'
|
||||||
|
`, m.tableName)).Scan(&columnCount).Error
|
||||||
|
if checkErr == nil {
|
||||||
|
hasExecutionTime = columnCount > 0
|
||||||
|
}
|
||||||
|
case "postgres":
|
||||||
|
// PostgreSQL语法
|
||||||
|
checkErr = m.db.Raw(fmt.Sprintf(`
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = CURRENT_SCHEMA()
|
||||||
|
AND table_name = '%s'
|
||||||
|
AND column_name = 'execution_time'
|
||||||
|
`, m.tableName)).Scan(&columnCount).Error
|
||||||
|
if checkErr == nil {
|
||||||
|
hasExecutionTime = columnCount > 0
|
||||||
|
}
|
||||||
|
case "sqlite":
|
||||||
|
// SQLite不支持information_schema,跳过检查
|
||||||
|
hasExecutionTime = false
|
||||||
|
default:
|
||||||
|
// 兼容模式:尝试MySQL语法
|
||||||
|
checkErr = m.db.Raw(fmt.Sprintf(`
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = '%s'
|
||||||
|
AND column_name = 'execution_time'
|
||||||
|
`, m.tableName)).Scan(&columnCount).Error
|
||||||
|
if checkErr == nil {
|
||||||
|
hasExecutionTime = columnCount > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasExecutionTime {
|
||||||
// 尝试添加字段(如果失败不影响功能)
|
// 尝试添加字段(如果失败不影响功能)
|
||||||
|
// 注意:SQLite的ALTER TABLE ADD COLUMN语法略有不同,但GORM会处理
|
||||||
_ = m.db.Exec(fmt.Sprintf(`
|
_ = m.db.Exec(fmt.Sprintf(`
|
||||||
ALTER TABLE %s
|
ALTER TABLE %s
|
||||||
ADD COLUMN execution_time INT COMMENT '执行耗时(ms)'
|
ADD COLUMN execution_time INT
|
||||||
`, m.tableName))
|
`, m.tableName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ import (
|
|||||||
// ./migrate down # 回滚最后一个迁移
|
// ./migrate down # 回滚最后一个迁移
|
||||||
//
|
//
|
||||||
// Docker 中使用:
|
// Docker 中使用:
|
||||||
// # 方式1:挂载配置文件
|
// # 方式1:挂载配置文件(推荐)
|
||||||
// docker run -v /host/config.json:/app/config.json myapp ./migrate up
|
// docker run -v /host/config.json:/app/config.json myapp ./migrate up
|
||||||
//
|
//
|
||||||
// # 方式2:使用环境变量
|
// # 方式2:使用环境变量指定配置文件路径
|
||||||
// docker run -e DATABASE_URL="mysql://..." myapp ./migrate up
|
// docker run -e CONFIG_FILE=/etc/app/config.json myapp ./migrate up
|
||||||
//
|
//
|
||||||
// # 方式3:指定容器内的配置文件路径
|
// # 方式3:指定容器内的配置文件路径
|
||||||
// docker run myapp ./migrate up -config /etc/app/config.json
|
// docker run myapp ./migrate up -config /etc/app/config.json
|
||||||
@@ -41,8 +41,7 @@ import (
|
|||||||
// 配置优先级(从高到低):
|
// 配置优先级(从高到低):
|
||||||
// 1. 命令行参数 -config 和 -dir
|
// 1. 命令行参数 -config 和 -dir
|
||||||
// 2. 环境变量 CONFIG_FILE 和 MIGRATIONS_DIR
|
// 2. 环境变量 CONFIG_FILE 和 MIGRATIONS_DIR
|
||||||
// 3. 环境变量 DATABASE_URL(直接连接,无需配置文件)
|
// 3. 默认值(config.json 和 migrations)
|
||||||
// 4. 默认值(config.json 和 migrations)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
configFile string
|
configFile string
|
||||||
@@ -137,15 +136,14 @@ func printHelp() {
|
|||||||
fmt.Println(" # 指定配置和迁移目录")
|
fmt.Println(" # 指定配置和迁移目录")
|
||||||
fmt.Println(" migrate up -c config.json -d db/migrations")
|
fmt.Println(" migrate up -c config.json -d db/migrations")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(" # 使用环境变量")
|
fmt.Println(" # 使用环境变量指定配置文件路径")
|
||||||
fmt.Println(" DATABASE_URL='mysql://...' migrate up")
|
fmt.Println(" CONFIG_FILE=/etc/app/config.json migrate up")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println(" # Docker 中使用")
|
fmt.Println(" # Docker 中使用(挂载配置文件)")
|
||||||
fmt.Println(" docker run -v /host/config.json:/app/config.json myapp migrate up")
|
fmt.Println(" docker run -v /host/config.json:/app/config.json myapp migrate up")
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("配置优先级(从高到低):")
|
fmt.Println("配置优先级(从高到低):")
|
||||||
fmt.Println(" 1. 命令行参数 -config 和 -dir")
|
fmt.Println(" 1. 命令行参数 -config 和 -dir")
|
||||||
fmt.Println(" 2. 环境变量 CONFIG_FILE 和 MIGRATIONS_DIR")
|
fmt.Println(" 2. 环境变量 CONFIG_FILE 和 MIGRATIONS_DIR")
|
||||||
fmt.Println(" 3. 环境变量 DATABASE_URL")
|
fmt.Println(" 3. 默认值(config.json 和 migrations)")
|
||||||
fmt.Println(" 4. 默认值(config.json 和 migrations)")
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user