You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
7.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}