
过程
我连接的过程。
我的数据库模型文件在server/model下,这是我的user.go
package models
import (
"gorm.io/gorm"
"time"
)
// 用户基础模型
type User struct {
gorm.Model
Username string `gorm:"uniqueIndex;size:50;not null"`
Password string `gorm:"size:255;not null"`
RealName string `gorm:"size:50"`
Email string `gorm:"size:100"`
Phone string `gorm:"size:20"`
LastLogin time.Time
Status int `gorm:"default:1;check:status IN (0,1)"` // 0-禁用 1-正常
RoleID uint `gorm:"not null"`
Role Role `gorm:"foreignKey:RoleID"`
DepartmentID *uint
Department Department `gorm:"foreignKey:DepartmentID"`
}
// 角色表
type Role struct {
gorm.Model
Name string `gorm:"uniqueIndex;size:50;not null"`
Description string `gorm:"size:255"`
Permissions []Permission `gorm:"many2many:role_permissions;"`
}
// 权限表
type Permission struct {
gorm.Model
Name string `gorm:"uniqueIndex;size:50;not null"`
Description string `gorm:"size:255"`
Code string `gorm:"uniqueIndex;size:50;not null"`
}
// 教师信息表(扩展用户表)
type Teacher struct {
gorm.Model
UserID uint `gorm:"uniqueIndex;not null"` // 必须关联用户
User User `gorm:"foreignKey:UserID"`
TeacherNumber string `gorm:"uniqueIndex;size:20;not null"`
Title string `gorm:"size:50"`
Introduction string `gorm:"type:text"`
DegreeLevel string `gorm:"size:50"`
EmploymentDate time.Time
SpecializedArea string `gorm:"size:100"`
}
// 院系表
type Department struct {
gorm.Model
Name string `gorm:"uniqueIndex;size:100;not null"`
Code string `gorm:"uniqueIndex;size:50;not null"`
Description string `gorm:"size:255"`
ParentID *uint
Parent *Department `gorm:"foreignKey:ParentID"`
}
// 专业表
type Major struct {
gorm.Model
Name string `gorm:"uniqueIndex;size:100;not null"`
Code string `gorm:"uniqueIndex;size:50;not null"`
Description string `gorm:"size:255"`
DepartmentID uint `gorm:"not null"` // 必须属于院系
Department Department `gorm:"foreignKey:DepartmentID"`
}
// 教室表(使用联合唯一索引)
type Classroom struct {
gorm.Model
Building string `gorm:"uniqueIndex:classroom_loc;size:50;not null"`
Floor int `gorm:"uniqueIndex:classroom_loc;not null"`
RoomNumber string `gorm:"uniqueIndex:classroom_loc;size:20;not null"`
Capacity int
IsMultimedia bool `gorm:"default:false"`
}
// 学期表
type Semester struct {
gorm.Model
Name string `gorm:"uniqueIndex;size:50;not null"`
StartDate time.Time
EndDate time.Time
IsActive bool `gorm:"index;default:false"`
}
// 课程表
type Course struct {
gorm.Model
Name string `gorm:"size:100;not null"`
Code string `gorm:"uniqueIndex;size:50;not null"`
Credits float32
Hours int
Description string `gorm:"size:255"`
MajorID uint `gorm:"not null"`
Major Major `gorm:"foreignKey:MajorID"`
}
// 课程排班表(优化时间字段)
type CourseSchedule struct {
gorm.Model
SemesterID uint `gorm:"index"`
Semester Semester `gorm:"foreignKey:SemesterID"`
CourseID uint `gorm:"index"`
Course Course `gorm:"foreignKey:CourseID"`
TeacherID uint `gorm:"index"`
Teacher Teacher `gorm:"foreignKey:TeacherID"`
ClassroomID uint
Classroom Classroom `gorm:"foreignKey:ClassroomID"`
DayOfWeek int `gorm:"not null;check:day_of_week BETWEEN 1 AND 7"`
StartTime string `gorm:"size:5;not null"` // 格式:"09:00"
EndTime string `gorm:"size:5;not null"` // 格式:"11:00"
StartWeek int `gorm:"not null;check:start_week >= 1"`
EndWeek int `gorm:"not null;check:end_week >= start_week"`
WeekType int `gorm:"default:0;check:week_type IN (0,1,2)"` // 0-不限 1-单周 2-双周
StudentClass string `gorm:"size:100"`
}
// 调课申请表(优化外键)
type CourseAdjustment struct {
gorm.Model
ScheduleID uint `gorm:"index"`
Schedule CourseSchedule `gorm:"foreignKey:ScheduleID"`
TeacherID uint `gorm:"index"`
Teacher Teacher `gorm:"foreignKey:TeacherID"`
OriginalDate time.Time `gorm:"type:date;not null"`
AdjustedDate time.Time `gorm:"type:date;not null"`
OriginalRoom *uint
OriginalClassroom Classroom `gorm:"foreignKey:OriginalRoom"`
NewRoom *uint
NewClassroom Classroom `gorm:"foreignKey:NewRoom"`
Reason string `gorm:"size:255;not null"`
Status int `gorm:"default:0;check:status IN (0,1,2)"`
ReviewerID *uint
Reviewer User `gorm:"foreignKey:ReviewerID"`
ReviewTime *time.Time
ReviewComments string `gorm:"size:255"`
}
// 请假申请表
type LeaveApplication struct {
gorm.Model
TeacherID uint `gorm:"index"`
Teacher Teacher `gorm:"foreignKey:TeacherID"`
StartDate time.Time `gorm:"not null"`
EndDate time.Time `gorm:"not null"`
LeaveType int `gorm:"not null"` // 1-病假 2-事假 3-其他
Reason string `gorm:"size:255;not null"`
Status int `gorm:"default:0"` // 0-待审核 1-已批准 2-已拒绝
ReviewerID *uint
Reviewer User `gorm:"foreignKey:ReviewerID"`
ReviewTime *time.Time
ReviewComments string `gorm:"size:255"`
AffectedCourses []CourseSchedule `gorm:"many2many:leave_affected_courses;"`
}
// 教师考勤记录表
type Attendance struct {
gorm.Model
TeacherID uint `gorm:"index"`
Teacher Teacher `gorm:"foreignKey:TeacherID"`
ScheduleID uint `gorm:"index"`
Schedule CourseSchedule `gorm:"foreignKey:ScheduleID"`
Date time.Time `gorm:"not null"`
Status int `gorm:"default:1"` // 1-正常 2-迟到 3-早退 4-缺勤 5-请假
RecordedBy *uint // 改为指针类型
Recorder User `gorm:"foreignKey:RecordedBy"`
Remarks string `gorm:"size:255"`
}
// 系统设置表
type SystemSetting struct {
gorm.Model
SettingKey string `gorm:"uniqueIndex;size:50;not null"`
SettingValue string `gorm:"type:text"`
Description string `gorm:"size:255"`
Type string `gorm:"size:20"` // text, number, boolean, json
}
// 公告表
type Announcement struct {
gorm.Model
Title string `gorm:"size:100;not null"`
Content string `gorm:"type:text;not null"`
StartDate time.Time `gorm:"not null"`
EndDate time.Time
IsImportant bool `gorm:"default:false"`
PublisherID uint
Publisher User `gorm:"foreignKey:PublisherID"`
TargetRoles []Role `gorm:"many2many:announcement_roles;"`
}
// GORM 数据库迁移函数
func AutoMigrate(db *gorm.DB) error {
// 禁用外键约束检查,解决迁移顺序问题
db.Exec("SET FOREIGN_KEY_CHECKS = 1")
err := db.AutoMigrate(
&User{},
&Role{},
&Permission{},
&Department{},
&Major{},
&Classroom{},
&Semester{},
&Course{},
&Teacher{},
&CourseSchedule{},
&CourseAdjustment{},
&LeaveApplication{},
&Attendance{},
&SystemSetting{},
&Announcement{},
)
// 重新启用外键约束
db.Exec("SET FOREIGN_KEY_CHECKS = 1")
return err
}
启动数据库的文件为server/config/database.go
package config
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"manager-server/model"
)
var DB *gorm.DB
// 初始化数据库连接 (包含连接池配置)
func InitDB() (*gorm.DB, error) {
// 从环境变量或配置文件读取
dbConfig := Cfg.Database
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
dbConfig.User,
dbConfig.Password,
dbConfig.Host,
dbConfig.Port,
dbConfig.DBName,
)
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
return nil, fmt.Errorf("数据库连接失败: %v", err)
}
// 配置连接池
sqlDB, _ := DB.DB()
sqlDB.SetMaxIdleConns(10) // 空闲连接数
sqlDB.SetMaxOpenConns(100) // 最大打开连接数
// 自动迁移数据库模型
// 检查是否需要迁移(只在表不存在时执行)
if !tableExists(DB) {
if err := models.AutoMigrate(DB); err != nil {
log.Fatalf("Database migration failed: %v", err)
}
log.Println("Database migration completed")
}
return DB,nil
}
// 获取数据库连接
func GetDB() *gorm.DB {
return DB
}
// 检查一个核心表是否存在,如果存在则假设数据库已经迁移
func tableExists(db *gorm.DB) bool {
return db.Migrator().HasTable(&models.User{}) &&
db.Migrator().HasTable(&models.Teacher{})
}
2025-03-26