<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Redis on ~Wumi~</title><link>http://wumi.uno/tags/redis/</link><description>Recent content from ~Wumi~</description><generator>Hugo</generator><language>zh-cn</language><managingEditor>xxx@example.com (Wumi)</managingEditor><webMaster>xxx@example.com (Wumi)</webMaster><copyright>本博客所有文章除特别声明外，均采用 BY-NC-SA 许可协议。转载请注明出处！</copyright><lastBuildDate>Thu, 24 Apr 2025 12:36:52 +0800</lastBuildDate><atom:link href="http://wumi.uno/tags/redis/index.xml" rel="self" type="application/rss+xml"/><item><title>关于go-redis</title><link>http://wumi.uno/post/go-redis/</link><pubDate>Thu, 24 Apr 2025 12:36:52 +0800</pubDate><author>xxx@example.com (Wumi)</author><guid>http://wumi.uno/post/go-redis/</guid><description>
<![CDATA[<h1>关于go-redis</h1><p>作者：Wumi（xxx@example.com）</p>
        
          <h1 id="关于-txpipelined">
<a class="header-anchor" href="#%e5%85%b3%e4%ba%8e-txpipelined"></a>
关于 TxPipelined
</h1><h2 id="redis里的事务">
<a class="header-anchor" href="#redis%e9%87%8c%e7%9a%84%e4%ba%8b%e5%8a%a1"></a>
redis里的事务？
</h2><p>首先，和sql（如mysql）不同，redis的事务不支持回滚操作，就只是一次性，顺序性执行一个队列中存放的一系列命令。</p>
<ul>
<li>相关命令：</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">MULTI    :开启事务
</span></span><span class="line"><span class="cl">EXEC     :提交事务
</span></span><span class="line"><span class="cl">DISCARD  :取消事务
</span></span><span class="line"><span class="cl">WATCH    :监听一个（多个）键，如果事务执行前监听的键被修改，则事务取消
</span></span><span class="line"><span class="cl">UNWATCH  :取消监听
</span></span></code></pre></div><p>redis的原子性：<strong>事务里的命令，要么全部执行，要么全部不执行。(不是全部成功,,,)</strong><br>
<del>（不行，不能回滚保证全部成功的原子性好抽象QAQ ,但毕竟redis主打一个快嘛）</del><br>
如果一组命令里有语法错误，redis会放弃事务里所有任务，其他很少情况下整个事务会被丢弃。</p>
<h2 id="pipeline--pipelined--txpipelined">
<a class="header-anchor" href="#pipeline--pipelined--txpipelined"></a>
Pipeline / Pipelined / TxPipelined
</h2><p>管道会把一系列命令打包起来一起发送，能减少网络往返次数，提高性能。管道里的命令会顺序执行。</p>
<ul>
<li>Pipeline : 会返回一个pipeliner，手动添加命令，手动pipe.Exec()并处理返回的错误</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">pipe</span> <span class="o">:=</span> <span class="nx">rdb</span><span class="p">.</span><span class="nf">Pipeline</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="nx">pipe</span><span class="p">.</span><span class="nf">Set</span><span class="p">(</span><span class="s">&#34;key&#34;</span><span class="p">,</span><span class="s">&#34;value&#34;</span><span class="p">,</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="o">*</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="nx">_</span><span class="p">,</span><span class="nx">err</span> <span class="o">:=</span> <span class="nx">pipe</span><span class="p">.</span><span class="nf">Exec</span><span class="p">()</span> <span class="p">;</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="c1">//错误处理
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><ul>
<li>Pipelined：把pipeline封装了一下，不用手动提交Exec()</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">_</span><span class="p">,</span><span class="nx">err</span> <span class="o">:=</span> <span class="nx">rdb</span><span class="p">.</span><span class="nf">Pipelined</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">pipe</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">Pipeliner</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">pipe</span><span class="p">.</span><span class="nf">Set</span><span class="p">(</span><span class="s">&#34;key&#34;</span><span class="p">,</span><span class="s">&#34;value&#34;</span><span class="p">,</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="o">*</span><span class="mi">5</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">nil</span>  
</span></span><span class="line"><span class="cl"><span class="p">})</span>  
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">//错误处理  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><ul>
<li>TxPipelined：加了事务的管道，也能保证这一组命令不被其他客户端打断；可以使用WATCH监听键</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">_</span><span class="p">,</span><span class="nx">err</span> <span class="o">:=</span> <span class="nx">rdb</span><span class="p">.</span><span class="nf">TxPipelined</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">pipe</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">Pipeliner</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">pipe</span><span class="p">.</span><span class="nf">Set</span><span class="p">(</span><span class="s">&#34;key&#34;</span><span class="p">,</span><span class="s">&#34;value&#34;</span><span class="p">,</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="o">*</span><span class="mi">5</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">nil</span>  
</span></span><span class="line"><span class="cl"><span class="p">})</span>  
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">//错误处理  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><h2 id="分析">
<a class="header-anchor" href="#%e5%88%86%e6%9e%90"></a>
分析
</h2><p>看看这个代码：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">lll</span> <span class="o">:=</span> <span class="s">&#34;默认&#34;</span>  
</span></span><span class="line"><span class="cl"><span class="nx">_</span><span class="p">,</span><span class="nx">err</span> <span class="o">:=</span> <span class="nx">rdb</span><span class="p">.</span><span class="nf">TxPipelined</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">pipe</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">Pipeliner</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">pipe</span><span class="p">.</span><span class="nf">Set</span><span class="p">(</span><span class="s">&#34;key&#34;</span><span class="p">,</span><span class="s">&#34;value&#34;</span><span class="p">,</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="o">*</span><span class="mi">5</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">pipe</span><span class="p">.</span><span class="nf">Incr</span><span class="p">(</span><span class="s">&#34;k&#34;</span><span class="p">)</span>  
</span></span><span class="line"><span class="cl">    <span class="nx">_</span><span class="p">,</span><span class="nx">lll</span> <span class="p">=</span> <span class="nx">pipe</span><span class="p">.</span><span class="nf">Get</span><span class="p">(</span><span class="s">&#34;k&#34;</span><span class="p">).</span><span class="nf">Result</span><span class="p">()</span>  
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">nil</span>  
</span></span><span class="line"><span class="cl"><span class="p">})</span>  
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>  
</span></span><span class="line"><span class="cl">    <span class="c1">//错误处理  
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>  
</span></span><span class="line"><span class="cl"><span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">lll</span><span class="p">)</span>
</span></span></code></pre></div><p>输出的<code>lll</code>会是什么呢?<br>
首先，如果Incr()一个不存在的键，会自动生成一个对应的，ttl为-1(不过期)的键值对再执行自增操作。<br>
所以？嘿嘿不是1，而是“” 空字符串。<br>
在事务/管道里使用Result()是没有意义的，在事务里，命令都还没有真正执行，都只是先被塞到队列里，但是Result()总得返回点东西吧，就返回的默认的&quot;&ldquo;并把&quot;默认&quot;覆盖了。要真想要这个值，要么把这个命令从事务里拿出来，要么接收一下TxPipelined返回的cmd，从里面读取（这里面放的是各个命令返回的结果）。<br>
所以所以，<strong>不要在事务里用Result()</strong> ~~~</p>
        
        <hr><p>本文2025-04-24首发于<a href='http://wumi.uno/'>~Wumi~</a>，最后修改于2025-04-24</p>]]></description></item></channel></rss>