Apply .gitignore rules
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
package sqlAsyncMgr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
||||
"goutil/logUtil"
|
||||
"goutil/stringUtil"
|
||||
)
|
||||
|
||||
// sql异步util类
|
||||
type SqlAsyncUtil struct {
|
||||
// 文件路径
|
||||
filePath string
|
||||
|
||||
// 名称
|
||||
name string
|
||||
|
||||
// 工作者最大数量
|
||||
max_Worker_Nums int32
|
||||
|
||||
// 工作池
|
||||
workerPool *SqlAsyncWorkerPool
|
||||
|
||||
// 缓存统计
|
||||
sqlStatistics *SqlAsyncIdentityStatistics
|
||||
|
||||
// 日志处理方法
|
||||
logAction func(logUtil.LogType, string)
|
||||
|
||||
// db驱动
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
// NewSqlAsyncUtil 创建新SqlAsyncUtil对象
|
||||
func NewSqlAsyncUtil(_name, _filePath string, maxWorker int32, dbConnectionStr string, _logAction func(logUtil.LogType, string)) *SqlAsyncUtil {
|
||||
if stringUtil.IsEmpty(_name) || stringUtil.IsEmpty(_filePath) || stringUtil.IsEmpty(dbConnectionStr) {
|
||||
panic(fmt.Sprintf("NewSqlAsyncUtil方法_name/_filePath/dbConnectionStr参数不能为空"))
|
||||
}
|
||||
if maxWorker <= 0 {
|
||||
panic(fmt.Sprintf("NewSqlAsyncUtil方法maxWorker参数必须>0"))
|
||||
}
|
||||
if _logAction == nil {
|
||||
panic(fmt.Sprintf("NewSqlAsyncUtil方法_logAction参数并能为nil"))
|
||||
}
|
||||
|
||||
result := &SqlAsyncUtil{
|
||||
name: _name,
|
||||
filePath: _filePath,
|
||||
max_Worker_Nums: maxWorker,
|
||||
logAction: _logAction,
|
||||
}
|
||||
result.db = newGormDb(dbConnectionStr, maxWorker)
|
||||
result.workerPool = newSqlAsyncWorkerPool(maxWorker, result.reduceStatistics, _logAction, func() string { return result.name }, result.db)
|
||||
result.sqlStatistics = newSqlAsyncIdentityStatistics()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// NewSqlAsyncUtil2 创建新SqlAsyncUtil对象
|
||||
func NewSqlAsyncUtil2(_name, _filePath string, maxWorker int32, db *gorm.DB, _logAction func(logUtil.LogType, string)) *SqlAsyncUtil {
|
||||
if stringUtil.IsEmpty(_name) || stringUtil.IsEmpty(_filePath) || db == nil {
|
||||
panic(fmt.Sprintf("NewSqlAsyncUtil方法_name/_filePath/db参数不能为空"))
|
||||
}
|
||||
if maxWorker <= 0 {
|
||||
panic(fmt.Sprintf("NewSqlAsyncUtil方法maxWorker参数必须>0"))
|
||||
}
|
||||
if _logAction == nil {
|
||||
panic(fmt.Sprintf("NewSqlAsyncUtil方法_logAction参数并能为nil"))
|
||||
}
|
||||
|
||||
result := &SqlAsyncUtil{
|
||||
name: _name,
|
||||
filePath: _filePath,
|
||||
max_Worker_Nums: maxWorker,
|
||||
logAction: _logAction,
|
||||
}
|
||||
result.db = db
|
||||
result.workerPool = newSqlAsyncWorkerPool(maxWorker, result.reduceStatistics, _logAction, func() string { return result.name }, result.db)
|
||||
result.sqlStatistics = newSqlAsyncIdentityStatistics()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Start 启动
|
||||
func (this *SqlAsyncUtil) Start() {
|
||||
// 启动工作线程
|
||||
this.workerPool.Start()
|
||||
|
||||
// 读取待同步sql
|
||||
waitSyncSqls := this.readWaitSql()
|
||||
if waitSyncSqls == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 将数据加入写入队列
|
||||
for _, item := range waitSyncSqls {
|
||||
if item == nil {
|
||||
continue
|
||||
}
|
||||
this.Write(item)
|
||||
}
|
||||
}
|
||||
|
||||
// Stop 停止
|
||||
func (this *SqlAsyncUtil) Stop(save bool) {
|
||||
saveList := this.workerPool.Stop()
|
||||
if saveList == nil || len(saveList) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if save == false {
|
||||
return
|
||||
}
|
||||
|
||||
this.waitSqlFlushFile(saveList)
|
||||
}
|
||||
|
||||
// WaitSqlSyncDone 等待剩余sql同步完成
|
||||
func (this *SqlAsyncUtil) WaitSqlSyncDone() {
|
||||
for {
|
||||
num := this.GetAllCount()
|
||||
this.logAction(logUtil.Debug, fmt.Sprintf("SqlAsyncUtil(%s)当前剩余sql数量为:%v", this.name, num))
|
||||
|
||||
if num > 0 {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
continue
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
this.delFile()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Write1 写入Sql
|
||||
func (this *SqlAsyncUtil) Write1(tableName, identityId, sql string) {
|
||||
newItem := newSqlAsyncItemModel(tableName, identityId, sql)
|
||||
this.Write(newItem)
|
||||
}
|
||||
|
||||
// Write 写入Sql
|
||||
func (this *SqlAsyncUtil) Write(item *SqlAsyncItemModel) {
|
||||
worker, err := this.workerPool.GetWork(item.TableName)
|
||||
if err != nil {
|
||||
this.logAction(logUtil.Error, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
worker.Add(item)
|
||||
this.sqlStatistics.AddCount(item.IdentityId, 1)
|
||||
}
|
||||
|
||||
// GetCount 获取指定标识的待执行sql
|
||||
func (this *SqlAsyncUtil) GetCount(identityId string) int32 {
|
||||
return this.sqlStatistics.GetCount(identityId)
|
||||
}
|
||||
|
||||
// GetAllCount 获取总的待执行sql
|
||||
func (this *SqlAsyncUtil) GetAllCount() int32 {
|
||||
return this.workerPool.GetWaitSyncCount()
|
||||
}
|
||||
|
||||
// ReduceStatistics 减少统计
|
||||
func (this *SqlAsyncUtil) reduceStatistics(item *SqlAsyncItemModel) {
|
||||
this.sqlStatistics.Reduce(item.IdentityId, 1)
|
||||
}
|
||||
|
||||
// readWaitSql 读取待同步sql
|
||||
func (this *SqlAsyncUtil) readWaitSql() []*SqlAsyncItemModel {
|
||||
_, err := os.Stat(this.filePath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var bytes []byte
|
||||
bytes, err = ioutil.ReadFile(this.filePath)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("readWaitSql错误 file:%s err:%s", this.filePath, err.Error()))
|
||||
}
|
||||
|
||||
result := make([]*SqlAsyncItemModel, 0)
|
||||
err = json.Unmarshal(bytes, &result)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("readWaitSql json反序列化错误 file:%s err:%s", this.filePath, err.Error()))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// waitSqlFlushFile 待同步sql写入文件
|
||||
func (this *SqlAsyncUtil) waitSqlFlushFile(waitSqlList []*SqlAsyncItemModel) {
|
||||
dir := filepath.Dir(this.filePath)
|
||||
|
||||
// 创建文件夹
|
||||
_, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
os.MkdirAll(dir, os.ModePerm)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(waitSqlList)
|
||||
if err != nil {
|
||||
this.logAction(logUtil.Error, fmt.Sprintf("SqlAsyncUtil保存sql时,json出错,name:%s err:%s", this.name, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(this.filePath, data, os.ModePerm)
|
||||
if err != nil {
|
||||
this.logAction(logUtil.Error, fmt.Sprintf("SqlAsyncUtil保存sql时,写入出错,name:%s err:%s", this.name, err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
// delFile 删除文件
|
||||
func (this *SqlAsyncUtil) delFile() {
|
||||
// 创建文件夹
|
||||
_, err := os.Stat(this.filePath)
|
||||
if err == nil {
|
||||
os.Remove(this.filePath)
|
||||
}
|
||||
}
|
||||
|
||||
// @title newGormDb
|
||||
// @description 构造新gorm.DB对象
|
||||
// @Param connectionString 数据库连接字符串
|
||||
// @Param maxOpenCount 最大打开连接数
|
||||
func newGormDb(connectionString string, maxOpenCount int32) *gorm.DB {
|
||||
dbObj, err := gorm.Open("mysql", connectionString)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("连接mysql出错 connectionString:%s err:%s", connectionString, err))
|
||||
}
|
||||
|
||||
dbObj.DB().SetMaxOpenConns(int(maxOpenCount))
|
||||
dbObj.DB().SetMaxIdleConns(int(maxOpenCount))
|
||||
dbObj.DB().SetConnMaxLifetime(time.Minute * 4)
|
||||
|
||||
return dbObj
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
提供int和[]Bytes互相转化的助手方法,其中需要注意的是在不同的平台上大、小端是不同的
|
||||
*/
|
||||
package intAndBytesUtil
|
||||
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
未实现的列表方法:
|
||||
SSCAN
|
||||
*/
|
||||
package redisUtil
|
||||
|
||||
import (
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
/*
|
||||
SADD key member [member …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N), N 是被添加的元素的数量。
|
||||
将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
|
||||
|
||||
假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
|
||||
|
||||
当 key 不是集合类型时,返回一个错误。
|
||||
|
||||
Note
|
||||
|
||||
在Redis2.4版本以前, SADD 只接受单个 member 值。
|
||||
|
||||
返回值
|
||||
被添加到集合中的新元素的数量,不包括被忽略的元素。
|
||||
*/
|
||||
func (this *RedisPool) SAdd(key string, values ...interface{}) (newCount int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
newCount, err = redis.Int(conn.Do("SADD", redis.Args{}.Add(key).AddFlat(values)...))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SISMEMBER key member
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
判断 member 元素是否集合 key 的成员。
|
||||
|
||||
返回值
|
||||
如果 member 元素是集合的成员,返回 1 。 如果 member 元素不是集合的成员,或 key 不存在,返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) SIsMember(key string, value interface{}) (isMember bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
isMember, err = redis.Bool(conn.Do("SISMEMBER", key, value))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SPOP key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
移除并返回集合中的一个随机元素。
|
||||
|
||||
如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用 SRANDMEMBER key [count] 命令。
|
||||
|
||||
返回值
|
||||
被移除的随机元素。 当 key 不存在或 key 是空集时,返回 nil 。
|
||||
*/
|
||||
func (this *RedisPool) SPop(key string) (value interface{}, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
value, err = conn.Do("SPOP", key)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SRANDMEMBER key [count]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: 只提供 key 参数时为 O(1) 。如果提供了 count 参数,那么为 O(N) ,N 为返回数组的元素个数。
|
||||
如果命令执行时,只提供了 key 参数,那么返回集合中的一个随机元素。
|
||||
|
||||
从 Redis 2.6 版本开始, SRANDMEMBER 命令接受可选的 count 参数:
|
||||
|
||||
如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。
|
||||
|
||||
如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
|
||||
|
||||
该操作和 SPOP key 相似,但 SPOP key 将随机元素从集合中移除并返回,而 SRANDMEMBER 则仅仅返回随机元素,而不对集合进行任何改动。
|
||||
|
||||
返回值
|
||||
只提供 key 参数时,返回一个元素;如果集合为空,返回 nil 。 如果提供了 count 参数,那么返回一个数组;如果集合为空,返回空数组。
|
||||
*/
|
||||
func (this *RedisPool) SRandMember(key string, count int) (reply interface{}, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
reply, err = conn.Do("SRANDMEMBER", key, count)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SREM key member [member …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N), N 为给定 member 元素的数量。
|
||||
移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
|
||||
|
||||
当 key 不是集合类型,返回一个错误。
|
||||
|
||||
Note
|
||||
|
||||
在 Redis 2.4 版本以前, SREM 只接受单个 member 值。
|
||||
|
||||
返回值
|
||||
被成功移除的元素的数量,不包括被忽略的元素。
|
||||
*/
|
||||
func (this *RedisPool) SRem(key string, values ...interface{}) (delCount int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
delCount, err = redis.Int(conn.Do("SREM", redis.Args{}.Add(key).AddFlat(values)...))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SMOVE source destination member
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
将 member 元素从 source 集合移动到 destination 集合。
|
||||
|
||||
SMOVE 是原子性操作。
|
||||
|
||||
如果 source 集合不存在或不包含指定的 member 元素,则 SMOVE 命令不执行任何操作,仅返回 0 。否则, member 元素从 source 集合中被移除,并添加到 destination 集合中去。
|
||||
|
||||
当 destination 集合已经包含 member 元素时, SMOVE 命令只是简单地将 source 集合中的 member 元素删除。
|
||||
|
||||
当 source 或 destination 不是集合类型时,返回一个错误。
|
||||
|
||||
返回值
|
||||
如果 member 元素被成功移除,返回 1 。 如果 member 元素不是 source 集合的成员,并且没有任何操作对 destination 集合执行,那么返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) SMove(source, destination string, member interface{}) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var result int
|
||||
result, err = redis.Int(conn.Do("SMOVE", source, destination, member))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if result == 1 {
|
||||
successful = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SCARD key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
返回集合 key 的基数(集合中元素的数量)。
|
||||
|
||||
返回值
|
||||
集合的基数。 当 key 不存在时,返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) SCard(key string) (nowCount int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
nowCount, err = redis.Int(conn.Do("SCARD", key))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SMEMBERS key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N), N 为集合的基数。
|
||||
返回集合 key 中的所有成员。
|
||||
|
||||
不存在的 key 被视为空集合。
|
||||
|
||||
返回值
|
||||
集合中的所有成员。
|
||||
*/
|
||||
func (this *RedisPool) SMembers(key string) (reply interface{}, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
reply, err = conn.Do("SMEMBERS", key)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SINTER key [key …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。
|
||||
返回一个集合的全部成员,该集合是所有给定集合的交集。
|
||||
|
||||
不存在的 key 被视为空集。
|
||||
|
||||
当给定集合当中有一个空集时,结果也为空集(根据集合运算定律)。
|
||||
|
||||
返回值
|
||||
交集成员的列表。
|
||||
*/
|
||||
func (this *RedisPool) SInter(key string, keyList ...string) (reply interface{}, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
reply, err = conn.Do("SINTER", redis.Args{}.Add(key).AddFlat(keyList)...)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SINTERSTORE destination key [key …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。
|
||||
这个命令类似于 SINTER key [key …] 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集。
|
||||
|
||||
如果 destination 集合已经存在,则将其覆盖。
|
||||
|
||||
destination 可以是 key 本身。
|
||||
|
||||
返回值
|
||||
结果集中的成员数量。
|
||||
*/
|
||||
func (this *RedisPool) SInterStore(destination string, key string, keyList ...string) (count int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
count, err = redis.Int(conn.Do("SINTERSTORE", redis.Args{}.Add(destination).Add(key).AddFlat(keyList)...))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SUNION key [key …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N), N 是所有给定集合的成员数量之和。
|
||||
返回一个集合的全部成员,该集合是所有给定集合的并集。
|
||||
|
||||
不存在的 key 被视为空集。
|
||||
|
||||
返回值
|
||||
并集成员的列表。
|
||||
*/
|
||||
func (this *RedisPool) SUnion(key string, keyList ...string) (reply interface{}, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
reply, err = conn.Do("SUNION", redis.Args{}.Add(key).AddFlat(keyList)...)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SUNIONSTORE destination key [key …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N), N 是所有给定集合的成员数量之和。
|
||||
这个命令类似于 SUNION key [key …] 命令,但它将结果保存到 destination 集合,而不是简单地返回结果集。
|
||||
|
||||
如果 destination 已经存在,则将其覆盖。
|
||||
|
||||
destination 可以是 key 本身。
|
||||
|
||||
返回值
|
||||
结果集中的元素数量。
|
||||
*/
|
||||
func (this *RedisPool) SUnionStore(destination string, key string, keyList ...string) (count int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
count, err = redis.Int(conn.Do("SUNIONSTORE", redis.Args{}.Add(destination).Add(key).AddFlat(keyList)...))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SDIFF key [key …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N), N 是所有给定集合的成员数量之和。
|
||||
返回一个集合的全部成员,该集合是所有给定集合之间的差集。
|
||||
|
||||
不存在的 key 被视为空集。
|
||||
|
||||
返回值
|
||||
一个包含差集成员的列表。
|
||||
*/
|
||||
func (this *RedisPool) SDiff(key string, keyList ...string) (reply interface{}, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
reply, err = conn.Do("SDIFF", redis.Args{}.Add(key).AddFlat(keyList)...)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SDIFFSTORE destination key [key …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N), N 是所有给定集合的成员数量之和。
|
||||
这个命令的作用和 SDIFF key [key …] 类似,但它将结果保存到 destination 集合,而不是简单地返回结果集。
|
||||
|
||||
如果 destination 集合已经存在,则将其覆盖。
|
||||
|
||||
destination 可以是 key 本身。
|
||||
|
||||
返回值
|
||||
结果集中的元素数量。
|
||||
*/
|
||||
func (this *RedisPool) SDiffStore(destination string, key string, keyList ...string) (count int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
count, err = redis.Int(conn.Do("SDIFFSTORE", redis.Args{}.Add(destination).Add(key).AddFlat(keyList)...))
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
package redisUtil
|
||||
|
||||
import (
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
/*
|
||||
SET key value [EX seconds] [PX milliseconds] [NX|XX]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
将字符串值 value 关联到 key 。
|
||||
|
||||
如果 key 已经持有其他值, SET 就覆写旧值, 无视类型。
|
||||
|
||||
当 SET 命令对一个带有生存时间(TTL)的键进行设置之后, 该键原有的 TTL 将被清除。
|
||||
|
||||
可选参数
|
||||
从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:
|
||||
|
||||
EX seconds : 将键的过期时间设置为 seconds 秒。 执行 SET key value EX seconds 的效果等同于执行 SETEX key seconds value 。
|
||||
|
||||
PX milliseconds : 将键的过期时间设置为 milliseconds 毫秒。 执行 SET key value PX milliseconds 的效果等同于执行 PSETEX key milliseconds value 。
|
||||
|
||||
NX : 只在键不存在时, 才对键进行设置操作。 执行 SET key value NX 的效果等同于执行 SETNX key value 。
|
||||
|
||||
XX : 只在键已经存在时, 才对键进行设置操作。
|
||||
|
||||
Note
|
||||
|
||||
因为 SET 命令可以通过参数来实现 SETNX 、 SETEX 以及 PSETEX 命令的效果, 所以 Redis 将来的版本可能会移除并废弃 SETNX 、 SETEX 和 PSETEX 这三个命令。
|
||||
|
||||
返回值
|
||||
在 Redis 2.6.12 版本以前, SET 命令总是返回 OK 。
|
||||
|
||||
从 Redis 2.6.12 版本开始, SET 命令只在设置操作成功完成时才返回 OK ; 如果命令使用了 NX 或者 XX 选项, 但是因为条件没达到而造成设置操作未执行, 那么命令将返回空批量回复(NULL Bulk Reply)。
|
||||
*/
|
||||
/*
|
||||
expireType: "EX"|"PX"|""(参照上面的说明)
|
||||
expireTime: seconds|milliseconds|无(根据expireType的不同而不同,参照上面的说明)
|
||||
setType: "NX"|"XX"|""(参照上面的说明)
|
||||
*/
|
||||
/*
|
||||
返回值:
|
||||
successful: 是否成功
|
||||
err: 错误对象
|
||||
*/
|
||||
func (this *RedisPool) Set(key string, value interface{}, expireType string, expireTime int, setType string) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
args := redis.Args{}.Add(key).Add(value)
|
||||
if expireType != "" {
|
||||
args = args.Add(expireType).Add(expireTime)
|
||||
}
|
||||
if setType != "" {
|
||||
args = args.Add(setType)
|
||||
}
|
||||
|
||||
reply, err := conn.Do("SET", args...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if reply == nil {
|
||||
return
|
||||
}
|
||||
|
||||
successful = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
GET key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
返回与键 key 相关联的字符串值。
|
||||
|
||||
返回值
|
||||
如果键 key 不存在, 那么返回特殊值 nil ; 否则, 返回键 key 的值。
|
||||
|
||||
如果键 key 的值并非字符串类型, 那么返回一个错误, 因为 GET 命令只能用于字符串值。
|
||||
*/
|
||||
func (this *RedisPool) Get(key string) (reply interface{}, exist bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
reply, err = conn.Do("GET", key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if reply == nil {
|
||||
return
|
||||
}
|
||||
|
||||
exist = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
GETSET key value
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
将键 key 的值设为 value , 并返回键 key 在被设置之前的旧值。
|
||||
|
||||
返回值
|
||||
返回给定键 key 的旧值。
|
||||
|
||||
如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil 。
|
||||
|
||||
当键 key 存在但不是字符串类型时, 命令返回一个错误。
|
||||
*/
|
||||
func (this *RedisPool) GetSet(key, value interface{}) (oldValue interface{}, exist bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
oldValue, err = conn.Do("GetSet", key, value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if oldValue == nil {
|
||||
return
|
||||
}
|
||||
|
||||
exist = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
STRLEN key
|
||||
可用版本: >= 2.2.0
|
||||
复杂度: O(1)
|
||||
返回键 key 储存的字符串值的长度。
|
||||
|
||||
返回值
|
||||
STRLEN 命令返回字符串值的长度。
|
||||
|
||||
当键 key 不存在时, 命令返回 0 。
|
||||
|
||||
当 key 储存的不是字符串值时, 返回一个错误。
|
||||
*/
|
||||
func (this *RedisPool) StrLen(key string) (length int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
length, err = redis.Int(conn.Do("STRLEN", key))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
APPEND key value
|
||||
可用版本: >= 2.0.0
|
||||
时间复杂度: 平摊O(1)
|
||||
如果键 key 已经存在并且它的值是一个字符串, APPEND 命令将把 value 追加到键 key 现有值的末尾。
|
||||
|
||||
如果 key 不存在, APPEND 就简单地将键 key 的值设为 value , 就像执行 SET key value 一样。
|
||||
|
||||
返回值
|
||||
追加 value 之后, 键 key 的值的长度。
|
||||
*/
|
||||
func (this *RedisPool) Append(key, value string) (length int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
length, err = redis.Int(conn.Do("APPEND", key, value))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SETRANGE key offset value
|
||||
可用版本: >= 2.2.0
|
||||
时间复杂度:对于长度较短的字符串,命令的平摊复杂度O(1);对于长度较大的字符串,命令的复杂度为 O(M) ,其中 M 为 value 的长度。
|
||||
从偏移量 offset 开始, 用 value 参数覆写(overwrite)键 key 储存的字符串值。
|
||||
|
||||
不存在的键 key 当作空白字符串处理。
|
||||
|
||||
SETRANGE 命令会确保字符串足够长以便将 value 设置到指定的偏移量上, 如果键 key 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的 offset 是 10 ), 那么原字符和偏移量之间的空白将用零字节(zerobytes, "\x00" )进行填充。
|
||||
|
||||
因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内, 所以用户能够使用的最大偏移量为 2^29-1(536870911) , 如果你需要使用比这更大的空间, 请使用多个 key 。
|
||||
|
||||
Warning
|
||||
|
||||
当生成一个很长的字符串时, Redis 需要分配内存空间, 该操作有时候可能会造成服务器阻塞(block)。 在2010年出产的Macbook Pro上, 设置偏移量为 536870911(512MB 内存分配)将耗费约 300 毫秒, 设置偏移量为 134217728(128MB 内存分配)将耗费约 80 毫秒, 设置偏移量 33554432(32MB 内存分配)将耗费约 30 毫秒, 设置偏移量为 8388608(8MB 内存分配)将耗费约 8 毫秒。
|
||||
|
||||
返回值
|
||||
SETRANGE 命令会返回被修改之后, 字符串值的长度。
|
||||
*/
|
||||
func (this *RedisPool) SetRange(key string, offset int, value string) (length int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
length, err = redis.Int(conn.Do("SETRANGE", key, offset, value))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
GETRANGE key start end
|
||||
可用版本: >= 2.4.0
|
||||
时间复杂度: O(N),其中 N 为被返回的字符串的长度。
|
||||
返回键 key 储存的字符串值的指定部分, 字符串的截取范围由 start 和 end 两个偏移量决定 (包括 start 和 end 在内)。
|
||||
|
||||
负数偏移量表示从字符串的末尾开始计数, -1 表示最后一个字符, -2 表示倒数第二个字符, 以此类推。
|
||||
|
||||
GETRANGE 通过保证子字符串的值域(range)不超过实际字符串的值域来处理超出范围的值域请求。
|
||||
|
||||
Note
|
||||
|
||||
GETRANGE 命令在 Redis 2.0 之前的版本里面被称为 SUBSTR 命令。
|
||||
|
||||
返回值
|
||||
GETRANGE 命令会返回字符串值的指定部分。
|
||||
*/
|
||||
func (this *RedisPool) GetRange(key string, start, end int) (value string, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
value, err = redis.String(conn.Do("GETRANGE", key, start, end))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
INCR key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
为键 key 储存的数字值加上一。
|
||||
|
||||
如果键 key 不存在, 那么它的值会先被初始化为 0 , 然后再执行 INCR 命令。
|
||||
|
||||
如果键 key 储存的值不能被解释为数字, 那么 INCR 命令将返回一个错误。
|
||||
|
||||
本操作的值限制在 64 位(bit)有符号数字表示之内。
|
||||
|
||||
Note
|
||||
|
||||
INCR 命令是一个针对字符串的操作。 因为 Redis 并没有专用的整数类型, 所以键 key 储存的值在执行 INCR 命令时会被解释为十进制 64 位有符号整数。
|
||||
|
||||
返回值
|
||||
INCR 命令会返回键 key 在执行加一操作之后的值。
|
||||
*/
|
||||
func (this *RedisPool) Incr(key string) (newValue int64, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
newValue, err = redis.Int64(conn.Do("INCR", key))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
INCRBY key increment
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
为键 key 储存的数字值加上增量 increment 。
|
||||
|
||||
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 INCRBY 命令。
|
||||
|
||||
如果键 key 储存的值不能被解释为数字, 那么 INCRBY 命令将返回一个错误。
|
||||
|
||||
本操作的值限制在 64 位(bit)有符号数字表示之内。
|
||||
|
||||
关于递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。
|
||||
|
||||
返回值
|
||||
在加上增量 increment 之后, 键 key 当前的值。
|
||||
*/
|
||||
func (this *RedisPool) IncrBy(key string, increment int64) (newValue int64, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
newValue, err = redis.Int64(conn.Do("INCRBY", key, increment))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
INCRBYFLOAT key increment
|
||||
可用版本: >= 2.6.0
|
||||
时间复杂度: O(1)
|
||||
为键 key 储存的值加上浮点数增量 increment 。
|
||||
|
||||
如果键 key 不存在, 那么 INCRBYFLOAT 会先将键 key 的值设为 0 , 然后再执行加法操作。
|
||||
|
||||
如果命令执行成功, 那么键 key 的值会被更新为执行加法计算之后的新值, 并且新值会以字符串的形式返回给调用者。
|
||||
|
||||
无论是键 key 的值还是增量 increment , 都可以使用像 2.0e7 、 3e5 、 90e-2 那样的指数符号(exponential notation)来表示, 但是, 执行 INCRBYFLOAT 命令之后的值总是以同样的形式储存, 也即是, 它们总是由一个数字, 一个(可选的)小数点和一个任意长度的小数部分组成(比如 3.14 、 69.768 ,诸如此类), 小数部分尾随的 0 会被移除, 如果可能的话, 命令还会将浮点数转换为整数(比如 3.0 会被保存成 3 )。
|
||||
|
||||
此外, 无论加法计算所得的浮点数的实际精度有多长, INCRBYFLOAT 命令的计算结果最多只保留小数点的后十七位。
|
||||
|
||||
当以下任意一个条件发生时, 命令返回一个错误:
|
||||
|
||||
键 key 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型);
|
||||
|
||||
键 key 当前的值或者给定的增量 increment 不能被解释(parse)为双精度浮点数。
|
||||
|
||||
返回值
|
||||
在加上增量 increment 之后, 键 key 的值。
|
||||
*/
|
||||
func (this *RedisPool) IncrByFloat(key string, increment float64) (newValue float64, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
newValue, err = redis.Float64(conn.Do("INCRBYFLOAT", key, increment))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
DECR key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
为键 key 储存的数字值减去一。
|
||||
|
||||
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECR 操作。
|
||||
|
||||
如果键 key 储存的值不能被解释为数字, 那么 DECR 命令将返回一个错误。
|
||||
|
||||
本操作的值限制在 64 位(bit)有符号数字表示之内。
|
||||
|
||||
关于递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。
|
||||
|
||||
返回值
|
||||
DECR 命令会返回键 key 在执行减一操作之后的值。
|
||||
*/
|
||||
func (this *RedisPool) Decr(key string) (newValue int64, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
newValue, err = redis.Int64(conn.Do("DECR", key))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
DECRBY key decrement
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
将键 key 储存的整数值减去减量 decrement 。
|
||||
|
||||
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECRBY 命令。
|
||||
|
||||
如果键 key 储存的值不能被解释为数字, 那么 DECRBY 命令将返回一个错误。
|
||||
|
||||
本操作的值限制在 64 位(bit)有符号数字表示之内。
|
||||
|
||||
关于更多递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。
|
||||
|
||||
返回值
|
||||
DECRBY 命令会返回键在执行减法操作之后的值。
|
||||
*/
|
||||
func (this *RedisPool) DecrBy(key string, decrement int64) (newValue int64, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
newValue, err = redis.Int64(conn.Do("DECRBY", key, decrement))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
MSET key value [key value …]
|
||||
可用版本: >= 1.0.1
|
||||
时间复杂度: O(N),其中 N 为被设置的键数量。
|
||||
同时为多个键设置值。
|
||||
|
||||
如果某个给定键已经存在, 那么 MSET 将使用新值去覆盖旧值, 如果这不是你所希望的效果, 请考虑使用 MSETNX 命令, 这个命令只会在所有给定键都不存在的情况下进行设置。
|
||||
|
||||
MSET 是一个原子性(atomic)操作, 所有给定键都会在同一时间内被设置, 不会出现某些键被设置了但是另一些键没有被设置的情况。
|
||||
|
||||
返回值
|
||||
MSET 命令总是返回 OK 。
|
||||
*/
|
||||
func (this *RedisPool) MSet(key_value_map map[string]interface{}) (err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
_, err = conn.Do("MSET", redis.Args{}.AddFlat(key_value_map)...)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
MSETNX key value [key value …]
|
||||
可用版本: >= 1.0.1
|
||||
时间复杂度: O(N), 其中 N 为被设置的键数量。
|
||||
当且仅当所有给定键都不存在时, 为所有给定键设置值。
|
||||
|
||||
即使只有一个给定键已经存在, MSETNX 命令也会拒绝执行对所有键的设置操作。
|
||||
|
||||
MSETNX 是一个原子性(atomic)操作, 所有给定键要么就全部都被设置, 要么就全部都不设置, 不可能出现第三种状态。
|
||||
|
||||
返回值
|
||||
当所有给定键都设置成功时, 命令返回 1 ; 如果因为某个给定键已经存在而导致设置未能成功执行, 那么命令返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) MSetNX(key_value_map map[string]interface{}) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var count int
|
||||
count, err = redis.Int(conn.Do("MSETNX", redis.Args{}.AddFlat(key_value_map)...))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if count == 1 {
|
||||
successful = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
MGET key [key …]
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(N) ,其中 N 为给定键的数量。
|
||||
返回给定的一个或多个字符串键的值。
|
||||
|
||||
如果给定的字符串键里面, 有某个键不存在, 那么这个键的值将以特殊值 nil 表示。
|
||||
|
||||
返回值
|
||||
MGET 命令将返回一个列表, 列表中包含了所有给定键的值。
|
||||
*/
|
||||
func (this *RedisPool) MGet(keyList []string) (reply interface{}, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
// valueList, err = redis.Values(conn.Do("MGET", redis.Args{}.AddFlat(keyList)...))
|
||||
reply, err = conn.Do("MGET", redis.Args{}.AddFlat(keyList)...)
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user