//go:build ignore // 数据库完整性检查工具 package main import ( "fmt" "log" "github.com/glebarez/sqlite" "gorm.io/gorm" ) func main() { db, err := gorm.Open(sqlite.Open("./data/user_management.db"), &gorm.Config{}) if err != nil { log.Fatal("open db:", err) } fmt.Println("=== 数据库完整性检查 ===\n") // 1. 表存在性检查 tables := []string{"users", "roles", "permissions", "user_roles", "role_permissions", "devices", "login_logs", "operation_logs", "social_accounts", "webhooks", "webhook_deliveries", "password_histories"} fmt.Println("[1] 表结构检查:") for _, table := range tables { var count int64 result := db.Raw("SELECT COUNT(*) FROM " + table).Scan(&count) if result.Error != nil { fmt.Printf(" ❌ %s: ERROR - %v\n", table, result.Error) } else { fmt.Printf(" ✅ %s: %d rows\n", table, count) } } // 2. 用户数据完整性 fmt.Println("\n[2] 用户数据:") var users []struct { ID int64 Username string Email *string Status int CreatedAt string } db.Raw("SELECT id, username, email, status, created_at FROM users").Scan(&users) for _, u := range users { email := "NULL" if u.Email != nil { email = *u.Email } fmt.Printf(" User[%d]: %s | email=%s | status=%d | created=%s\n", u.ID, u.Username, email, u.Status, u.CreatedAt) } // 3. 角色-权限绑定 fmt.Println("\n[3] 角色-权限绑定:") var rolePerms []struct { RoleID int64 PermissionID int64 } db.Raw("SELECT role_id, permission_id FROM role_permissions").Scan(&rolePerms) if len(rolePerms) == 0 { fmt.Println(" ⚠️ 没有角色-权限绑定数据") } else { for _, rp := range rolePerms { fmt.Printf(" role_id=%d permission_id=%d\n", rp.RoleID, rp.PermissionID) } } // 4. 操作日志(近5条) fmt.Println("\n[4] 操作日志(最近5条):") var opLogs []struct { ID int64 UserID int64 RequestMethod string RequestPath string ResponseStatus int CreatedAt string } db.Raw("SELECT id, user_id, request_method, request_path, response_status, created_at FROM operation_logs ORDER BY id DESC LIMIT 5").Scan(&opLogs) for _, l := range opLogs { fmt.Printf(" [%d] user=%d %s %s status=%d time=%s\n", l.ID, l.UserID, l.RequestMethod, l.RequestPath, l.ResponseStatus, l.CreatedAt) } // 5. 登录日志 fmt.Println("\n[5] 登录日志:") var loginLogs []struct { ID int64 UserID int64 IP string Status int CreatedAt string } db.Raw("SELECT id, user_id, ip, status, created_at FROM login_logs ORDER BY id DESC LIMIT 10").Scan(&loginLogs) if len(loginLogs) == 0 { fmt.Println(" ⚠️ 没有登录日志数据 - 登录时未记录!") } else { for _, l := range loginLogs { fmt.Printf(" [%d] user=%d ip=%s status=%d time=%s\n", l.ID, l.UserID, l.IP, l.Status, l.CreatedAt) } } // 6. 密码历史 fmt.Println("\n[6] 密码历史:") var pwdHistory []struct { ID int64 UserID int64 CreatedAt string } db.Raw("SELECT id, user_id, created_at FROM password_histories ORDER BY id DESC LIMIT 5").Scan(&pwdHistory) for _, ph := range pwdHistory { fmt.Printf(" [%d] user=%d time=%s\n", ph.ID, ph.UserID, ph.CreatedAt) } // 7. 索引检查 fmt.Println("\n[7] 主要唯一约束验证:") // 检查 users 邮箱唯一 var dupEmails []struct { Email string Count int64 } db.Raw("SELECT email, COUNT(*) as count FROM users WHERE email IS NOT NULL GROUP BY email HAVING count > 1").Scan(&dupEmails) if len(dupEmails) == 0 { fmt.Println(" ✅ users.email 唯一性: OK") } else { fmt.Printf(" ❌ users.email 重复: %v\n", dupEmails) } // 检查 users 用户名唯一 var dupUsernames []struct { Username string Count int64 } db.Raw("SELECT username, COUNT(*) as count FROM users GROUP BY username HAVING count > 1").Scan(&dupUsernames) if len(dupUsernames) == 0 { fmt.Println(" ✅ users.username 唯一性: OK") } else { fmt.Printf(" ❌ users.username 重复: %v\n", dupUsernames) } fmt.Println("\n=== 检查完成 ===") }