原文地址:https://www.jb51.net/article/76124.htm

项目应用中,曾有以下一个场景:
接口中要求发送一个int类型的流水号,由于多线程模式,如果用时间戳,可能会有重复的情况(当然概率很小)。
所以想到了利用一个独立的自增的sequence来解决该问题。
当前数据库为:mysql
由于mysql和oracle不太一样,不支持直接的sequence,所以需要创建一张table来模拟sequence的功能,理由sql语句如下:
第一步:创建--Sequence 管理表

  1. DROP TABLE IF EXISTS sequence;
  2. CREATE TABLE sequence (
  3. name VARCHAR(50) NOT NULL,
  4. current_value INT NOT NULL,
  5. increment INT NOT NULL DEFAULT 1,
  6. PRIMARY KEY (name)
  7. ) ENGINE=InnoDB;

第二步:创建--取当前值的函数

  1. DROP FUNCTION IF EXISTS currval;
  2. DELIMITER $
  3. CREATE FUNCTION currval (seq_name VARCHAR(50))
  4. RETURNS INTEGER
  5. LANGUAGE SQL
  6. DETERMINISTIC
  7. CONTAINS SQL
  8. SQL SECURITY DEFINER
  9. COMMENT ''
  10. BEGIN
  11. DECLARE value INTEGER;
  12. SET value = 0;
  13. SELECT current_value INTO value
  14. FROM sequence
  15. WHERE name = seq_name;
  16. RETURN value;
  17. END
  18. $
  19. DELIMITER ;

第三步:创建--取下一个值的函数

  1. DROP FUNCTION IF EXISTS nextval;
  2. DELIMITER $
  3. CREATE FUNCTION nextval (seq_name VARCHAR(50))
  4. RETURNS INTEGER
  5. LANGUAGE SQL
  6. DETERMINISTIC
  7. CONTAINS SQL
  8. SQL SECURITY DEFINER
  9. COMMENT ''
  10. BEGIN
  11. UPDATE sequence
  12. SET current_value = current_value + increment
  13. WHERE name = seq_name;
  14. RETURN currval(seq_name);
  15. END
  16. $
  17. DELIMITER ;

第四步:创建--更新当前值的函数

  1. DROP FUNCTION IF EXISTS setval;
  2. DELIMITER $
  3. CREATE FUNCTION setval (seq_name VARCHAR(50), value INTEGER)
  4. RETURNS INTEGER
  5. LANGUAGE SQL
  6. DETERMINISTIC
  7. CONTAINS SQL
  8. SQL SECURITY DEFINER
  9. COMMENT ''
  10. BEGIN
  11. UPDATE sequence
  12. SET current_value = value
  13. WHERE name = seq_name;
  14. RETURN currval(seq_name);
  15. END
  16. $
  17. DELIMITER ;

第五步:测试函数功能
当上述四步完成后,可以用以下数据设置需要创建的sequence名称以及设置初始值和获取当前值和下一个值。

  • INSERT INTO sequence VALUES ('TestSeq', 0, 1);----添加一个sequence名称和初始值,以及自增幅度
  • SELECT SETVAL('TestSeq', 10);---设置指定sequence的初始值
  • SELECT CURRVAL('TestSeq');--查询指定sequence的当前值
  • SELECT NEXTVAL('TestSeq');--查询指定sequence的下一个值

在java代码中,可直接创建sql语句查询下一个值,这样就解决了流水号唯一的问题。
贴出部分代码(已测试通过)

  1. public void testGetSequence() {
  2. Connection conn = JDBCUtils.getConnection(url, userName, password);
  3. String sql = "SELECT CURRVAL('TestSeq');";
  4. PreparedStatement ptmt = null;
  5. ResultSet rs = null;
  6. try {
  7. ptmt = conn.prepareStatement(sql);
  8. rs = ptmt.executeQuery();
  9. int count = 0;
  10. while (rs.next()) {
  11. count = rs.getInt(1);
  12. }
  13. System.out.println(count);
  14. } catch (SQLException e) {
  15. e.printStackTrace();
  16. } finally {
  17. JDBCUtils.close(rs, ptmt, conn);
  18. }
  19. }

ps:在应用中,还有一种用java代码去实现模拟自增sequence的方式,具体思路是创建一张存放sequence的table,然后通过java调用sql语句去查询和修改这个table中指定sequence名称的值,这种方式请加上synchronized。具体代码这里就不上传了,因为实现了,未去测试过。

在 oracle 中, sequence 提供多表多字段可共用一个不重复值。 Mysql 中存在自增列,基本可以满足 PK 的要求。但自增列存在限制:

a. 只能用于表中的一个字段,一张不能同时存在两个以上的自增列 ;

b. 自增列必须被定义为 key ( PK 或 FK ) ;

c. 自增列不能被多个表共用 ;

d. 当 insert 语句不包括自增字段或将其值设置为 NULL 时,该值会自动填上。

在不要求字段顺序递增的情况下,可以在 Mysql 中实现序列,再来看下面一个例子:

  1. DROP TABLE IF EXISTS sequence;
  2.  
  3. -- sequence表,指定seq列为无符号大整型,可支持无符号值:0(default)到1844674407370955161502^641)。
  4. CREATE TABLE sequence (
  5. name VARCHAR(50) NOT NULL,
  6. current_value BIGINT UNSIGNED NOT NULL DEFAULT 0,
  7. increment INT NOT NULL DEFAULT 1,
  8. PRIMARY KEY (name) -- 不允许重复seq的存在。
  9. ) ENGINE=InnoDB;
  10.  
  11. DELIMITER /
  12.  
  13. DROP FUNCTION IF EXISTS currval /
  14.  
  15. CREATE FUNCTION currval(seq_name VARCHAR(50))
  16. RETURNS BIGINT
  17. BEGIN
  18. DECLARE value BIGINT;
  19. SELECT current_value INTO value
  20. FROM sequence
  21. WHERE upper(name) = upper(seq_name); -- 大小写不区分.
  22. RETURN value;
  23. END;
  24. /
  25.  
  26. DELIMITER ;
  27.  
  28. DELIMITER /
  29.  
  30. DROP FUNCTION IF EXISTS nextval /
  31.  
  32. CREATE FUNCTION nextval (seq_name VARCHAR(50))
  33. RETURNS BIGINT
  34. BEGIN
  35. DECLARE value BIGINT;
  36. UPDATE sequence
  37. SET current_value = current_value + increment
  38. WHERE upper(name) = upper(seq_name);
  39. RETURN currval(seq_name);
  40. END;
  41. /
  42.  
  43. DELIMITER ;
  44.  
  45. DELIMITER /
  46.  
  47. DROP FUNCTION IF EXISTS setval /
  48.  
  49. CREATE FUNCTION setval (seq_name VARCHAR(50), value BIGINT)
  50. RETURNS BIGINT
  51. BEGIN
  52. UPDATE sequence
  53. SET current_value = value
  54. WHERE upper(name) = upper(seq_name);
  55. RETURN currval(seq_name);
  56. END;
  57. /
  58.  
  59. DELIMITER ;

在 SQL 中使用序列:
创建序列,往sequence表插入值即可:

  1. mysql> insert into sequence set name='myseq';

查看当前已建序列:

  1. mysql> select * from sequence;
  1. +-------+---------------+-----------+
  2. | name | current_value | increment |
  3. +-------+---------------+-----------+
  4. | myseq | 0 | 1 |
  5. +-------+---------------+-----------+
  6. 1 row in set (0.00 sec)

获得序列的下一个值,第一次使用,因此值为1:

  1. mysql> select nextval('myseq');
  1. +------------------+
  2. | nextval('myseq') |
  3. +------------------+
  4. | 1 |
  5. +------------------+
  6. 1 row in set (0.00 sec)

[转]在MySQL中创建实现自增的序列(Sequence)的教程的更多相关文章

  1. 在MySQL中创建实现自增的序列(Sequence)的教程

    这篇文章主要介绍了在MySQL中创建实现自增的序列(Sequence)的教程,分别列举了两个实例并简单讨论了一些限制因素,需要的朋友可以参考下 项目应用中,曾有以下一个场景: 接口中要求发送一个int ...

  2. mysql 中创建存储过程

    mysql中创建存储过程和存储函数虽相对其他的sql语言相对复杂,但却功能强大,存储过程和存储函数更像是一种sql语句中特定功能的一种封装,这种封装可以大大简化外围调用语句的复杂程度. 首先以表emp ...

  3. EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型

    官方教程:https://docs.microsoft.com/en-us/aspnet/core/data/?view=aspnetcore-2.1 使用EF CodeFirst在MySql中创建新 ...

  4. C# 利用mysql.data 在mysql中创建数据库及数据表

    C# 利用mysql.data 在mysql中创建数据库及数据表 using System; using System.Collections.Generic; using System.Linq; ...

  5. mysql中创建函数时报错信息

    报错信息如下 ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its ...

  6. mysql中,创建包含json数据类型的表?创建json表时候的注意事项?查询json字段中某个key的值?

    需求描述: 在mysql数据库中,创建包含json数据类型的表.记录下,在创建的过程中,需要注意的问题. 操作过程: 1.通过以下的语句,创建包含json数据类型的表 mysql> create ...

  7. MySql中创建存储过程

    MySQL 存储过程是从 MySQL 5.0 开始增加的新功能.存储过程的优点有一箩筐.不过最主要的还是执行效率和SQL 代码封装.特别是 SQL 代码封装功能,如果没有存储过程,在外部程序访问数据库 ...

  8. mysql中各种复杂的增删改查

    1.mysql查出数据表中连续出现三次或三次以上的数据 建一张表如下:表名为 number 1.1 要求找出num列连续出现三次或三次以上的数据: select * from number where ...

  9. mysql 中创建递归函数

    1.在navicat中创建递归函数 BEGIN ) DEFAULT ''; ) default ''; ) default ''; ) default rootId; ; WHILE rootId i ...

随机推荐

  1. 【java】自定义异常类

    目录结构: contents structure [+] 为什么需要自定义异常类 自定义异常的方式 实例 日常日志 一,为什么需要自定义异常类 当java中的异常类型没有能够满足我们所需的异常的时候就 ...

  2. struts2 标签变形和 样式class无效 问题解决方法

    在jsp使用Struts2标签的时候会发现,出现严重变形问题. <s:textfield type="text" name="username" labe ...

  3. Snip for Mac(桌面截图工具)安装

    1.软件简介    Snip 一款用于桌面截图的工具. 2.资源列表 链接 提取密码 系统要求 软件语言 Snip for Mac v2.0 (5771) fgab macOS 10.6.8 及以上 ...

  4. SQL 中 Arg的使用

    今天在写SQL脚本时用到了Arg这个函数,发现了一个问题就是如果取平均数的字段是int类型那么,无论你怎么平均都不会有小数位出来. 因为Arg默认将你取的平均值转换为了你的字段对应的类型int.那么如 ...

  5. CListCtrl行高问题最终解决方法

    原文链接: http://blog.csdn.net/benny5609/article/details/1967078 解决方案: 1. 设置List Control的属性 Owen Draw Fi ...

  6. Python 文件 seek() 方法

    概述 Python 文件 seek() 方法用于移动文件读取指针到指定位置. 语法 seek() 方法语法如下: fileObject.seek(offset[,whence]) 参数 offset  ...

  7. 【解决】网站运行一段时间后就无法访问,重启Tomcat才能恢复

    [背景]重新部署了网站,运行环境是Linux(centOS6.5)+Tomcat7+mysql5,作了相关安全配置和系统优化工作: [问题]运行几天后,出现了网站无法访问的现象,具体是进入网站首页时页 ...

  8. 小程序踩过的一个小坑---解析二维码decodeURIComponent() url解码

    因为我们需要用户扫码进入小程序,每一个货柜都有一个对应的二维码,当然每个二维码里的信息也不一样.用户扫码进入小程序之后,二维码的信息会以参数q带进去,而我们只能在onLoad事件中拿到这个参数, 但是 ...

  9. Netflix OSS、Spring Cloud还是Kubernetes? 都要吧!

    Netflix OSS是由Netflix公司主持开发的一套代码框架和库,目的是解决上了规模之后的分布式系统可能出现的一些有趣问题.对于当今时代的Java开发者们来说,Netflix OSS简直就是在云 ...

  10. Android Eclipse Libs 的 jar 源码查看 (或者新版本ADT无法查看jar的源码)

    问题背景:在使用比较新的ADT的时候,无法导入Jar中的源码包查看源码.只好自己打开压缩包,实在恼火.在半年前,只好这样. 问题解决方案:我就以 " android-support-v4.j ...