package SqlKit import ( "dsSupport/Const/ErrorConst" "dsSupport/Utils/CommonUtil" "dsSupport/Utils/ConfigUtil" "dsSupport/Utils/DbUtil" "dsSupport/Utils/LogUtil" "dsSupport/Utils/RedisUtil" "encoding/json" "fmt" "github.com/go-redis/redis/v7" "github.com/xormplus/builder" "reflect" "strconv" "strings" "time" ) //操作数据库的变量 var db = DbUtil.Engine /** 功能:通用的批量删除功能(逻辑) 作者:黄海 时间:2020-05-29 */ func DeleteIds(tableName string, ids []string) error { //1、清除Redis缓存 var selector = GetBean(tableName) DeleteCacheByIds(ids, selector) //2、获取此表的主键 _, PkField := GetTablePk(tableName) //3、批量删除 // -1:未启用,-2:删除 var myBuilder = builder.Dialect(builder.MYSQL).Update(builder.Eq{"b_use": -2}).From(tableName).Where(builder.In(PkField, ids)) sql, _ := myBuilder.ToBoundSQL() _, err := db.SQL(sql).Execute() return err } /** 功能:优先从缓存读取,检查到缺失的,就从数据库读取,然后两个结果集拼接后返回,同时将缺失的缓存补全 作者:黄海 时间:2020-02-05 */ func QueryByIds(ids []string, tableName string) []map[string]interface{} { return getListByIds(ids, GetBean(tableName)) } func getListByIds(ids []string, m Selector) []map[string]interface{} { //1、第一步从缓存读取 list, notExistsIds := batchReadRedis(ids, m.RedisPrefix) //2、如果有一些ID在缓存中不存在,那么需要从数据库中查询,然后填充到缓存中 if notExistsIds != nil && len(notExistsIds) > 0 { //从数据库中获取缺失的数据 lostCacheList := fromDb(notExistsIds, m) //缓存写入 batchWriteRedis(lostCacheList, m) //再次查询,应该是全的了~~,之所以修改成这样, //是因为如果从数据库取回的直接与缓存中的两个结果集进行拼接的话,数据库取回的数据类型可能不一致。 list, _ = batchReadRedis(ids, m.RedisPrefix) } return list } /** 功能:删除指定ID的缓存 作者:黄海 时间:2020-02-21 */ func DeleteCacheByIds(ids []string, m Selector) { prefix := m.RedisPrefix for i := 0; i < len(ids); i++ { id := ids[i] key := prefix + id RedisUtil.DEL(key) } } /*===================以下为内部函数,用于扩展从REDIS缓存中查询===========================*/ func fromDb(idAry []string, m Selector) []map[string]interface{} { tableName := m.TableName pkField := m.PkField //查询数据库 ids := strings.Join(idAry, "','") sqlRaw := fmt.Sprintf(`select * from `+tableName+` where `+pkField+` in ('%s')`, ids) results, err := db.SQL(sqlRaw).Query().List() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, "从数据库中读取数据失败:"+err.Error()) } return results } /** 功能:批量写入缓存 作者:黄海 时间:2020-02-05 */ func batchWriteRedis(list []map[string]interface{}, m Selector) { pkField := m.PkField prefix := m.RedisPrefix //声明管道 pipe := RedisUtil.RedisClient.Pipeline() for i := 0; i < len(list); i++ { bean := list[i] var pkSuffix = "" switch bean[pkField].(type) { case string: pkSuffix = bean[pkField].(string) case int64: pkSuffix = strconv.FormatInt(reflect.ValueOf(bean[pkField]).Int(), 10) } key := prefix + pkSuffix jsonStr, _ := json.Marshal(bean) pipe.Set(key, jsonStr, 24*time.Hour) } //执行管道 pipe.Exec() } /** 功能:从REDIS中批量获取指定ID的列表信息 作者:黄海 时间:2020-02-05 */ func batchReadRedis(ids []string, prefix string) ([]map[string]interface{}, []string) { //1、创建管道 var list []*redis.StringCmd pipe := RedisUtil.RedisClient.Pipeline() for i := 0; i < len(ids); i++ { list = append(list, pipe.Get(prefix+ids[i])) } //2、执行管道 pipe.Exec() //存在于缓存中的数据 var existList []map[string]interface{} //不存在的主键有哪些 var notExistsIds []string //3、输出结果 for i := 0; i < len(list); i++ { _bean := list[i].Val() if len(_bean) > 0 { n := CommonUtil.ConvertJsonStringToMap(_bean) //找到了加到返回值列表中去 existList = append(existList, n) } else { notExistsIds = append(notExistsIds, ids[i]) } } //返回值 return existList, notExistsIds } /** 功能:对于简单表提供分页的通用SQL组装方法,返回通用分页的SQL语句和获取查询总数的SQL语句 作者:黄海 时间:2020-02-21 */ func Count(baseSql string) (int32, error) { //转小写 baseSql = strings.ToLower(baseSql) //截取去掉最后面的 limit ? baseSql = strings.Split(baseSql, " limit ")[0] countSql := "select count(1) as count from (" + baseSql + ") as t100" var count int32 _, err := db.SQL(countSql).Get(&count) if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) return 0, err } return count, nil } /** 功能:判断一个sql是不是多表关联查询 作者:黄海 时间:2020-06-10 */ func isMultiFieldSql(sql string) bool { sql = strings.ToLower(sql) if strings.Index(sql, " join ") > 0 { return true } else { return false } } /** 功能:是不是带有distinct的sql 作者:黄海 时间:2020-06-12 */ func isDistinctSql(sql string) bool { sql = strings.ToLower(sql) if strings.Index(sql, " distinct ") > 0 { return true } else { return false } } /** 功能:通用的SQL查询办法 作者:黄海 时间:2020-06-10 */ func Query(sql string) ([]map[string]interface{}, int32, error) { if isMultiFieldSql(sql) || isDistinctSql(sql) { return pageSql(sql) } else { return pageCache(sql) } } /** 功能:对于查询SQL,返回查询结果,并返回 作者:黄海 时间:2020-03-25 */ func pageSql(sql string) ([]map[string]interface{}, int32, error) { //总数 count, err := Count(sql) if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) return nil, 0, err } //数据 list, err := db.SQL(sql).Query().List() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) return nil, 0, err } return list, count, nil } /** 功能:分页(按指定的SQL,只有主键,可以使用缓存) 作者:黄海 时间:2020-06-10 */ func pageCache(sql string) ([]map[string]interface{}, int32, error) { var model Selector //删除多余的空格 sql = CommonUtil.DeleteExtraSpace(sql) arr := strings.Split(sql, " ") for i := 0; i < len(arr)-1; i++ { if strings.ToLower(arr[i]) == "from" { model = GetBean(arr[i+1]) break } } //分页数据 list, err := db.SQL(sql).Query().List() if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) return nil, 0, err } //总数 count, err := Count(sql) if err != nil { LogUtil.Error(ErrorConst.SqlQueryError, err.Error()) return nil, 0, err } //有哪些ids? var ids = CommonUtil.Ids(list, model.PkField) //-->缓存层-->数据库-->缓存 list = getListByIds(ids, model) return list, count, nil } /** 功能:获取指定的表有哪些列 作者:黄海 时间:2020-6-12 */ func GetTableColumns(tableName string) ([]map[string]interface{}, error) { sql := `select COLUMN_NAME from information_schema.COLUMNS where table_name = ? and table_schema = '` + ConfigUtil.MysqlDataBase + `'` return db.SQL(sql, tableName).Query().List() } /** 功能:获取指定表的成批提交的大小 作者:黄海 时间:2020-06-12 */ func GetTableBatchSize(tableName string) int { var maxFileds = 65535 //计算每个批次的大小 list, _ := GetTableColumns(tableName) batchSize := maxFileds / len(list) return batchSize }