// 数据库底层操作接口 // 秒寻科技 // zt 2024-01-04 package mysqlapi import ( "encoding/json" "errors" "fmt" "ipsomc/core/dao/mysql/mysqlmodel" "ipsomc/util" "reflect" "strings" "time" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type MySqlApi struct { } // 全局数据库操作对象 var ( Db *gorm.DB ) // 初始化数据库模块,创建一个数据连接对象 func OpenSqlDb() error { var err error myViper := util.GetViper() dbHostAddress := myViper.GetString("dbDefault.dbHost") //主机地址 dbHostPort := myViper.GetString("dbDefault.dbPort") //主机端口 dbName := myViper.GetString("dbDefault.dbName") //数据库名 dbUser := myViper.GetString("dbDefault.dbUser") //数据库用户名 dbPassword := myViper.GetString("dbDefault.dbPassword") //数据库用户登录密码 //组织dsn字符串 dsn := dbUser + ":" + dbPassword + "@tcp(" + dbHostAddress + ":" + dbHostPort + ")/" + dbName + "?charset=utf8mb4&parseTime=True&loc=Local" //连接数据库 for Db, err = gorm.Open("mysql", dsn); err != nil; { fmt.Println("连接数据库异常,之后自动重连") time.Sleep(5 * time.Second) Db, err = gorm.Open("mysql", dsn) } Db.LogMode(true) //打开日志开关 Db.SingularTable(true) //禁用数据库表名复数 TimerConnectSqlDb(Db) //5秒定时连接数据库,以免连接断开 return nil } // CloseDb 关闭数据 func CloseSqlDb() { Db.Close() //关闭数据 } // GetDb 返回当前db对象 func (obj *MySqlApi) GetDb() *gorm.DB { return Db } // 创建数据库表,不会删除和修改数据库中的数据,只增加新新的表字段 func (obj *MySqlApi) GenerateDbTable(dataModel interface{}) { Db.AutoMigrate(dataModel) } // TimerConnectSqlDb 定时连接数据库 func TimerConnectSqlDb(db *gorm.DB) { go func() { myTiker := time.NewTicker(30 * time.Second) for range myTiker.C { var dtTime time.Time if err := db.Raw("select now() as time").Scan(&dtTime).Error; err != nil { fmt.Println(err) } } }() } // AddItem 增加数据库记录 func (obj *MySqlApi) AddItem(dataModel interface{}) error { if err := Db.Create(dataModel).Error; err != nil { return err } return nil } // UpdateItem 更新记录 func (obj *MySqlApi) UpdateItem(dataModel interface{}, dataMap map[string]interface{}) error { val := reflect.ValueOf(dataModel) if val.Kind() != reflect.Ptr { return errors.New("更新失败,函数参数检查错误,应为指针类型") } val = val.Elem() if val.Kind() != reflect.Struct { return errors.New("更新失败,函数参数检查错误,应为结构体指针类型") } id := val.FieldByName("ID").Int() if id == 0 { return errors.New("更新失败,请设置要更新的数据的ID值") } //更新数据 if err := Db.Model(dataModel).Updates(dataMap).Error; err != nil { return err } return nil } // DeleteItem 删除记录 func (obj *MySqlApi) DeleteItem(dataModel interface{}) error { val := reflect.ValueOf(dataModel) if val.Kind() != reflect.Ptr { return errors.New("删除失败,函数参数检查错误,应为指针类型") } val = val.Elem() if val.Kind() != reflect.Struct { return errors.New("删除失败,函数参数检查错误,应为结构体指针类型") } id := val.FieldByName("ID").Int() if id == 0 { return errors.New("删除失败,请设置要删除的数据的ID值") } if err := Db.Where("owner_id <> 0").Delete(dataModel).Error; err != nil { return err } return nil } // GetItemByID 根据id获得记录数据 func (obj *MySqlApi) GetItemByID(dataModel interface{}) error { val := reflect.ValueOf(dataModel) if val.Kind() != reflect.Ptr { return errors.New("查询数据失败,函数参数检查错误,应为指针类型") } val = val.Elem() if val.Kind() != reflect.Struct { return errors.New("查询数据失败,函数参数检查错误,应为结构体指针类型") } id := val.FieldByName("ID").Int() if id == 0 { return errors.New("查询数据失败,请设置要查询的数据的ID值") } if err := Db.First(dataModel).Error; err != nil { return err } return nil } // 组织公司参数(公司ID和项目ID) func (obj *MySqlApi) GenerateCompanyParam(db *gorm.DB, companyId int, projectId int) *gorm.DB { if companyId > 0 { db = db.Where("company_id=?", companyId) } if projectId > 0 { db = db.Where("project_id=?", projectId) } return db } // 组织search参数 func (obj *MySqlApi) GenerateSearchParam(db *gorm.DB, searchParam map[string]interface{}, dataMap map[string]interface{}) *gorm.DB { //组织Search参数 for queryKey, value := range searchParam { queryKey = strings.ToLower(queryKey) for mapKey := range dataMap { mapKey = strings.ToLower(mapKey) if mapKey == queryKey { db = db.Where(queryKey+"=?", value) } } } return db } // 组织Query参数 func (obj *MySqlApi) GenerateQueryParam(db *gorm.DB, queryParam []mysqlmodel.QueryParam, dataMap map[string]interface{}) *gorm.DB { wLen := len(queryParam) for i := 0; i < wLen; i++ { obj := queryParam[i] for mapKey := range dataMap { mapKey = strings.ToLower(mapKey) queryKey := strings.ToLower(obj.Key) if mapKey == queryKey { if obj.Opt == "like" { db = db.Where(queryKey+" like ?", fmt.Sprintf("%v", obj.Data)) //%通配在前端处理 } else if obj.Opt == "in" { db = db.Where(queryKey+" in (?)", obj.Data) } else { db = db.Where(queryKey+obj.Opt+"?", obj.Data) } } } } return db } // 组织Order参数 func (obj *MySqlApi) GenerateOrderParam(db *gorm.DB, orderBy string) *gorm.DB { strOrderBy := orderBy if len(strOrderBy) > 0 { orderList := strings.Split(strOrderBy, ",") for _, item := range orderList { db = db.Order(item) } } else { db = db.Order("id") //默认按照ID排序 } return db } // 组织查询条件where参数 func (obj *MySqlApi) GenerateWhereParam(dataModel interface{}, companyId int, projectId int, searchParam map[string]interface{}, queryParam []mysqlmodel.QueryParam, orderParam string) *gorm.DB { //空接口转map,以便判断查询字段是否在模型 dataMap := make(map[string]interface{}) byteList, _ := json.Marshal(dataModel) json.Unmarshal(byteList, &dataMap) db := obj.GetDb() db = obj.GenerateCompanyParam(db, companyId, projectId) //组织公司ID参数 db = obj.GenerateSearchParam(db, searchParam, dataMap) //组织Search参数 db = obj.GenerateQueryParam(db, queryParam, dataMap) //组织query参数 db = obj.GenerateOrderParam(db, orderParam) //组织排序参数 return db } // 查询 func (obj *MySqlApi) GetItemList(dataModel interface{}, listParam *mysqlmodel.ListParam, dataList interface{}) error { val := reflect.ValueOf(dataModel) if val.Kind() != reflect.Ptr { return errors.New("查询数据失败,函数参数检查错误,应为指针类型") } val = val.Elem() if val.Kind() != reflect.Struct { return errors.New("查询数据失败,函数参数检查错误,应为结构体指针类型") } //组织查询条件 db := obj.GenerateWhereParam(dataModel, listParam.CompanyID, listParam.ProjectID, listParam.Search, listParam.Query, listParam.OrderBy) //查询数据 if err := db.Find(dataList).Error; err != nil { return errors.New("查询数据失败") } return nil } // 分页查询 func (obj *MySqlApi) GetPageItemList(dataModel interface{}, listParam *mysqlmodel.PageListParam, dataList interface{}) (mysqlmodel.PageListData, error) { pageListData := mysqlmodel.PageListData{} pageListData.PageNum = listParam.PageNum pageListData.PageSize = listParam.PageSize offset := (listParam.PageNum - 1) * listParam.PageSize pageSize := listParam.PageSize //组织查询条件 db := obj.GenerateWhereParam(dataModel, listParam.CompanyID, listParam.ProjectID, listParam.Search, listParam.Query, listParam.OrderBy) //获得分页数据 if err := db.Limit(pageSize).Offset(offset).Find(dataList).Error; err != nil { return pageListData, err } pageListData.Items = dataList //计算总记录数 value := reflect.ValueOf(dataList).Elem() if listParam.PageNum == 1 && value.Len() < listParam.PageSize { //记录数不足一页 pageListData.TotalCount = value.Len() } else { db.Model(dataModel).Count(&pageListData.TotalCount) } return pageListData, nil }