redisutil.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /**
  2. redis_util Redis工具包<br/>
  3. 作者:hongbo<br/>
  4. 日期:2020-4-22<br/>
  5. */
  6. package redis_util
  7. import (
  8. "encoding/json"
  9. "errors"
  10. "log"
  11. "runtime"
  12. "strings"
  13. "time"
  14. redigo "github.com/garyburd/redigo/redis"
  15. )
  16. // RedisPool redis 多服务端连接池,1个应用同时连接多个redis服务
  17. var RedisPool map[string]*redigo.Pool
  18. // 初始化redis 多端连接池 <br/>
  19. // @param addrs enterprise=192.168.3.14:1379,service=192.168.3.14:2379,other=192.168.3.14:3379
  20. func InitRedis(addrs string) {
  21. InitRedisBySize(addrs, 300, 30, 240)
  22. }
  23. // 初始化redis连接池,支持多个redis库
  24. func InitRedisBySize(addrs string, maxSize, maxIdle, timeout int) {
  25. RedisPool = map[string]*redigo.Pool{}
  26. addr := strings.Split(addrs, ",")
  27. for _, v := range addr {
  28. saddr := strings.Split(v, "=")
  29. RedisPool[saddr[0]] = &redigo.Pool{MaxActive: maxSize, MaxIdle: maxIdle,
  30. IdleTimeout: time.Duration(timeout) * time.Second, Dial: func() (redigo.Conn, error) {
  31. return redigo.Dial("tcp", saddr[1])
  32. }}
  33. }
  34. }
  35. // 分流redis ,并存入字符串缓存
  36. func PutKV(key string, obj interface{}) bool {
  37. return Put("other", key, obj, -1)
  38. }
  39. // 存储KV对,并设置永不超时
  40. func PutCKV(code, key string, obj interface{}) bool {
  41. return Put(code, key, obj, -1)
  42. }
  43. // 存储KV对,可设置超时时间,单位秒
  44. func Put(code, key string, obj interface{}, timeout int) bool {
  45. b := false
  46. defer catch()
  47. conn := RedisPool[code].Get()
  48. defer conn.Close()
  49. var err error
  50. _obj, _err := json.Marshal(obj)
  51. if _err != nil {
  52. log.Println("redisutil-SET-序列化出错Error", _err)
  53. return b
  54. }
  55. if timeout < 1 {
  56. _, err = conn.Do("SET", key, _obj)
  57. } else {
  58. _, err = conn.Do("SET", key, _obj, "EX", timeout)
  59. }
  60. if nil != err {
  61. log.Println("redisutil-SETError-put", err)
  62. } else {
  63. b = true
  64. }
  65. return b
  66. }
  67. // 批量存储KV对,可指定超时时间,obj格式=[[key,value],,,]
  68. func BulkPut(code string, timeout int, obj ...interface{}) bool {
  69. b := false
  70. defer catch()
  71. conn := RedisPool[code].Get()
  72. defer conn.Close()
  73. var err error
  74. for _, _tmp := range obj {
  75. tmp, ok := _tmp.([]interface{})
  76. if ok && len(tmp) == 2 {
  77. key, kok := tmp[0].(string)
  78. if kok && key != "" {
  79. _obj, _err := json.Marshal(tmp[1])
  80. if _err != nil {
  81. log.Println("redisutil-SET-序列化出错Error", _err)
  82. return b
  83. }
  84. if timeout < 1 {
  85. _, err = conn.Do("SET", key, _obj)
  86. } else {
  87. _, err = conn.Do("SET", key, _obj, "EX", timeout)
  88. }
  89. }
  90. }
  91. }
  92. if nil != err {
  93. b = false
  94. log.Println("redisutil-SETError-put", err)
  95. } else {
  96. b = b && true
  97. }
  98. return b
  99. }
  100. // 存储KV对,Value是字节数组,可指定超时时间
  101. func PutBytes(code, key string, data *[]byte, timeout int) (err error) {
  102. defer catch()
  103. conn := RedisPool[code].Get()
  104. defer conn.Close()
  105. if timeout < 1 {
  106. _, err = conn.Do("SET", key, *data)
  107. } else {
  108. _, err = conn.Do("SET", key, *data, "EX", timeout)
  109. }
  110. if nil != err {
  111. log.Println("redisutil-SETError", err)
  112. }
  113. return
  114. }
  115. // 设置超时时间,单位秒
  116. func SetExpire(code, key string, expire int) error {
  117. defer catch()
  118. conn := RedisPool[code].Get()
  119. defer conn.Close()
  120. _, err := conn.Do("expire", key, expire)
  121. return err
  122. }
  123. // 判断一个key是否存在
  124. func Exists(code, key string) (bool, error) {
  125. defer catch()
  126. conn := RedisPool[code].Get()
  127. defer conn.Close()
  128. repl, err := conn.Do("exists", key)
  129. ret, _ := redigo.Int(repl, err)
  130. return ret == 1, err
  131. }
  132. // 依据Key,获取Value 自动转化为字符串格式
  133. func GetStr(code, key string) string {
  134. res := Get(code, key)
  135. str, _ := res.(string)
  136. return str
  137. }
  138. // 依据Key,获取Value 自动转化为int格式
  139. func GetInt(code, key string) int {
  140. result, _ := GetNewInt(code, key)
  141. return result
  142. }
  143. // 依据Key,获取Value 兼容int类型数据将自动转换
  144. func GetNewInt(code, key string) (int, error) {
  145. var res interface{}
  146. err := GetNewInterface(code, key, &res)
  147. var result int
  148. if str, ok := res.(float64); ok {
  149. result = int(str)
  150. }
  151. return result, err
  152. }
  153. // 依据Key,获取字符串,返回interface{},需要自己断言
  154. func Get(code, key string) (result interface{}) {
  155. GetInterface(code, key, &result)
  156. return
  157. }
  158. // NOTE: 建议使用GetNewInterface
  159. // 依据Key,获取字符串,返回interface{} 为兼容老代码所写
  160. func GetInterface(code, key string, result interface{}) {
  161. GetNewInterface(code, key, result)
  162. }
  163. // NOTE:注意result必须为指针对象
  164. // 依据Key,获取字符串,返回interface{} ,基础方法,部分外部接口依赖此方法
  165. func GetNewInterface(code, key string, result interface{}) error {
  166. defer catch()
  167. conn := RedisPool[code].Get()
  168. defer conn.Close()
  169. ret, err := conn.Do("GET", key)
  170. if nil != err {
  171. log.Println("redisutil-GetError", err)
  172. } else {
  173. var ok bool
  174. var res []byte
  175. if res, ok = ret.([]byte); ok {
  176. err = json.Unmarshal(res, result)
  177. if err != nil {
  178. log.Println("Get ERROR:", err.Error())
  179. }
  180. }
  181. }
  182. return err
  183. }
  184. // 依据Key,获取字节数组
  185. func GetBytes(code, key string) (ret *[]byte, err error) {
  186. defer catch()
  187. conn := RedisPool[code].Get()
  188. defer conn.Close()
  189. var r interface{}
  190. r, err = conn.Do("GET", key)
  191. if err != nil {
  192. log.Println("redisutil-GetBytesError", err)
  193. } else {
  194. if tmp, ok := r.([]byte); ok {
  195. ret = &tmp
  196. } else {
  197. err = errors.New("redis返回数据格式不对")
  198. }
  199. }
  200. return
  201. }
  202. // FIXME: 写注释,表示很忧伤,GetNewBytes/GetBytes的实现,没看出来差异啊
  203. // 依据Key,获取字节数组
  204. func GetNewBytes(code, key string) (ret *[]byte, err error) {
  205. defer catch()
  206. redisPool := RedisPool[code]
  207. if redisPool == nil {
  208. err = errors.New("redis code " + code + " is nil")
  209. log.Println("redisutil-GetNewBytesError", err)
  210. return
  211. }
  212. conn := redisPool.Get()
  213. defer conn.Close()
  214. var r interface{}
  215. r, err = conn.Do("GET", key)
  216. if err != nil {
  217. log.Println("redisutil-GetNewBytesError", err)
  218. } else if r != nil {
  219. if tmp, ok := r.([]byte); ok {
  220. ret = &tmp
  221. }
  222. }
  223. return
  224. }
  225. // 删所有key,清理Redis库
  226. func FlushDB(code string) bool {
  227. b := false
  228. defer catch()
  229. conn := RedisPool[code].Get()
  230. defer conn.Close()
  231. var err error
  232. _, err = conn.Do("FLUSHDB")
  233. if nil != err {
  234. log.Println("redisutil-FLUSHDBError", err)
  235. } else {
  236. b = true
  237. }
  238. return b
  239. }
  240. // 批量删除多个key
  241. // NOTE: key 为变参
  242. func Del(code string, key ...interface{}) bool {
  243. defer catch()
  244. b := false
  245. conn := RedisPool[code].Get()
  246. defer conn.Close()
  247. var err error
  248. _, err = conn.Do("DEL", key...)
  249. if nil != err {
  250. log.Println("redisutil-DELError", err)
  251. } else {
  252. b = true
  253. }
  254. return b
  255. }
  256. // 根据key前辍,批量删除
  257. // NOTE: key前缀 如:key*
  258. func DelByCodePattern(code, key string) {
  259. defer catch()
  260. conn := RedisPool[code].Get()
  261. defer conn.Close()
  262. ret, err := conn.Do("KEYS", key)
  263. var result []interface{}
  264. if nil != err {
  265. log.Println("redisutil-GetError", err)
  266. } else {
  267. result = ret.([]interface{})
  268. for k := 0; k < len(result); k++ {
  269. conn.Do("DEL", string(result[k].([]uint8)))
  270. }
  271. }
  272. }
  273. // 指定key,自增计数,并返回增加后的值
  274. func Incr(code, key string) int64 {
  275. defer catch()
  276. conn := RedisPool[code].Get()
  277. defer conn.Close()
  278. ret, err := conn.Do("INCR", key)
  279. if nil != err {
  280. log.Println("redisutil-INCR-Error", err)
  281. } else {
  282. if res, ok := ret.(int64); ok {
  283. return res
  284. } else {
  285. return 0
  286. }
  287. }
  288. return 0
  289. }
  290. // 指定key,自减计数,并返回增加后的值
  291. func Decrby(code, key string, val int) int64 {
  292. defer catch()
  293. conn := RedisPool[code].Get()
  294. defer conn.Close()
  295. ret, err := conn.Do("DECRBY", key, val)
  296. if nil != err {
  297. log.Println("redisutil-DECR-Error", err)
  298. } else {
  299. if res, ok := ret.(int64); ok {
  300. return res
  301. } else {
  302. return 0
  303. }
  304. }
  305. return 0
  306. }
  307. // 根据正则key,获取结果
  308. func GetKeysByPattern(code, key string) []interface{} {
  309. defer catch()
  310. conn := RedisPool[code].Get()
  311. defer conn.Close()
  312. ret, err := conn.Do("KEYS", key)
  313. if nil != err {
  314. log.Println("redisutil-GetKeysError", err)
  315. return nil
  316. } else {
  317. res, _ := ret.([]interface{})
  318. return res
  319. }
  320. }
  321. // 批量取多个key的值
  322. func Mget(code string, key []string) []interface{} {
  323. defer catch()
  324. conn := RedisPool[code].Get()
  325. defer conn.Close()
  326. interfaceKeys := make([]interface{}, len(key))
  327. for n, k := range key {
  328. interfaceKeys[n] = k
  329. }
  330. ret, err := conn.Do("MGET", interfaceKeys...)
  331. if nil != err {
  332. log.Println("redisutil-MgetError", err)
  333. return nil
  334. } else {
  335. res, _ := ret.([]interface{})
  336. return res
  337. }
  338. }
  339. // 常规KV,出栈操作,查询指定Key,返回Value后,删除此KV对
  340. func Pop(code string, key string) (result interface{}) {
  341. defer catch()
  342. conn := RedisPool[code].Get()
  343. defer conn.Close()
  344. ret, err := conn.Do("GET", key)
  345. if nil != err {
  346. log.Println("redisutil-PopError", err)
  347. } else {
  348. var ok bool
  349. var res []byte
  350. if res, ok = ret.([]byte); ok {
  351. err = json.Unmarshal(res, &result)
  352. if err != nil {
  353. log.Println("Poperr", err)
  354. }
  355. }
  356. conn.Do("DEL", key)
  357. }
  358. return
  359. }
  360. // List数据 KV,队首出栈操作,对应RPOP队尾出栈
  361. func LPOP(code, list string) (result interface{}) {
  362. defer catch()
  363. conn := RedisPool[code].Get()
  364. defer conn.Close()
  365. ret, err := conn.Do("LPOP", list)
  366. if nil != err {
  367. log.Println("redisutil-LPopError", err)
  368. } else {
  369. if res, ok := ret.([]byte); ok {
  370. err = json.Unmarshal(res, &result)
  371. log.Println(err)
  372. }
  373. }
  374. return
  375. }
  376. // List数据 后端入栈,在List末尾追加数据 对应LPUSH在队首插入数据
  377. func RPUSH(code, list string, val interface{}) bool {
  378. defer catch()
  379. conn := RedisPool[code].Get()
  380. defer conn.Close()
  381. _obj, _ := json.Marshal(val)
  382. _, err := conn.Do("RPUSH", list, _obj)
  383. if nil != err {
  384. log.Println("redisutil-RPUSHError", err)
  385. return false
  386. }
  387. return true
  388. }
  389. // List数据长度
  390. func LLEN(code, list string) int64 {
  391. defer catch()
  392. conn := RedisPool[code].Get()
  393. defer conn.Close()
  394. ret, err := conn.Do("LLEN", list)
  395. if nil != err {
  396. log.Println("redisutil-LLENError", err)
  397. return 0
  398. }
  399. if res, ok := ret.(int64); ok {
  400. return res
  401. } else {
  402. return 0
  403. }
  404. }
  405. func catch() {
  406. if r := recover(); r != nil {
  407. log.Println(r)
  408. for skip := 0; ; skip++ {
  409. _, file, line, ok := runtime.Caller(skip)
  410. if !ok {
  411. break
  412. }
  413. go log.Printf("%v,%v\n", file, line)
  414. }
  415. }
  416. }