<p align="left">在涉及数据库存储数据的时候,经常会遇到唯一值问题,有的是主键带来的限制,有的则是业务上的需要。</p> <p align="left">下面介绍几种唯一值的获取或者生产方法:</p> <div align="left">先建一个测试用的表tbl_user,有三个字段:Id、Name、Age,其中Id为主键。</div> <div class="csharpcode"> <pre><span class="lnum"> 1: </span><span class="kwrd">drop</span> <span class="kwrd">table</span> <span class="kwrd">if</span> <span class="kwrd">exists</span> `tbl_user`;</pre>
<pre><span class="lnum"> 2: </span><span class="kwrd">create</span> <span class="kwrd">table</span> </pre>
<pre><span class="lnum"> 3: </span>`tbl_user` (</pre>
<pre><span class="lnum"> 4: </span> `Id` <span class="kwrd">int</span>(10),</pre>
<pre><span class="lnum"> 5: </span> `Name` <span class="kwrd">varchar</span>(20),</pre>
<pre><span class="lnum"> 6: </span> `Age` <span class="kwrd">int</span>(10),</pre>
<pre><span class="lnum"> 7: </span> <span class="kwrd">PRIMARY</span> <span class="kwrd">KEY</span> (`Id`)</pre>
<pre><span class="lnum"> 8: </span>)<span class="kwrd">DEFAULT</span> CHARSET=utf8 <span class="kwrd">COLLATE</span>=utf8_unicode_ci;</pre>
<pre> </pre>
</div>
<p>插入几条数据</p>
<div class="csharpcode"> <pre><span class="lnum"> 1: </span>insert <span class="kwrd">into</span> tbl_user <span class="kwrd">values</span> (1000,"小猫",22);</pre>
<pre><span class="lnum"> 2: </span>insert <span class="kwrd">into</span> tbl_user <span class="kwrd">values</span> (1001,"小狗",22);</pre>
<pre><span class="lnum"> 3: </span>insert <span class="kwrd">into</span> tbl_user <span class="kwrd">values</span> (1002,"小刺猬",22);</pre>
<pre><span class="lnum"> 4: </span> </pre>
<pre><span class="lnum"> 5: </span><span class="kwrd">select</span> * <span class="kwrd">from</span> tbl_user;</pre>
<pre> 查询结果:</pre>
<pre><a href="http://images.cnitblog.com/blog/313639/201312/24191613-3c357956539f4e01bf32db1cd711fae2.png"> <img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnitblog.com/blog/313639/201312/24191613-bb4c16c7c5e64ed6948ffe585fcf4c0c.png" width="212" height="113" /></a></pre>
<pre> </pre>
</div> <style>
<!-- .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } --></style>
<div align="left"> <div id="codeSnippetWrapper"> <div>1.由<span style="color: #ff00ff">应用程序根据一定算法生成唯一值</span>:一般采用”<span style="color: #ff00ff">MD5(时间戳+随机数)</span>“或者其他的UUID算法,基本也比较好实现。如果遇到多机器上分布的程序访问统一数据库的表,可以把Ip、网卡号等信息考进来就可以解决了(当然可以不是简单的拼接,你可以根据需要去合适的位数经过一定的算法去获取)。</div>
<div> </div>
</div> </div>
<p align="left">2.先查询表中最大的值select max(id),再加1后作为新的值。很笨的方法。</p>
<div class="csharpcode"> <pre><span class="lnum"> 1: </span><span class="kwrd">select</span> <span class="kwrd">max</span>(Id) <span class="kwrd">from</span> tbl_user;</pre>
<pre><span class="lnum"> 2: </span>查询到的最大Id为 1002</pre>
<pre><span class="lnum"> 3: </span> </pre>
<pre><span class="lnum"> 4: </span>之后插入 1003</pre>
<pre><span class="lnum"> 5: </span> </pre>
<pre><span class="lnum"> 6: </span>insert <span class="kwrd">into</span> tbl_user <span class="kwrd">values</span> (1003,"小熊",22);</pre>
<pre><span class="lnum"> 7: </span> </pre>
</div> <style>
<!-- .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } --></style>
<p align="left">此时表中数据为</p>
<p align="left"><a href="http://images.cnitblog.com/blog/313639/201312/24191614-098ab587823c454f93a1205e7687ffc6.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnitblog.com/blog/313639/201312/24191614-f85e6a501a8944968c179873dcd58f8a.png" width="220" height="131" /></a></p>
<p align="left">3.如果是表级别的唯一,即在同一个表中某个字段唯一,可以把该字段设置为“<span style="color: #ff00ff">自增(AUTO_INCREMENT)</span>”的。这样你不必费心思去生成这个不能重复的唯一值了。但是一般应用程序是需要这个唯一值的,这个时候你就得在查询一次去获取刚才数据库自增生成的Id。比如在用户登录的时候,你要生成一个登录会话Id或者Token,这些程序一般是需要得到这个值而不是仅仅存在数据库中。生成的值,1.可以<span style="color: #ff00ff">一般的select条件查询</span>,根据条件查询刚才插入的数据。2.直接调用<span style="color: #ff00ff">select @@IDENTITY</span> 就可以得到上一次插入记录时自动产生的ID(注意是在数据库同一个连接(会话)中),用在插入后立<span style="color: #000000">即</span><span style="color: #333333">select @@IDENTITY</span> 。</p>
<p align="left">看例子,先将表中的Id字段设置为自增,再插入一条数据(不要插入Id值,让数据库自增得到值),select @@IDENTITY查询,最后验证看看。</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 5px; background-color: #f5f5f5; padding-left: 5px; padding-right: 5px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 5px" class="cnblogs_code"> <pre><span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">.#将Id改为自增(auto_increment) </span><span style="color: #0000ff">ALTER</span> <span style="color: #0000ff">TABLE</span> tbl_user CHANGE Id Id <span style="color: #0000ff">int</span> <span style="color: #808080">not</span> <span style="color: #0000ff">null</span><span style="color: #000000"> auto_increment;
#或者 先删除Id字段再添加一个Id字段 </span><span style="color: #0000ff">alter</span> <span style="color: #0000ff">table</span> tbl_user auto_increment<span style="color: #808080">=</span><span style="color: #800000; font-weight: bold">1000</span><span style="color: #000000">; </span><span style="color: #0000ff">alter</span> <span style="color: #0000ff">table</span> tbl_user <span style="color: #0000ff">drop</span> <span style="color: #0000ff">column</span><span style="color: #000000"> Id; </span><span style="color: #0000ff">alter</span> <span style="color: #0000ff">table</span> tbl_user <span style="color: #0000ff">add</span> Id <span style="color: #0000ff">int</span> <span style="color: #808080">not</span> <span style="color: #0000ff">null</span> auto_increment <span style="color: #0000ff">primary</span> <span style="color: #0000ff">key</span><span style="color: #000000"> first;
</span><span style="color: #800000; font-weight: bold">2</span><span style="color: #000000">.插入一条记录 </span><span style="color: #0000ff">insert</span> tbl_user <span style="color: #0000ff">set</span> Name<span style="color: #808080">=</span><span style="color: #ff0000">'</span><span style="color: #ff0000">小猴</span><span style="color: #ff0000">'</span>,Age<span style="color: #808080">=</span><span style="color: #800000; font-weight: bold">23</span><span style="color: #000000">;
</span><span style="color: #800000; font-weight: bold">3</span><span style="color: #000000">.查询刚才的自增Id值 </span><span style="color: #0000ff">select</span> <span style="color: #008000; font-weight: bold">@@IDENTITY</span><span style="color: #000000">; 值是1004,</span></pre>
</div>
<p> <br />验证下:select * from tbl_user;得到的当前表记录为</p>
<p><a href="http://images.cnitblog.com/blog/313639/201312/25190638-1c3a06e8e03b4077969b7b0a73ff4d77.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnitblog.com/blog/313639/201312/25190640-f6520567a8fc4d45a7a17c62cfa2a778.png" width="208" height="138" /></a></p>
<p>过刚插入的数据“小猴”id为1004,和<span style="color: #000000">select </span><span style="color: #008000; font-weight: bold"><span style="color: #333333">@@IDENTITY</span></span><span style="color: #000000">;结果一样。</span> </p>
<p>4.使用mysql的<span style="color: #ff00ff"> UUID()</span>函数。前面的自增字段(auto_increment)只能生成”表内”的唯一值,且需要搭配使其为”唯一的主键或唯一索引”,它的值是逐步增长的。这里的UUID产生的是字符串类型值,固定长度为:36个字符。UUID生成的是在时间、空间上都独一无二的值,是“随机+规则”组合而成。</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 5px; background-color: #f5f5f5; padding-left: 5px; padding-right: 5px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 5px" class="cnblogs_code"> <pre><span style="color: #0000ff">select</span><span style="color: #000000"> uuid(); </span><span style="color: #0000ff">select</span><span style="color: #000000"> uuid();
执行两次,结果: 69ad8b74</span><span style="color: #808080">-</span>6d47<span style="color: #808080">-</span>11e3<span style="color: #808080">-</span>ba6e<span style="color: #808080">-</span><span style="color: #000000">7446a08ee8ec 69b03c16</span><span style="color: #808080">-</span>6d47<span style="color: #808080">-</span>11e3<span style="color: #808080">-</span>ba6e<span style="color: #808080">-</span>7446a08ee8ec</pre>
</div>
<p>可以看到,多次调用UUID()函数得到的值不相同,它由五部分组成,并且有连字符(-)隔开,一共36个字符。其中:</p>
<p>前3组值是时间戳换算过来的,解决“时间上唯一”;</p>
<p>第4组值是暂时性保持时间戳的唯一性,重启mysql才会变动;</p>
<p>第5组是mac值转过来的,有助于解决“空间上的唯一”,同一个机器多实例的一般相同。如果mac值获取不到,则是一个随机值。</p>
<p>这些已经可以保证得到的值在时间和空间上的唯一。当然你也可以去掉连字符: select replace(uuid(),'-','')。</p>
<p>在MySQL 5.1.*及更高版本有一个变种的UUID()函数,<strong><span style="color: #ff00ff">UUID_SHORT()</span></strong>,可以生成一个17-64位无符号的整数,注意是生成的一个整数,而前面UUID()生成的是字符串。MySQL启动后第一次执行的值是通过时间戳等初始化这个值,在本次运行中再次调用的时候都加1。这个值一般比较大,可以调用right(UUID_SHORT(),9)取后面的若干位。或者,你还可以写成自定义函数,来按需生成这个值。举个例子:</p>
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 5px; background-color: #f5f5f5; padding-left: 5px; padding-right: 5px; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 5px" class="cnblogs_code"> <pre>#<span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">.调用uuid_short()函数 </span><span style="color: #0000ff">SELECT</span><span style="color: #000000"> UUID_SHORT(); </span><span style="color: #0000ff">SELECT</span><span style="color: #000000"> UUID_SHORT();
#执行两次得到的值递增的: </span><span style="color: #800000; font-weight: bold">23285634974089216</span> <span style="color: #800000; font-weight: bold">23285634974089217</span><span style="color: #000000">
#</span><span style="color: #800000; font-weight: bold">2</span><span style="color: #000000">.创建一个自定义函数,按需获取唯一值:
</span><span style="color: #0000ff">CREATE</span> DEFINER<span style="color: #808080">=</span>root
@<span style="color: #808080">%</span>
<span style="color: #0000ff">FUNCTION</span> GetUuidTest
(SysId <span style="color: #0000ff">int</span>) <span style="color: #0000ff">RETURNS</span> <span style="color: #0000ff">int</span>(<span style="color: #800000; font-weight: bold">10</span><span style="color: #000000">)
</span><span style="color: #0000ff">begin</span>
<span style="color: #0000ff">declare</span> tmpID <span style="color: #0000ff">int</span><span style="color: #000000">;
</span><span style="color: #0000ff">set</span> tmpID <span style="color: #808080">=</span> <span style="color: #800000; font-weight: bold">0</span><span style="color: #000000">;
#</span><span style="color: #0000ff">SELECT</span> UUID_SHORT() <span style="color: #0000ff">into</span><span style="color: #000000"> tmpID; #直接取值
</span><span style="color: #0000ff">SELECT</span> concat(SysId,<span style="color: #808080">right</span>(UUID_SHORT(),<span style="color: #800000; font-weight: bold">8</span>)) <span style="color: #0000ff">into</span><span style="color: #000000"> tmpID;#SysId和UUID_SHORT()后8位数拼接得到
</span><span style="color: #0000ff">return</span><span style="color: #000000"> tmpID;
</span><span style="color: #0000ff">end</span><span style="color: #000000">
#</span><span style="color: #800000; font-weight: bold">3</span>.调用自定义的函数GetUuidTest(<span style="color: #0000ff">int</span><span style="color: #000000">)函数: </span><span style="color: #0000ff">select</span> GetUuidTest(<span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">); </span><span style="color: #0000ff">select</span> GetUuidTest(<span style="color: #800000; font-weight: bold">1</span><span style="color: #000000">); </span><span style="color: #0000ff">select</span> GetUuidTest(<span style="color: #800000; font-weight: bold">2</span><span style="color: #000000">); </span><span style="color: #0000ff">select</span> GetUuidTest(<span style="color: #800000; font-weight: bold">2</span><span style="color: #000000">); #得到结果: </span><span style="color: #800000; font-weight: bold">174089233</span> #<span style="color: #800000; font-weight: bold">1</span><span style="color: #808080">+</span>uuid_short()后8位(<span style="color: #800000; font-weight: bold">74089233</span><span style="color: #000000">)组成 </span><span style="color: #800000; font-weight: bold">174089234</span> #<span style="color: #800000; font-weight: bold">1</span><span style="color: #808080">+</span>uuid_short()后8位(<span style="color: #800000; font-weight: bold">74089234</span><span style="color: #000000">)组成 </span><span style="color: #800000; font-weight: bold">274089235</span> #<span style="color: #800000; font-weight: bold">2</span><span style="color: #808080">+</span>uuid_short()后8位(<span style="color: #800000; font-weight: bold">74089235</span><span style="color: #000000">)组成 </span><span style="color: #800000; font-weight: bold">274089236</span> #<span style="color: #800000; font-weight: bold">3</span><span style="color: #808080">+</span>uuid_short()后8位(<span style="color: #800000; font-weight: bold">74089236</span><span style="color: #000000">)组成 #uuid_short()值递增,前面在加一个Id,不同的服务器IdSysId不同。
#</span><span style="color: #800000; font-weight: bold">4</span>.在例子中调用自定义函数GetUuidTest(<span style="color: #0000ff">int</span><span style="color: #000000">) 来插入记录:这时候不需要把Id设置为自增了。 </span><span style="color: #0000ff">insert</span> tbl_user <span style="color: #0000ff">set</span> Id<span style="color: #808080">=</span>GetUuidTest(<span style="color: #800000; font-weight: bold">1</span>),Name<span style="color: #808080">=</span><span style="color: #ff0000">'</span><span style="color: #ff0000">小熊猫</span><span style="color: #ff0000">'</span>,Age<span style="color: #808080">=</span><span style="color: #800000; font-weight: bold">22</span><span style="color: #000000">; </span><span style="color: #0000ff">insert</span> tbl_user <span style="color: #0000ff">set</span> Id<span style="color: #808080">=</span>GetUuidTest(<span style="color: #800000; font-weight: bold">2</span>),Name<span style="color: #808080">=</span><span style="color: #ff0000">'</span><span style="color: #ff0000">小鸭子</span><span style="color: #ff0000">'</span>,Age<span style="color: #808080">=</span><span style="color: #800000; font-weight: bold">21</span>;</pre>
</div>
<p>例子中,select * from tbl_user;得到的所有记录为</p>
<p><a href="http://images.cnitblog.com/blog/313639/201312/25190640-3ece31e0fdd3419384139d8be1d03c37.png"><img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://images.cnitblog.com/blog/313639/201312/25190641-65d418d786984345959c7acc64ee0b6f.png" width="239" height="188" /></a></p>
<p style="text-align: left"><a href="http://www.cnblogs.com/alylee/p/Mysql_UUID.html">欢迎转载,方便的话,请注明出处,谢谢</a>!</p>
<p style="text-align: left">作者:<a href="http://www.cnblogs.com/alylee">子韦一</a></p>
来源:oschina
链接:https://my.oschina.net/u/922660/blog/187508