forked from free-lancers/electricity_bill_calc_service
		
	feat(cache):实验性增加缓存操作函数。
This commit is contained in:
		
							
								
								
									
										8
									
								
								cache/abstract.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								cache/abstract.go
									
									
									
									
										vendored
									
									
								
							| @@ -10,6 +10,14 @@ import ( | |||||||
| 	"github.com/vmihailenco/msgpack/v5" | 	"github.com/vmihailenco/msgpack/v5" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	TAG_ENTITY  = "ENTITY" | ||||||
|  | 	TAG_COUNT   = "COUNT" | ||||||
|  | 	TAG_SEARCH  = "SEARCH" | ||||||
|  | 	TAG_EXISTS  = "CHECK" | ||||||
|  | 	TAG_SESSION = "SESSION" | ||||||
|  | ) | ||||||
|  |  | ||||||
| // 向Redis缓存中保存一个数据 | // 向Redis缓存中保存一个数据 | ||||||
| // ! 如果需要长期保存一个数据,那么需要向expires传入0。 | // ! 如果需要长期保存一个数据,那么需要向expires传入0。 | ||||||
| func Cache[T interface{}](key string, value *T, expires time.Duration) error { | func Cache[T interface{}](key string, value *T, expires time.Duration) error { | ||||||
|   | |||||||
							
								
								
									
										52
									
								
								cache/count.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								cache/count.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | package cache | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"electricity_bill_calc/global" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func assembleCountKey(entityName string) string { | ||||||
|  | 	var keys = make([]string, 0) | ||||||
|  | 	keys = append(keys, strings.ToUpper(entityName)) | ||||||
|  | 	return CacheKey(TAG_COUNT, keys...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func assembleCountIdentification(additional ...string) string { | ||||||
|  | 	var b strings.Builder | ||||||
|  | 	for _, s := range additional { | ||||||
|  | 		fmt.Fprintf(&b, ":%s", s) | ||||||
|  | 	} | ||||||
|  | 	return b.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 向缓存中缓存模型名称明确的包含指定条件的实体记录数量 | ||||||
|  | func CacheCount(entityName string, count int64, conditions ...string) error { | ||||||
|  | 	countKey := assembleCountKey(entityName) | ||||||
|  | 	identification := assembleCountIdentification(conditions...) | ||||||
|  | 	result := global.RedisConn.HSet(global.Ctx, countKey, map[string]interface{}{identification: count}) | ||||||
|  | 	return result.Err() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 从缓存中获取模型名称明确的,包含指定条件的实体记录数量 | ||||||
|  | func RetreiveCount(entityName string, condtions ...string) (int64, error) { | ||||||
|  | 	countKey := assembleCountKey(entityName) | ||||||
|  | 	identification := assembleCountIdentification(condtions...) | ||||||
|  | 	result := global.RedisConn.HGet(global.Ctx, countKey, identification) | ||||||
|  | 	if result.Err() != nil { | ||||||
|  | 		return -1, result.Err() | ||||||
|  | 	} | ||||||
|  | 	count, err := strconv.ParseInt(result.Val(), 10, 64) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return -1, err | ||||||
|  | 	} | ||||||
|  | 	return count, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 删除指定模型名称的数量缓存 | ||||||
|  | func AbolishCountEntity(entityName string) error { | ||||||
|  | 	countKey := assembleCountKey(entityName) | ||||||
|  | 	result := global.RedisConn.Del(global.Ctx, countKey) | ||||||
|  | 	return result.Err() | ||||||
|  | } | ||||||
							
								
								
									
										61
									
								
								cache/entity.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								cache/entity.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | |||||||
|  | package cache | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"electricity_bill_calc/global" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func assembleEntityKey(entityName, id string) string { | ||||||
|  | 	var keys = make([]string, 0) | ||||||
|  | 	keys = append(keys, TAG_ENTITY) | ||||||
|  | 	keys = append(keys, strings.ToUpper(entityName), id) | ||||||
|  | 	var b strings.Builder | ||||||
|  | 	for _, s := range keys { | ||||||
|  | 		fmt.Fprintf(&b, ":%s", s) | ||||||
|  | 	} | ||||||
|  | 	return b.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 缓存模型名称明确的,使用ID进行检索的实体内容。 | ||||||
|  | func CacheEntity[T any](instance T, entityName, id string) error { | ||||||
|  | 	entityKey := assembleEntityKey(entityName, id) | ||||||
|  | 	err := Cache(entityKey, &instance, 0) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 从缓存中取出模型名称明确的,使用ID进行检索的实体内容。 | ||||||
|  | func RetreiveEntity[T any](entityName, id string) (T, error) { | ||||||
|  | 	entityKey := assembleEntityKey(entityName, id) | ||||||
|  | 	instance, err := Retreive[T](entityKey) | ||||||
|  | 	return *instance, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 精确的从缓存中删除指定模型名称、指定ID的实体内容。 | ||||||
|  | func AbolishSpecificEntity(entityName, id string) (bool, error) { | ||||||
|  | 	entityKey := assembleEntityKey(entityName, id) | ||||||
|  | 	return Delete(entityKey) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 从缓存中删除指定模型名称的所有内容。 | ||||||
|  | func AbolishEntity(entityName string) error { | ||||||
|  | 	var ( | ||||||
|  | 		cursor uint64 | ||||||
|  | 		keys   = make([]string, 0) | ||||||
|  | 	) | ||||||
|  | 	pattern := fmt.Sprintf("%s:%s:*", TAG_ENTITY, strings.ToUpper(entityName)) | ||||||
|  | 	for { | ||||||
|  | 		k, cursor, err := global.RedisConn.Scan(global.Ctx, cursor, pattern, 20).Result() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		keys = append(keys, k...) | ||||||
|  | 		if cursor == 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	pipeline := global.RedisConn.Pipeline() | ||||||
|  | 	pipeline.Del(global.Ctx, keys...) | ||||||
|  | 	_, err := pipeline.Exec(global.Ctx) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
							
								
								
									
										70
									
								
								cache/exists.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								cache/exists.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | package cache | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"electricity_bill_calc/global" | ||||||
|  | 	"electricity_bill_calc/tools" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func assembleExistsKey(entityName string) string { | ||||||
|  | 	var keys = make([]string, 0) | ||||||
|  | 	keys = append(keys, strings.ToUpper(entityName)) | ||||||
|  | 	return CacheKey(TAG_EXISTS, keys...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func assembleExistsIdentification(id string, additional ...string) string { | ||||||
|  | 	var b strings.Builder | ||||||
|  | 	b.WriteString(id) | ||||||
|  | 	for _, s := range additional { | ||||||
|  | 		fmt.Fprintf(&b, ":%s", s) | ||||||
|  | 	} | ||||||
|  | 	return b.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 缓存模型名称明确的、包含指定ID以及一些附加条件的记录 | ||||||
|  | func CacheExists(entityName, id string, conditions ...string) error { | ||||||
|  | 	existskey := assembleExistsKey(entityName) | ||||||
|  | 	identification := assembleExistsIdentification(id, conditions...) | ||||||
|  | 	result := global.RedisConn.SAdd(global.Ctx, existskey, identification) | ||||||
|  | 	return result.Err() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 从缓存中获取模型名称明确、包含指定ID以及一些附加条件的实体是否存在的标记,函数在返回false时不保证数据库中相关记录也不存在 | ||||||
|  | func CheckExists(entityName, id string, condtions ...string) (bool, error) { | ||||||
|  | 	existsKey := assembleExistsKey(entityName) | ||||||
|  | 	identification := assembleExistsIdentification(id, condtions...) | ||||||
|  | 	result := global.RedisConn.SIsMember(global.Ctx, existsKey, identification) | ||||||
|  | 	return result.Val(), result.Err() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 从缓存中删除模型名称明确、包含指定ID的全部实体存在标记 | ||||||
|  | func AbolishExists(entityName, id string) error { | ||||||
|  | 	existsKey := assembleExistsKey(entityName) | ||||||
|  | 	pattern := fmt.Sprintf("%s*", id) | ||||||
|  | 	var ( | ||||||
|  | 		cursor uint64 | ||||||
|  | 		elems  = make([]string, 0) | ||||||
|  | 	) | ||||||
|  | 	for { | ||||||
|  | 		k, cursor, err := global.RedisConn.SScan(global.Ctx, existsKey, cursor, pattern, 20).Result() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		elems = append(elems, k...) | ||||||
|  | 		if cursor == 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	pipeline := global.RedisConn.Pipeline() | ||||||
|  | 	pipeline.SRem(global.Ctx, existsKey, tools.ConvertSliceToInterfaceSlice(elems)...) | ||||||
|  | 	_, err := pipeline.Exec(global.Ctx) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 从缓存中删除指定模型名称的全部存在标记 | ||||||
|  | func AbolishExistsEntity(entityName string) error { | ||||||
|  | 	existskey := assembleExistsKey(entityName) | ||||||
|  | 	result := global.RedisConn.Del(global.Ctx, existskey) | ||||||
|  | 	return result.Err() | ||||||
|  | } | ||||||
							
								
								
									
										56
									
								
								cache/search.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								cache/search.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | package cache | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"electricity_bill_calc/global" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func assembleSearchKey(entityName string, additional ...string) string { | ||||||
|  | 	var keys = make([]string, 0) | ||||||
|  | 	keys = append(keys, TAG_SEARCH) | ||||||
|  | 	keys = append(keys, strings.ToUpper(entityName)) | ||||||
|  | 	keys = append(keys, additional...) | ||||||
|  | 	var b strings.Builder | ||||||
|  | 	for _, s := range keys { | ||||||
|  | 		fmt.Fprintf(&b, ":%s", s) | ||||||
|  | 	} | ||||||
|  | 	return b.String() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 缓存模型名称明确的,使用或者包含非ID检索条件的实体内容。 | ||||||
|  | func CacheSearch[T any](instance T, entityName string, conditions ...string) error { | ||||||
|  | 	searchKey := assembleSearchKey(entityName, conditions...) | ||||||
|  | 	err := Cache(searchKey, &instance, 0) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 从缓存中取得模型名称明确的,使用或者包含非ID检索条件的实体内容。 | ||||||
|  | func RetreiveSearch[T any](entityName string, conditions ...string) (T, error) { | ||||||
|  | 	searchKey := assembleSearchKey(entityName, conditions...) | ||||||
|  | 	instance, err := Retreive[T](searchKey) | ||||||
|  | 	return *instance, err | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 从缓存中删除全部指定模型名称的实体内容。 | ||||||
|  | func AbolishSearch(entityName string) error { | ||||||
|  | 	var ( | ||||||
|  | 		cursor uint64 | ||||||
|  | 		keys   = make([]string, 0) | ||||||
|  | 	) | ||||||
|  | 	pattern := fmt.Sprintf("%s:%s:*", TAG_SEARCH, strings.ToUpper(entityName)) | ||||||
|  | 	for { | ||||||
|  | 		k, cursor, err := global.RedisConn.Scan(global.Ctx, cursor, pattern, 20).Result() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		keys = append(keys, k...) | ||||||
|  | 		if cursor == 0 { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	pipeline := global.RedisConn.Pipeline() | ||||||
|  | 	pipeline.Del(global.Ctx, keys...) | ||||||
|  | 	_, err := pipeline.Exec(global.Ctx) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								cache/session.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								cache/session.go
									
									
									
									
										vendored
									
									
								
							| @@ -9,7 +9,7 @@ import ( | |||||||
|  |  | ||||||
| func SessionKey(keys ...string) string { | func SessionKey(keys ...string) string { | ||||||
| 	var b strings.Builder | 	var b strings.Builder | ||||||
| 	b.WriteString("session") | 	b.WriteString(TAG_SESSION) | ||||||
| 	for _, s := range keys { | 	for _, s := range keys { | ||||||
| 		fmt.Fprintf(&b, ":%s", s) | 		fmt.Fprintf(&b, ":%s", s) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -30,3 +30,11 @@ func ConvertStructToMap[T any](origin T) map[string]interface{} { | |||||||
| 	json.Unmarshal(incr, &dest) | 	json.Unmarshal(incr, &dest) | ||||||
| 	return dest | 	return dest | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func ConvertSliceToInterfaceSlice[T any](origin []T) []interface{} { | ||||||
|  | 	dest := make([]interface{}, len(origin)) | ||||||
|  | 	for i, e := range origin { | ||||||
|  | 		dest[i] = e | ||||||
|  | 	} | ||||||
|  | 	return dest | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user