狂虐倭奴 發表於 2022-8-10 14:00:00

go-redis

<h1 class="md-end-block md-heading"><span class="md-plain">golang redis快速入门教程</span></h1>
<p class="md-end-block md-p"><span class="md-plain">redis是目前流行的高性能key/value缓存,基本上在各种项目都经常出现,后续教程针对golang如何操作redis进行展开。</span></p>
<p class="md-end-block md-p"><span class="md-plain">本教程是使用的是go-redis/redis包操作redis。<span class="md-softbreak"> <span class="md-plain">github: <span class="md-link">https://github.com/go-redis/redis</span></span></span></span></p>
<h2 class="md-end-block md-heading"><span class="md-plain">1.安装依赖包</span></h2>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>go get -u github.com/go-redis/redis</span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">2.golang连接redis</span></h2>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 根据redis配置初始化一个客户端<br><span>client := redis.NewClient(&amp;redis.Options{<br><span><span class="cm-tab">    <span class="cm-tab">    Addr: &nbsp; &nbsp; "localhost:6379", // redis地址<br><span><span class="cm-tab">    <span class="cm-tab">    Password: "", // redis密码,没有则留空<br><span><span class="cm-tab">    <span class="cm-tab">    DB: &nbsp; &nbsp; &nbsp; 0,// 默认数据库,默认是0<br><span><span class="cm-tab">    })</span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">3.简单的例子</span></h2>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 设置一个key,过期时间为0,意思就是永远不过期<br><span>err := client.Set("key", "value", 0).Err()<br><span><span>​<br><span>// 检测设置是否成功<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>// 根据key查询缓存,通过Result函数返回两个值<br><span>//第一个代表key的值,第二个代表查询错误信息<br><span>val, err := client.Get("key").Result()<br><span><span>​<br><span>// 检测,查询是否出错<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println("key", val)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h1 class="md-end-block md-heading"><span class="md-plain">golang 如何连接redis</span></h1>
<p class="md-end-block md-p"><span class="md-plain">下面介绍golang如何连接redis服务端。</span></p>
<h2 class="md-end-block md-heading"><span class="md-plain">1.golang连接redis</span></h2>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 初始化一个新的redis client<br><span>client := redis.NewClient(&amp;redis.Options{<br><span><span class="cm-tab">    <span class="cm-tab">    Addr: &nbsp; &nbsp; "localhost:6379", // redis地址<br><span><span class="cm-tab">    <span class="cm-tab">    Password: "", // redis没密码,没有设置,则留空<br><span><span class="cm-tab">    <span class="cm-tab">    DB: &nbsp; &nbsp; &nbsp; 0,// 使用默认数据库<br><span><span class="cm-tab">    })</span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">通过例子,我们知道主要通过Options配置redis的连接参数,下面对Options参数进行详细说明。</span></p>
<blockquote>
<p class="md-end-block md-p"><span class="md-plain">提示:go-redis包自带了连接池,会自动维护redis连接,因此创建一次client即可,不要查询一次redis就关闭client。</span></p>
</blockquote>
<h2 class="md-end-block md-heading"><span class="md-plain">2.Options参数详解</span></h2>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>type Options struct {<br><span><span class="cm-tab">    // 网络类型 tcp 或者 unix.<br><span><span class="cm-tab">    // 默认是 tcp.<br><span><span class="cm-tab">    Network string<br><span><span class="cm-tab">    // redis地址,格式 host:port<br><span><span class="cm-tab">    Addr string<br><span><span>​<br><span><span class="cm-tab">    // 新建一个redis连接的时候,会回调这个函数<br><span><span class="cm-tab">    OnConnect func(*Conn) error<br><span><span>​<br><span><span class="cm-tab">    // redis密码,redis server没有设置可以为空。<br><span><span class="cm-tab">    Password string<br><span class="cm-tab-wrap-hack"><span class="cm-tab">    <br><span><span class="cm-tab">    // redis数据库,序号从0开始,默认是0,可以不用设置<br><span><span class="cm-tab">    DB int<br><span><span>​<br><span><span class="cm-tab">    // redis操作失败最大重试次数,默认不重试。<br><span><span class="cm-tab">    MaxRetries int<br><span class="cm-tab-wrap-hack"><span class="cm-tab">    <br><span><span class="cm-tab">    // 最小重试时间间隔.<br><span><span class="cm-tab">    // 默认是 8ms ; -1 表示关闭.<br><span><span class="cm-tab">    MinRetryBackoff time.Duration<br><span class="cm-tab-wrap-hack"><span class="cm-tab">    <br><span><span class="cm-tab">    // 最大重试时间间隔<br><span><span class="cm-tab">    // 默认是 512ms; -1 表示关闭.<br><span><span class="cm-tab">    MaxRetryBackoff time.Duration<br><span><span>​<br><span><span class="cm-tab">    // redis连接超时时间.<br><span><span class="cm-tab">    // 默认是 5 秒.<br><span><span class="cm-tab">    DialTimeout time.Duration<br><span class="cm-tab-wrap-hack"><span class="cm-tab">    <br><span><span class="cm-tab">    // socket读取超时时间<br><span><span class="cm-tab">    // 默认 3 秒.<br><span><span class="cm-tab">    ReadTimeout time.Duration<br><span class="cm-tab-wrap-hack"><span class="cm-tab">    <br><span><span class="cm-tab">    // socket写超时时间<br><span><span class="cm-tab">    WriteTimeout time.Duration<br><span><span>​<br><span><span class="cm-tab">    // redis连接池的最大连接数.<br><span><span class="cm-tab">    // 默认连接池大小等于 cpu个数 * 10<br><span><span class="cm-tab">    PoolSize int<br><span class="cm-tab-wrap-hack"><span class="cm-tab">    <br><span><span class="cm-tab">    // redis连接池最小空闲连接数.<br><span><span class="cm-tab">    MinIdleConns int<br><span><span class="cm-tab">    // redis连接最大的存活时间,默认不会关闭过时的连接.<br><span><span class="cm-tab">    MaxConnAge time.Duration<br><span class="cm-tab-wrap-hack"><span class="cm-tab">    <br><span><span class="cm-tab">    // 当你从redis连接池获取一个连接之后,连接池最多等待这个拿出去的连接多长时间。<br><span><span class="cm-tab">    // 默认是等待 ReadTimeout + 1 秒.<br><span><span class="cm-tab">    PoolTimeout time.Duration<br><span><span class="cm-tab">    // redis连接池多久会关闭一个空闲连接.<br><span><span class="cm-tab">    // 默认是 5 分钟. -1 则表示关闭这个配置项<br><span><span class="cm-tab">    IdleTimeout time.Duration<br><span><span class="cm-tab">    // 多长时间检测一下,空闲连接<br><span><span class="cm-tab">    // 默认是 1 分钟. -1 表示关闭空闲连接检测<br><span><span class="cm-tab">    IdleCheckFrequency time.Duration<br><span><span>​<br><span><span class="cm-tab">    // 只读设置,如果设置为true, redis只能查询缓存不能更新。<br><span><span class="cm-tab">    readOnly bool<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h1 class="md-end-block md-heading"><span class="md-plain">golang redis基本键值操作</span></h1>
<p class="md-end-block md-p"><span class="md-plain">redis基本的key/value操作,指的是针对value值的类型为字符串或者数字类型的读写操作。</span></p>
<p class="md-end-block md-p"><span class="md-plain">golang redis常用函数列表:</span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Set - 设置一个key的值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Get - 查询key的值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">GetSet - 设置一个key的值,并返回这个key的旧值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SetNX - 如果key不存在,则设置这个key的值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">MGet - 批量查询key的值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">MSet - 批量设置key的值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Incr,IncrBy,IncrByFloat - 针对一个key的数值进行递增操作</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Decr,DecrBy - 针对一个key的数值进行递减操作</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Del - 删除key操作,可以批量删除</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Expire - 设置key的过期时间</span></p>
</li>
</ul>
<h2 class="md-end-block md-heading"><span class="md-plain">1.Set</span></h2>
<p class="md-end-block md-p"><span class="md-plain">设置一个key的值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 第三个参数代表key的过期时间,0代表不会过期。<br><span>err := client.Set("key", "value", 0).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">2.Get</span></h2>
<p class="md-end-block md-p"><span class="md-plain">查询key的值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// Result函数返回两个值,第一个是key的值,第二个是错误信息<br><span>val, err := client.Get("key").Result()<br><span>// 判断查询是否出错<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println("key", val)</span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">3.GetSet</span></h2>
<p class="md-end-block md-p"><span class="md-plain">设置一个key的值,并返回这个key的旧值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// Result函数返回两个值,第一个是key的值,第二个是错误信息<br><span>oldVal, err := client.GetSet("key", "new value").Result()<br><span><span>​<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>// 打印key的旧值<br><span>fmt.Println("key", oldVal)</span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">4.SetNX</span></h2>
<p class="md-end-block md-p"><span class="md-plain">如果key不存在,则设置这个key的值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 第三个参数代表key的过期时间,0代表不会过期。<br><span>err := client.SetNX("key", "value", 0).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">5.MGet</span></h2>
<p class="md-end-block md-p"><span class="md-plain">批量查询key的值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// MGet函数可以传入任意个key,一次性返回多个值。<br><span>// 这里Result返回两个值,第一个值是一个数组,第二个值是错误信息<br><span>vals, err := client.MGet("key1", "key2", "key3").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println(vals)</span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">6.MSet</span></h2>
<p class="md-end-block md-p"><span class="md-plain">批量设置key的值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>err := client.MSet("key1", "value1", "key2", "value2", "key3", "value3").Err()<br><span>if err != nil {<br><span>panic(err)<br><span>}</span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">7.Incr,IncrBy</span></h2>
<p class="md-end-block md-p"><span class="md-plain">针对一个key的数值进行递增操作</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// Incr函数每次加一<br><span>val, err := client.Incr("key").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println("最新值", val)<br><span><span>​<br><span>// IncrBy函数,可以指定每次递增多少<br><span>val, err := client.IncrBy("key", 2).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println("最新值", val)<br><span><span>​<br><span>// IncrByFloat函数,可以指定每次递增多少,跟IncrBy的区别是累加的是浮点数<br><span>val, err := client.IncrByFloat("key", 2).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println("最新值", val)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">8.Decr,DecrBy</span></h2>
<p class="md-end-block md-p"><span class="md-plain">针对一个key的数值进行递减操作</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// Decr函数每次减一<br><span>val, err := client.Decr("key").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println("最新值", val)<br><span><span>​<br><span>// DecrBy函数,可以指定每次递减多少<br><span>val, err := client.DecrBy("key", 2).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println("最新值", val)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">9.Del</span></h2>
<p class="md-end-block md-p"><span class="md-plain">删除key操作,支持批量删除</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 删除key<br><span>client.Del("key")<br><span><span>​<br><span>// 删除多个key, Del函数支持删除多个key<br><span>err := client.Del("key1", "key2", "key3").Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">10.Expire</span></h2>
<p class="md-end-block md-p"><span class="md-plain">设置key的过期时间,单位秒</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>client.Expire("key", 3)</span></pre>
<h1 class="md-end-block md-heading"><span class="md-plain">golang redis hash教程</span></h1>
<p class="md-end-block md-p"><span class="md-plain">golang redis hash类型数据操作。</span></p>
<p class="md-end-block md-p"><span class="md-plain">如果你希望key/value的值也能作为hash结构进行操作,可以选择redis hash类型。</span></p>
<p class="md-end-block md-p"><span class="md-plain">使用场景举例:<span class="md-softbreak"> <span class="md-plain">如果我们希望缓存一条用户信息(包括用户id、用户名、email字段),希望能够做到局部读写用户信息(例如:读写用户名),也能够读取整条用户信息,那么hash类型就支持这些操作。</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain">redis hash操作主要有2-3个元素组成:</span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">key - redis key 唯一标识</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">field - hash数据的字段名</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">value - 值,有些操作不需要值</span></p>
</li>
</ul>
<p class="md-end-block md-p"><span><strong>go redis hash数据常用函数:</strong></span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HSet - 根据key和field字段设置,field字段的值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HGet - 根据key和field字段,查询field字段的值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HGetAll - 根据key查询所有字段和值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HIncrBy - 根据key和field字段,累加数值。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HKeys - 根据key返回所有字段名</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HLen - 根据key,查询hash的字段数量</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HMGet - 根据key和多个字段名,批量查询多个hash字段值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HMSet - 根据key和多个字段名和字段值,批量设置hash字段值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HSetNX - 如果field字段不存在,则设置hash字段值</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HDel - 根据key和字段名,删除hash字段,支持批量删除hash字段</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">HExists - 检测hash字段名是否存在。</span></p>
</li>
</ul>
<blockquote>
<p class="md-end-block md-p"><span class="md-plain">提示:不管我们选择redis什么类型的数据,操作的时候都必须要有一个唯一的Key, 用来唯一标识一个数据。</span></p>
</blockquote>
<h2 class="md-end-block md-heading"><span class="md-plain">1.HSet</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key和field字段设置,field字段的值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// user_1 是hash key,username 是字段名, tizi365是字段值<br><span>err := client.HSet("user_1", "username", "tizi365").Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">2.HGet</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key和field字段,查询field字段的值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// user_1 是hash key,username是字段名<br><span>username, err := client.HGet("user_1", "username").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println(username)</span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">3.HGetAll</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key查询所有字段和值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 一次性返回key=user_1的所有hash字段和值<br><span>data, err := client.HGetAll("user_1").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>// data是一个map类型,这里使用使用循环迭代输出<br><span>for field, val := range data {<br><span><span class="cm-tab">    fmt.Println(field,val)<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">4.HIncrBy</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key和field字段,累加字段的数值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 累加count字段的值,一次性累加2, user_1为hash key<br><span>count, err := client.HIncrBy("user_1", "count", 2).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>fmt.Println(count)</span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">5.HKeys</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key返回所有字段名</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// keys是一个string数组<br><span>keys, err := client.HKeys("user_1").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>fmt.Println(keys)</span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">6.HLen</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key,查询hash的字段数量</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>size, err := client.HLen("key").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>fmt.Println(size)</span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">7.HMGet</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key和多个字段名,批量查询多个hash字段值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// HMGet支持多个field字段名,意思是一次返回多个字段值<br><span>vals, err := client.HMGet("key","field1", "field2").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>// vals是一个数组<br><span>fmt.Println(vals)</span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">8.HMSet</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key和多个字段名和字段值,批量设置hash字段值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 初始化hash数据的多个字段值<br><span>data := make(mapinterface{})<br><span>data["id"] = 1<br><span>data["username"] = "tizi"<br><span><span>​<br><span>// 一次性保存多个hash字段值<br><span>err := client.HMSet("key", data).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">9.HSetNX</span></h2>
<p class="md-end-block md-p"><span class="md-plain">如果field字段不存在,则设置hash字段值</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>err := client.HSetNX("key", "id", 100).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">10.HDel</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据key和字段名,删除hash字段,支持批量删除hash字段</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 删除一个字段id<br><span>client.HDel("key", "id")<br><span><span>​<br><span>// 删除多个字段<br><span>client.HDel("key", "id", "username")</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">11.HExists</span></h2>
<p class="md-end-block md-p"><span class="md-plain">检测hash字段名是否存在。</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 检测id字段是否存在<br><span>err := client.HExists("key", "id").Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></pre>
<h1 class="md-end-block md-heading"><span class="md-plain">golang redis 列表(list)用法</span></h1>
<p class="md-end-block md-p"><span class="md-plain">Redis列表是简单的字符串列表,列表是有序的,列表中的元素可以重复。</span></p>
<p class="md-end-block md-p"><span class="md-plain">可以添加一个元素到列表的头部(左边)或者尾部(右边)</span></p>
<p class="md-end-block md-p"><span><strong>golang redis list数据操作常用函数:</strong></span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LPush - 从列表左边插入数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LPushX - 跟LPush的区别是,仅当列表存在的时候才插入数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">RPop - 从列表的右边删除第一个数据,并返回删除的数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">RPush - 从列表右边插入数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">RPushX - 跟RPush的区别是,仅当列表存在的时候才插入数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LPop - 从列表左边删除第一个数据,并返回删除的数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LLen - 返回列表的大小</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LRange - 返回列表的一个范围内的数据,也可以返回全部数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LRem - 删除列表中的数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LIndex - 根据索引坐标,查询列表中的数据</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">LInsert - 在指定位置插入数据</span></p>
</li>
</ul>
<h2 class="md-end-block md-heading"><span class="md-plain">1.LPush</span></h2>
<p class="md-end-block md-p"><span class="md-plain">从列表左边插入数据</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 插入一个数据<br><span>client.LPush("key", "data1")<br><span><span>​<br><span>// LPush支持一次插入任意个数据<br><span>err := client.LPush("key", 1,2,3,4,5).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">2.LPushX</span></h2>
<p class="md-end-block md-p"><span class="md-plain">跟LPush的区别是,仅当列表存在的时候才插入数据,用法完全一样。</span></p>
<h2 class="md-end-block md-heading"><span class="md-plain">3.RPop</span></h2>
<p class="md-end-block md-p"><span class="md-plain">从列表的右边删除第一个数据,并返回删除的数据</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>val, err := client.RPop("key").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>fmt.Println(val)</span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">4.RPush</span></h2>
<p class="md-end-block md-p"><span class="md-plain">从列表右边插入数据</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 插入一个数据<br><span>client.RPush("key", "data1")<br><span><span>​<br><span>// 支持一次插入任意个数据<br><span>err := client.RPush("key", 1,2,3,4,5).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">5.RPushX</span></h2>
<p class="md-end-block md-p"><span class="md-plain">跟RPush的区别是,仅当列表存在的时候才插入数据, 他们用法一样</span></p>
<h2 class="md-end-block md-heading"><span class="md-plain">6.LPop</span></h2>
<p class="md-end-block md-p"><span class="md-plain">从列表左边删除第一个数据,并返回删除的数据</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>val, err := client.LPop("key").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>fmt.Println(val)</span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">7.LLen</span></h2>
<p class="md-end-block md-p"><span class="md-plain">返回列表的大小</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>val, err := client.LLen("key").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>fmt.Println(val)</span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">8.LRange</span></h2>
<p class="md-end-block md-p"><span class="md-plain">返回列表的一个范围内的数据,也可以返回全部数据</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 返回从0开始到-1位置之间的数据,意思就是返回全部数据<br><span>vals, err := client.LRange("key",0,-1).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println(vals)</span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">9.LRem</span></h2>
<p class="md-end-block md-p"><span class="md-plain">删除列表中的数据</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 从列表左边开始,删除100, 如果出现重复元素,仅删除1次,也就是删除第一个<br><span>dels, err := client.LRem("key",1,100).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>// 如果存在多个100,则从列表左边开始删除2个100<br><span>client.LRem("key",2,100)<br><span><span>​<br><span><span>​<br><span>// 如果存在多个100,则从列表右边开始删除2个100<br><span>// 第二个参数负数表示从右边开始删除几个等于100的元素<br><span>client.LRem("key",-2,100)<br><span><span>​<br><span>// 如果存在多个100,第二个参数为0,表示删除所有元素等于100的数据<br><span>client.LRem("key",0,100)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">10.LIndex</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据索引坐标,查询列表中的数据</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 列表索引从0开始计算,这里返回第6个元素<br><span>val, err := client.LIndex("key",5).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>fmt.Println(val)</span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">11.LInsert</span></h2>
<p class="md-end-block md-p"><span class="md-plain">在指定位置插入数据</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 在列表中5的前面插入4<br><span>// before是之前的意思<br><span>err := client.LInsert("key","before", 5, 4).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>// 在列表中 tizi365 元素的前面插入 欢迎你<br><span>client.LInsert("key","before", "tizi365", "欢迎你")<br><span><span>​<br><span>// 在列表中 tizi365 元素的后面插入 2019<br><span>client.LInsert("key","after", "tizi365", "2019")</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h1 class="md-end-block md-heading"><span class="md-plain">golang redis 集合(set)</span></h1>
<p class="md-end-block md-p"><span class="md-plain">redis的set类型(集合)是string类型数值的无序集合,并且集合元素唯一。</span></p>
<p class="md-end-block md-p"><span class="md-plain">下面介绍go redis的集合用法。</span></p>
<p class="md-end-block md-p"><span><strong>go redis 集合(set)常用函数列表</strong><span class="md-plain">:</span></span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SAdd - 添加集合元素</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SCard - 获取集合元素个数</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SIsMember - 判断元素是否在集合中</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SMembers - 获取集合中所有的元素</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SRem - 删除集合元素</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">SPop,SPopN - 随机返回集合中的元素,并且删除返回的元素</span></p>
</li>
</ul>
<h2 class="md-end-block md-heading"><span class="md-plain">1.SAdd</span></h2>
<p class="md-end-block md-p"><span class="md-plain">添加集合元素</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 添加100到集合中<br><span>err := client.SAdd("key",100).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>// 将100,200,300添加到集合中<br><span>client.SAdd("key",100, 200, 300)</span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">2.SCard</span></h2>
<p class="md-end-block md-p"><span class="md-plain">获取集合元素个数</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>size, err := client.SCard("key").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println(size)</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">3.SIsMember</span></h2>
<p class="md-end-block md-p"><span class="md-plain">判断元素是否在集合中</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 检测100是否包含在集合中<br><span>ok, _ := client.SIsMember("key", 100).Result()<br><span>if ok {<br><span><span class="cm-tab">    fmt.Println("集合包含指定元素")<br><span>}</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">4.SMembers</span></h2>
<p class="md-end-block md-p"><span class="md-plain">获取集合中所有的元素</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>es, _ := client.SMembers("key").Result()<br><span>// 返回的es是string数组<br><span>fmt.Println(es)</span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">5.SRem</span></h2>
<p class="md-end-block md-p"><span class="md-plain">删除集合元素</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 删除集合中的元素100<br><span>client.SRem("key", 100)<br><span><span>​<br><span>// 删除集合中的元素tizi和2019<br><span>client.SRem("key", "tizi", "2019")</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">6.SPop,SPopN</span></h2>
<p class="md-end-block md-p"><span class="md-plain">随机返回集合中的元素,并且删除返回的元素</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 随机返回集合中的一个元素,并且删除这个元素<br><span>val, _ := client.SPop("key").Result()<br><span>fmt.Println(val)<br><span><span>​<br><span>// 随机返回集合中的5个元素,并且删除这些元素<br><span>vals, _ := client.SPopN("key", 5).Result()<br><span>fmt.Println(vals)</span></span></span></span></span></span></span></span></pre>
<h1 class="md-end-block md-heading"><span class="md-plain">golang redis 有序集合(sorted set)</span></h1>
<p class="md-end-block md-p"><span class="md-plain">Redis 有序集合(sorted set)和集合一样也是string类型元素的集合,且不允许重复的成员,不同的是每个元素都会关联一个double类型的分数,这个分数主要用于集合元素排序。</span></p>
<p class="md-end-block md-p"><span class="md-plain">下面介绍golang redis 有序集合的用法</span></p>
<p class="md-end-block md-p"><span><strong>go redis有序集合常用函数:</strong></span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZAdd - 添加一个或者多个元素到集合,如果元素已经存在则更新分数</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZCard - 返回集合元素个数</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZCount - 统计某个分数范围内的元素个数</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZIncrBy - 增加元素的分数</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZRange,ZRevRange - 返回集合中某个索引范围的元素,根据分数从小到大排序</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZRangeByScore,ZRevRangeByScore - 根据分数范围返回集合元素,元素根据分数从小到大排序,支持分页。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZRem - 删除集合元素</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZRemRangeByRank - 根据索引范围删除元素</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZRemRangeByScore - 根据分数范围删除元素</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZScore - 查询元素对应的分数</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">ZRank, ZRevRank - 查询元素的排名</span></p>
</li>
</ul>
<h2 class="md-end-block md-heading"><span class="md-plain">1.ZAdd</span></h2>
<p class="md-end-block md-p"><span class="md-plain">添加一个或者多个元素到集合,如果元素已经存在则更新分数</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 添加一个集合元素到集合中, 这个元素的分数是2.5,元素名是tizi<br><span>err := client.ZAdd("key", redis.Z{2.5,"tizi"}).Err()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}</span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">下面是redis.Z结构体说明:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>type Z struct {<br><span><span class="cm-tab">    Scorefloat64 // 分数<br><span><span class="cm-tab">    Member interface{} // 元素名<br><span>}</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">2.ZCard</span></h2>
<p class="md-end-block md-p"><span class="md-plain">返回集合元素个数</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>size, err := client.ZCard("key").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println(size)</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">3.ZCount</span></h2>
<p class="md-end-block md-p"><span class="md-plain">统计某个分数范围内的元素个数</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 返回: 1&lt;=分数&lt;=5 的元素个数, 注意:"1", "5"两个参数是字符串<br><span>size, err := client.ZCount("key", "1","5").Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span>fmt.Println(size)<br><span><span>​<br><span>// 返回: 1&lt;分数&lt;=5 的元素个数<br><span>// 说明:默认第二,第三个参数是大于等于和小于等于的关系。<br><span>// 如果加上( 则表示大于或者小于,相当于去掉了等于关系。<br><span>size, err := client.ZCount("key", "(1","5").Result()</span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">4.ZIncrBy</span></h2>
<p class="md-end-block md-p"><span class="md-plain">增加元素的分数</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 给元素5,加上2分<br><span>client.ZIncrBy("key", 2,"5")</span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">5.ZRange,ZRevRange</span></h2>
<p class="md-end-block md-p"><span class="md-plain">返回集合中某个索引范围的元素,根据分数从小到大排序</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 返回从0到-1位置的集合元素, 元素按分数从小到大排序<br><span>// 0到-1代表则返回全部数据<br><span>vals, err := client.ZRange("key", 0,-1).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>for _, val := range vals {<br><span><span class="cm-tab">    fmt.Println(val)<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">ZRevRange用法跟ZRange一样,区别是ZRevRange的结果是按分数从大到小排序。</span></p>
<h2 class="md-end-block md-heading"><span class="md-plain">6.ZRangeByScore</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据分数范围返回集合元素,元素根据分数从小到大排序,支持分页。</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 初始化查询条件, Offset和Count用于分页<br><span>op := redis.ZRangeBy{<br><span><span class="cm-tab">    Min:"2", // 最小分数<br><span><span class="cm-tab">    Max:"10", // 最大分数<br><span><span class="cm-tab">    Offset:0, // 类似sql的limit, 表示开始偏移量<br><span><span class="cm-tab">    Count:5, // 一次返回多少数据<br><span>}<br><span class="cm-tab-wrap-hack"><span class="cm-tab">    <br><span>vals, err := client.ZRangeByScore("key", op).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>for _, val := range vals {<br><span><span class="cm-tab">    fmt.Println(val)<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">7.ZRevRangeByScore</span></h2>
<p class="md-end-block md-p"><span class="md-plain">用法类似ZRangeByScore,区别是元素根据分数从大到小排序。</span></p>
<h2 class="md-end-block md-heading"><span class="md-plain">8.ZRangeByScoreWithScores</span></h2>
<p class="md-end-block md-p"><span class="md-plain">用法跟ZRangeByScore一样,区别是除了返回集合元素,同时也返回元素对应的分数</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 初始化查询条件, Offset和Count用于分页<br><span>op := redis.ZRangeBy{<br><span><span class="cm-tab">    Min:"2", // 最小分数<br><span><span class="cm-tab">    Max:"10", // 最大分数<br><span><span class="cm-tab">    Offset:0, // 类似sql的limit, 表示开始偏移量<br><span><span class="cm-tab">    Count:5, // 一次返回多少数据<br><span>}<br><span><span>​<br><span>vals, err := client.ZRangeByScoreWithScores("key", op).Result()<br><span>if err != nil {<br><span><span class="cm-tab">    panic(err)<br><span>}<br><span><span>​<br><span>for _, val := range vals {<br><span><span class="cm-tab">    fmt.Println(val.Member) // 集合元素<br><span><span class="cm-tab">    fmt.Println(val.Score) // 分数<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">8.ZRem</span></h2>
<p class="md-end-block md-p"><span class="md-plain">删除集合元素</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 删除集合中的元素tizi<br><span>client.ZRem("key", "tizi")<br><span><span>​<br><span>// 删除集合中的元素tizi和xiaoli<br><span>// 支持一次删除多个元素<br><span>client.ZRem("key", "tizi", "xiaoli")</span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">9.ZRemRangeByRank</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据索引范围删除元素</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 集合元素按分数排序,从最低分到高分,删除第0个元素到第5个元素。<br><span>// 这里相当于删除最低分的几个元素<br><span>client.ZRemRangeByRank("key", 0, 5)<br><span><span>​<br><span>// 位置参数写成负数,代表从高分开始删除。<br><span>// 这个例子,删除最高分数的两个元素,-1代表最高分数的位置,-2第二高分,以此类推。<br><span>client.ZRemRangeByRank("key", -1, -2)</span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">10.ZRemRangeByScore</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据分数范围删除元素</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 删除范围: 2&lt;=分数&lt;=5 的元素<br><span>client.ZRemRangeByScore("key", "2", "5")<br><span><span>​<br><span>// 删除范围: 2&lt;=分数&lt;5 的元素<br><span>client.ZRemRangeByScore("key", "2", "(5")</span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">11.ZScore</span></h2>
<p class="md-end-block md-p"><span class="md-plain">查询元素对应的分数</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 查询集合元素tizi的分数<br><span>score, _ := client.ZScore("key", "tizi").Result()<br><span>fmt.Println(score)</span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">12.ZRank</span></h2>
<p class="md-end-block md-p"><span class="md-plain">根据元素名,查询集合元素在集合中的排名,从0开始算,集合元素按分数从小到大排序</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>rk, _ := client.ZRank("key", "tizi").Result()<br><span>fmt.Println(rk)</span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">ZRevRank的作用跟ZRank一样,区别是ZRevRank是按分数从大到小排序。</span></p>
<h1 class="md-end-block md-heading"><span class="md-plain">golang redis发布订阅</span></h1>
<p class="md-end-block md-p"><span class="md-plain">Redis提供了发布订阅功能,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。</span></p>
<p class="md-end-block md-p"><span class="md-plain">发布订阅架构图:</span></p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://www.tizi365.com/wp-content/uploads/2019/09/redis-pubsub.jpg"><img src="https://www.tizi365.com/wp-content/uploads/2019/09/redis-pubsub.jpg" alt="img"></span></p>
<p class="md-end-block md-p"><span class="md-plain">发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息。Redis的这种发布订阅机制与基于主题的发布订阅类似,Channel相当于主题。</span></p>
<p class="md-end-block md-p"><span class="md-plain">下面介绍golang如何使用redis的发布订阅功能。</span></p>
<p class="md-end-block md-p"><span><strong>go redis发布订阅常用函数:</strong></span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Subscribe - 订阅channel</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">PSubscribe - 订阅channel支持通配符匹配</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Publish - 将信息发送到指定的channel。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">PubSubChannels - 查询活跃的channel</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">PubSubNumSub - 查询指定的channel有多少个订阅者</span></p>
</li>
</ul>
<h2 class="md-end-block md-heading"><span class="md-plain">1.Subscribe</span></h2>
<p class="md-end-block md-p"><span class="md-plain">订阅channel</span></p>
<p class="md-end-block md-p"><span class="md-plain">例子1:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 订阅channel1这个channel<br><span>sub := client.Subscribe("channel1")<br><span><span>​<br><span>// 读取channel消息<br><span>iface, err := sub.Receive()<br><span>if err != nil {<br><span> &nbsp;// handle error<br><span>}<br><span><span>​<br><span>// 检测收到的消息类型<br><span>switch iface.(type) {<br><span>case *redis.Subscription:<br><span> &nbsp;// 订阅成功<br><span>case *redis.Message:<br><span> &nbsp;// 处理收到的消息<br><span> &nbsp;// 这里需要做一下类型转换<br><span> &nbsp;m := iface.(redis.Message)<br><span> &nbsp;// 打印收到的小<br><span><span class="cm-tab">    fmt.Println(m.Payload)<br><span>case *redis.Pong:<br><span> &nbsp;// 收到Pong消息<br><span>default:<br><span> &nbsp;// handle error<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">例子2:<span class="md-softbreak"> <span class="md-plain">使用golang channel的方式处理消息</span></span></span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 订阅channel1这个channel<br><span>sub := client.Subscribe("channel1")<br><span><span>​<br><span>// sub.Channel() 返回go channel,可以循环读取redis服务器发过来的消息<br><span>for msg := range sub.Channel() {<br><span><span class="cm-tab">    // 打印收到的消息<br><span><span class="cm-tab">    fmt.Println(msg.Channel)<br><span><span class="cm-tab">    fmt.Println(msg.Payload)<br><span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<p class="md-end-block md-p"><span class="md-plain">例子3:<span class="md-softbreak"> <span class="md-plain">取消订阅</span></span></span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 订阅channel1这个channel<br><span>sub := client.Subscribe("channel1")<br><span><span>​<br><span>// 忽略其他处理逻辑<br><span> <br><span>// 取消订阅<br><span>sub.Unsubscribe("channel1")</span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">2.PSubscribe</span></h2>
<p class="md-end-block md-p"><span class="md-plain">用法跟Subscribe一样,区别是PSubscribe订阅通道(channel)支持模式匹配。</span></p>
<p class="md-end-block md-p"><span class="md-plain">例子:</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 订阅channel1这个channel<br><span>sub := client.PSubscribe("ch_user_*")<br><span>// 可以匹配ch_user_开头的任意channel</span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">3.Publish</span></h2>
<p class="md-end-block md-p"><span class="md-plain">将消息发送到指定的channel</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 将"message"消息发送到channel1这个通道上<br><span>client.Publish("channel1","message")</span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">4.PubSubChannels</span></h2>
<p class="md-end-block md-p"><span class="md-plain">查询活跃的channel</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 没有指定查询channel的匹配模式,则返回所有的channel<br><span>chs, _ := client.PubSubChannels("").Result()<br><span>for _, ch := range chs {<br><span><span class="cm-tab">    fmt.Println(ch)<br><span>}<br><span><span>​<br><span>// 匹配user_开头的channel<br><span>chs, _ := client.PubSubChannels("user_*").Result()</span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">5.PubSubNumSub</span></h2>
<p class="md-end-block md-p"><span class="md-plain">查询指定的channel有多少个订阅者</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 查询channel1,channel2两个通道的订阅者数量<br><span>chs, _ := client.PubSubNumSub("channel1", "channel2").Result()<br><span>for ch, count := range chs {<br><span><span class="cm-tab">    fmt.Println(ch) // channel名字<br><span><span class="cm-tab">    fmt.Println(count) // channel的订阅者数量<br><span>}</span></span></span></span></span></span></span></span></pre>
<h1 class="md-end-block md-heading"><span class="md-plain">golang redis事务</span></h1>
<p class="md-end-block md-p"><span class="md-plain">redis事务可以一次执行多个命令, 并且带有以下两个重要的保证:</span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。</span></p>
</li>
</ul>
<p class="md-end-block md-p"><span class="md-plain">下面介绍golang redis事务用法。</span></p>
<p class="md-end-block md-p"><span><strong>go redis事务常用函数:</strong></span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">TxPipeline - 以Pipeline的方式操作事务</span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><span class="md-plain">Watch - redis乐观锁支持</span></p>
</li>
</ul>
<h2 class="md-end-block md-heading"><span class="md-plain">1.TxPipeline</span></h2>
<p class="md-end-block md-p"><span class="md-plain">以Pipeline的方式操作事务</span></p>
<pre class="md-fences md-end-block ty-contain-cm modeLoaded"><span>// 开启一个TxPipeline事务<br><span>pipe := client.TxPipeline()<br><span><span>​<br><span>// 执行事务操作,可以通过pipe读写redis<br><span>incr := pipe.Incr("tx_pipeline_counter")<br><span>pipe.Expire("tx_pipeline_counter", time.Hour)<br><span><span>​<br><span>// 上面代码等同于执行下面redis命令<br><span>//<br><span>// &nbsp; &nbsp; MULTI<br><span>// &nbsp; &nbsp; INCR pipeline_counter<br><span>// &nbsp; &nbsp; EXPIRE pipeline_counts 3600<br><span>// &nbsp; &nbsp; EXEC<br><span><span>​<br><span>// 通过Exec函数提交redis事务<br><span>_, err := pipe.Exec()<br><span><span>​<br><span>// 提交事务后,我们可以查询事务操作的结果<br><span>// 前面执行Incr函数,在没有执行exec函数之前,实际上还没开始运行。<br><span>fmt.Println(incr.Val(), err)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
<h2 class="md-end-block md-heading"><span class="md-plain">2.watch</span></h2>
<p class="md-end-block md-p"><span class="md-plain">redis乐观锁支持,可以通过watch监听一些Key, 如果这些key的值没有被其他人改变的话,才可以提交事务。</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义一个回调函数,用于处理事务逻辑</span>
fn := func(tx *<span style="color: rgba(0, 0, 0, 1)">redis.Tx) error {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 先查询下当前watch监听的key的值</span>
      v, err := tx.Get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">key</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">).Result()
      </span><span style="color: rgba(0, 0, 255, 1)">if</span> err != nil &amp;&amp; err !=<span style="color: rgba(0, 0, 0, 1)"> redis.Nil {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> err
      }

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里可以处理业务</span>
<span style="color: rgba(0, 0, 0, 1)">      fmt.Println(v)

      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果key的值没有改变的话,Pipelined函数才会调用成功</span>
      _, err =<span style="color: rgba(0, 0, 0, 1)"> tx.Pipelined(func(pipe redis.Pipeliner) error {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 在这里给key设置最新值</span>
            pipe.Set(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">key</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">new value</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> nil
      })
      </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> err
    }

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用Watch监听一些Key, 同时绑定一个回调函数fn, 监听Key后的逻辑写在fn这个回调函数里面
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果想监听多个key,可以这么写:client.Watch(fn, "key1", "key2", "key3")</span>
client.Watch(fn, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">key</span><span style="color: rgba(128, 0, 0, 1)">"</span>)</pre>
</div>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/root-123/p/16572175.html
頁: [1]
查看完整版本: go-redis