github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgRedis/db.go (about) 1 package kmgRedis 2 3 import ( 4 "github.com/bronze1man/kmg/errors" 5 "gopkg.in/redis.v3" 6 "strconv" 7 "strings" 8 "time" 9 ) 10 11 var gClient *redis.Client 12 13 func DefaultInit() { 14 InitWithDbNum(0) 15 } 16 17 func TestInit() { 18 InitWithDbNum(1) 19 20 } 21 22 func InitWithConfig(opt *redis.Options) { 23 gClient = redis.NewClient(opt) 24 } 25 26 func InitWithDbNum(num int){ 27 gClient = redis.NewClient(&redis.Options{ 28 Network: "tcp", 29 Addr: "127.0.0.1:6379", 30 DB: int64(num), 31 }) 32 } 33 34 // 向redis中插入数据,如果已经存在数据会返回 ErrKeyExist 35 // 如果出现网络错误,会返回 一个网络错误的err 36 // 没有其他错误的可能性了. 37 func Insert(key string, value string) (err error) { 38 success, err := gClient.SetNX(key, value, 0).Result() 39 if err != nil { 40 return 41 } 42 if !success { 43 return ErrKeyExist 44 } 45 return nil 46 } 47 48 func MustInsert(key string, value string) { 49 err := Insert(key, value) 50 if err != nil { 51 panic(err) 52 } 53 } 54 55 // 数据不存在会返回 ErrKeyNotExist 56 // 网络错误会返回 error 57 func Update(key string, value string) (err error) { 58 cmd := redis.NewStatusCmd("SET", key, value, "XX") 59 gClient.Process(cmd) 60 _, err = cmd.Result() 61 if err == redis.Nil { 62 return ErrKeyNotExist 63 } 64 return err 65 } 66 67 func MustUpdate(key string, value string) { 68 err := Update(key, value) 69 if err != nil { 70 panic(err) 71 } 72 } 73 74 // key,不存在会insert,存在会update 75 // 网络错误会返回 error 76 // 注意redis类型错误时,也不会报错,只会把这个key设置成正确的value 77 func Set(key string, value string) (err error) { 78 return gClient.Set(key, value, 0).Err() 79 } 80 81 func MustSet(key string, value string) { 82 err := Set(key, value) 83 if err != nil { 84 panic(err) 85 } 86 } 87 88 type KeyValuePair struct { 89 Key string 90 Value string 91 } 92 93 // 经过实际测试发现一次只能写入1万个,太多会 broken pipe 94 func MustMSet(pairList []KeyValuePair) { 95 outPair := make([]string, len(pairList)*2) 96 for i, pair := range pairList { 97 outPair[2*i] = pair.Key 98 outPair[2*i+1] = pair.Value 99 } 100 err := gClient.MSet(outPair...).Err() 101 if err != nil { 102 panic(err) 103 } 104 } 105 106 // 从redis的kvdb中获取一个key 107 // 注意 value有可能是 "" 这个和数据不存在是两种情况. 108 // 如果数据不存在,会返回ErrKeyNotExist 109 // value在redis里面不是string类型,会返回 ErrStringWrongType 110 // 网络错误也会返回 error 111 func Get(key string) (value string, err error) { 112 value, err = gClient.Get(key).Result() 113 if err == nil { 114 return value, nil 115 } 116 if isRedisErrorWrongType(err) { 117 return "", ErrStringWrongType 118 } 119 if err == redis.Nil { 120 return "", ErrKeyNotExist 121 } 122 return "", err 123 } 124 125 func MustGet(key string) (value string) { 126 value, err := Get(key) 127 if err != nil { 128 panic(err) 129 } 130 return value 131 } 132 133 // 从redis的kvdb中获取一个key 134 // 将这个key转换成int 135 // 无法转换成int,会panic 136 // key不存在,返回0 137 // 网络错误会panic 138 func MustGetIntIgnoreNotExist(key string) (valueI int) { 139 value, err := Get(key) 140 if err == ErrKeyNotExist { 141 return 0 142 } 143 if err != nil { 144 panic(err) 145 } 146 valueI, err = strconv.Atoi(value) 147 if err != nil { 148 panic(err) 149 } 150 return valueI 151 } 152 153 // 从redis的kvdb中获取一个key 154 // 将这个key转换成float 155 // 无法转换成float,会panic 156 // key不存在,返回0 157 // 网络错误会panic 158 func MustGetFloatIgnoreNotExist(key string) float64 { 159 value, err := Get(key) 160 if err == ErrKeyNotExist { 161 return 0 162 } 163 if err != nil { 164 panic(err) 165 } 166 valueF, err := strconv.ParseFloat(value, 64) 167 if err != nil { 168 panic(err) 169 } 170 return valueF 171 } 172 173 // 只有网络问题会返回error 174 func Del(key string) (err error) { 175 return gClient.Del(key).Err() 176 } 177 178 func MustDel(key string) { 179 err := gClient.Del(key).Err() 180 if err!=nil{ 181 panic(err) 182 } 183 return 184 } 185 186 // 只有网络问题会返回error 187 func FlushDbV2() (err error) { 188 _, err = gClient.FlushDb().Result() 189 return err 190 } 191 func MustFlushDbV2() { 192 err := FlushDbV2() 193 if err != nil { 194 panic(err) 195 } 196 } 197 198 // 使用 redis的表达式搜索key,返回搜索到的key的列表 199 // 只有网络问题会返回error 200 // ** 仅适用于整个数据库key数量比较少的数据库(<500k条数据),否则非常慢. ** 201 func Keys(searchKey string) (keyList []string, err error) { 202 return gClient.Keys(searchKey).Result() 203 } 204 205 func MustKeys(searchKey string)(kList []string){ 206 kList,err:=Keys(searchKey) 207 if err!=nil{ 208 panic(err) 209 } 210 return kList 211 } 212 213 214 // 某个key是否存在 215 // 只有网络问题会返回error 216 func Exists(key string) (exist bool, err error) { 217 return gClient.Exists(key).Result() 218 } 219 220 /* 221 Insert all the specified values at the tail of the list stored at key. If key does not exist, it is created as empty list before performing the push operation. When key holds a value that is not a list, an error is returned. 222 更改的key存在,会向这个数组类型的key,右边加入一个元素. 223 更改的key不存在,会创建一个,并且写入第一个值. 224 更改的key的类型不正确会返回 ErrListWrongType 225 网络错误会返回error 226 */ 227 func RPush(key string, value string) (err error) { 228 err = gClient.RPush(key, value).Err() 229 if err == nil { 230 return nil 231 } 232 if isRedisErrorWrongType(err) { 233 return ErrListWrongType 234 } 235 return err 236 } 237 238 /* 239 返回一个redis数组里面所有的值. 240 查询的key存在,并且类型正确,返回列表里面的数据 241 查询的key不存在,返回空数组 TODO 好用? 242 查询的key类型错误,返回 ErrListWrongType 243 网络错误会返回error 244 */ 245 func LRangeAll(key string) (out []string, err error) { 246 out, err = gClient.LRange(key, 0, -1).Result() 247 if err == nil { 248 return out, nil 249 } 250 if isRedisErrorWrongType(err) { 251 return nil, ErrListWrongType 252 } 253 return nil, err 254 } 255 256 257 258 /* 259 一次操作,批量从redis里面返回大量key的值. 260 没有传入数据,不报错 261 如果查询的key全部存在,返回数据. 262 如果存在某一个key不存在,或者类型错误,返回 ErrKeyNotExist ,value里面什么也没有 (和redis命令不一致) 263 网络错误会返回error 264 */ 265 func MGetNotExistCheck(keyList []string) (value []string, err error) { 266 if len(keyList) == 0 { 267 return nil, nil 268 } 269 outList, err := gClient.MGet(keyList...).Result() 270 if err != nil { 271 return nil, err 272 } 273 value = make([]string, len(outList)) 274 for i, stringI := range outList { 275 s, ok := stringI.(string) 276 if !ok { 277 return nil, ErrKeyNotExist 278 } 279 value[i] = s 280 } 281 return value, nil 282 } 283 284 /* 285 带超时的设置一条数据 286 网络错误会返回error 287 */ 288 func SetEx(key string, dur time.Duration, value string) (err error) { 289 return gClient.Set(key, value, dur).Err() 290 } 291 292 func isRedisErrorWrongType(err error) bool { 293 return strings.Contains(err.Error(), "WRONGTYPE") 294 } 295 296 /* 297 改key的名字 298 key不存在 ErrKeyNotExist 299 key和newKey一样 ErrRenameSameName 300 newKey存在 ErrKeyExist 301 网络错误会返回error 302 */ 303 func RenameNx(key string, newKey string) (err error) { 304 retB, err := gClient.RenameNX(key, newKey).Result() 305 if err == nil { 306 if retB == false { 307 return ErrKeyExist 308 } 309 return 310 } 311 errS := err.Error() 312 if strings.Contains(errS, "ERR source and destination objects are the same") { 313 return ErrRenameSameName 314 } 315 if strings.Contains(errS, "ERR no such key") { 316 return ErrKeyNotExist 317 } 318 return err 319 } 320 321 /* 322 给某一个redis的key加一个整数 323 key不存在,会先把这个key变成0,然后再进行增加 324 key不能被解析成整数,会返回 ErrValueNotIntFormatOrOutOfRange 325 value不是string类型,会返回 ErrStringWrongType 326 网络错误会返回error 327 */ 328 func IncrBy(key string, num int64) (err error) { 329 err = gClient.IncrBy(key, num).Err() 330 if err != nil { 331 if isRedisErrorWrongType(err) { 332 return ErrStringWrongType 333 } 334 if strings.Contains(err.Error(), "ERR value is not an integer or out of range") { 335 return ErrValueNotIntFormatOrOutOfRange 336 } 337 return 338 } 339 return nil 340 } 341 342 /* 343 给某一个redis的key加一个浮点 344 不要传入大于1e200的浮点,会挂掉. TODO 解决这个问题? 345 key不存在,会先把这个key变成0,然后再进行增加 346 key不能被解析成整数,会返回 ErrValueNotFloatFormatOrOutOfRange 347 value不是string类型,会返回 ErrStringWrongType 348 网络错误会返回error 349 */ 350 func IncrByFloat(key string, num float64) (err error) { 351 err = gClient.IncrByFloat(key, num).Err() 352 if err != nil { 353 if isRedisErrorWrongType(err) { 354 return ErrStringWrongType 355 } 356 if strings.Contains(err.Error(), "ERR value is not a valid float") { 357 return ErrValueNotFloatFormat 358 } 359 return 360 } 361 return nil 362 } 363 364 // 1万个key扫描大概需要花费 10ms时间,如果这个东西性能是瓶颈.请尝试降低这个值. 365 var scanSize = 10000 366 367 // 扫描redis里面所有的key. 368 // 目前按照10000个一次的速度进行出来. 369 func ScanCallback(patten string, cb func(key string) error) (err error) { 370 var cursor int64 371 var keyList []string 372 for { 373 cursor, keyList, err = gClient.Scan(cursor, patten, int64(scanSize)).Result() 374 if err != nil { 375 return err 376 } 377 for _, key := range keyList { 378 err = cb(key) 379 if err != nil { 380 return err 381 } 382 } 383 if cursor == 0 { 384 return nil 385 } 386 } 387 } 388 389 var scanWithOutputLimitEOFError = errors.New("scanWithOutputLimitEOFError") 390 391 // 保证只会返回小于等于limit个数据. 392 func ScanWithOutputLimit(pattern string, limit int) (sList []string, err error) { 393 if limit == 0 { 394 return nil, nil 395 } 396 sList = make([]string, 0, limit) 397 err = ScanCallback(pattern, func(key string) error { 398 sList = append(sList, key) 399 if len(sList) >= limit { 400 return scanWithOutputLimitEOFError 401 } else { 402 return nil 403 } 404 }) 405 if err == scanWithOutputLimitEOFError { 406 return sList, nil 407 } 408 return sList, err 409 }