[转]在MySQL中创建实现自增的序列(Sequence)的教程
原文地址:https://www.jb51.net/article/76124.htm
项目应用中,曾有以下一个场景:
接口中要求发送一个int类型的流水号,由于多线程模式,如果用时间戳,可能会有重复的情况(当然概率很小)。
所以想到了利用一个独立的自增的sequence来解决该问题。
当前数据库为:mysql
由于mysql和oracle不太一样,不支持直接的sequence,所以需要创建一张table来模拟sequence的功能,理由sql语句如下:
第一步:创建--Sequence 管理表
- DROP TABLE IF EXISTS sequence;
- CREATE TABLE sequence (
- name VARCHAR(50) NOT NULL,
- current_value INT NOT NULL,
- increment INT NOT NULL DEFAULT 1,
- PRIMARY KEY (name)
- ) ENGINE=InnoDB;
第二步:创建--取当前值的函数
- DROP FUNCTION IF EXISTS currval;
- DELIMITER $
- CREATE FUNCTION currval (seq_name VARCHAR(50))
- RETURNS INTEGER
- LANGUAGE SQL
- DETERMINISTIC
- CONTAINS SQL
- SQL SECURITY DEFINER
- COMMENT ''
- BEGIN
- DECLARE value INTEGER;
- SET value = 0;
- SELECT current_value INTO value
- FROM sequence
- WHERE name = seq_name;
- RETURN value;
- END
- $
- DELIMITER ;
第三步:创建--取下一个值的函数
- DROP FUNCTION IF EXISTS nextval;
- DELIMITER $
- CREATE FUNCTION nextval (seq_name VARCHAR(50))
- RETURNS INTEGER
- LANGUAGE SQL
- DETERMINISTIC
- CONTAINS SQL
- SQL SECURITY DEFINER
- COMMENT ''
- BEGIN
- UPDATE sequence
- SET current_value = current_value + increment
- WHERE name = seq_name;
- RETURN currval(seq_name);
- END
- $
- DELIMITER ;
第四步:创建--更新当前值的函数
- DROP FUNCTION IF EXISTS setval;
- DELIMITER $
- CREATE FUNCTION setval (seq_name VARCHAR(50), value INTEGER)
- RETURNS INTEGER
- LANGUAGE SQL
- DETERMINISTIC
- CONTAINS SQL
- SQL SECURITY DEFINER
- COMMENT ''
- BEGIN
- UPDATE sequence
- SET current_value = value
- WHERE name = seq_name;
- RETURN currval(seq_name);
- END
- $
- 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语句查询下一个值,这样就解决了流水号唯一的问题。
贴出部分代码(已测试通过)
- public void testGetSequence() {
- Connection conn = JDBCUtils.getConnection(url, userName, password);
- String sql = "SELECT CURRVAL('TestSeq');";
- PreparedStatement ptmt = null;
- ResultSet rs = null;
- try {
- ptmt = conn.prepareStatement(sql);
- rs = ptmt.executeQuery();
- int count = 0;
- while (rs.next()) {
- count = rs.getInt(1);
- }
- System.out.println(count);
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- JDBCUtils.close(rs, ptmt, conn);
- }
- }
ps:在应用中,还有一种用java代码去实现模拟自增sequence的方式,具体思路是创建一张存放sequence的table,然后通过java调用sql语句去查询和修改这个table中指定sequence名称的值,这种方式请加上synchronized。具体代码这里就不上传了,因为实现了,未去测试过。
在 oracle 中, sequence 提供多表多字段可共用一个不重复值。 Mysql 中存在自增列,基本可以满足 PK 的要求。但自增列存在限制:
a. 只能用于表中的一个字段,一张不能同时存在两个以上的自增列 ;
b. 自增列必须被定义为 key ( PK 或 FK ) ;
c. 自增列不能被多个表共用 ;
d. 当 insert 语句不包括自增字段或将其值设置为 NULL 时,该值会自动填上。
在不要求字段顺序递增的情况下,可以在 Mysql 中实现序列,再来看下面一个例子:
- DROP TABLE IF EXISTS sequence;
- -- 建sequence表,指定seq列为无符号大整型,可支持无符号值:0(default)到18446744073709551615(0到2^64–1)。
- CREATE TABLE sequence (
- name VARCHAR(50) NOT NULL,
- current_value BIGINT UNSIGNED NOT NULL DEFAULT 0,
- increment INT NOT NULL DEFAULT 1,
- PRIMARY KEY (name) -- 不允许重复seq的存在。
- ) ENGINE=InnoDB;
- DELIMITER /
- DROP FUNCTION IF EXISTS currval /
- CREATE FUNCTION currval(seq_name VARCHAR(50))
- RETURNS BIGINT
- BEGIN
- DECLARE value BIGINT;
- SELECT current_value INTO value
- FROM sequence
- WHERE upper(name) = upper(seq_name); -- 大小写不区分.
- RETURN value;
- END;
- /
- DELIMITER ;
- DELIMITER /
- DROP FUNCTION IF EXISTS nextval /
- CREATE FUNCTION nextval (seq_name VARCHAR(50))
- RETURNS BIGINT
- BEGIN
- DECLARE value BIGINT;
- UPDATE sequence
- SET current_value = current_value + increment
- WHERE upper(name) = upper(seq_name);
- RETURN currval(seq_name);
- END;
- /
- DELIMITER ;
- DELIMITER /
- DROP FUNCTION IF EXISTS setval /
- CREATE FUNCTION setval (seq_name VARCHAR(50), value BIGINT)
- RETURNS BIGINT
- BEGIN
- UPDATE sequence
- SET current_value = value
- WHERE upper(name) = upper(seq_name);
- RETURN currval(seq_name);
- END;
- /
- DELIMITER ;
在 SQL 中使用序列:
创建序列,往sequence表插入值即可:
- mysql> insert into sequence set name='myseq';
查看当前已建序列:
- mysql> select * from sequence;
- +-------+---------------+-----------+
- | name | current_value | increment |
- +-------+---------------+-----------+
- | myseq | 0 | 1 |
- +-------+---------------+-----------+
- 1 row in set (0.00 sec)
获得序列的下一个值,第一次使用,因此值为1:
- mysql> select nextval('myseq');
- +------------------+
- | nextval('myseq') |
- +------------------+
- | 1 |
- +------------------+
- 1 row in set (0.00 sec)
[转]在MySQL中创建实现自增的序列(Sequence)的教程的更多相关文章
- 在MySQL中创建实现自增的序列(Sequence)的教程
这篇文章主要介绍了在MySQL中创建实现自增的序列(Sequence)的教程,分别列举了两个实例并简单讨论了一些限制因素,需要的朋友可以参考下 项目应用中,曾有以下一个场景: 接口中要求发送一个int ...
- mysql 中创建存储过程
mysql中创建存储过程和存储函数虽相对其他的sql语言相对复杂,但却功能强大,存储过程和存储函数更像是一种sql语句中特定功能的一种封装,这种封装可以大大简化外围调用语句的复杂程度. 首先以表emp ...
- EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型
官方教程:https://docs.microsoft.com/en-us/aspnet/core/data/?view=aspnetcore-2.1 使用EF CodeFirst在MySql中创建新 ...
- C# 利用mysql.data 在mysql中创建数据库及数据表
C# 利用mysql.data 在mysql中创建数据库及数据表 using System; using System.Collections.Generic; using System.Linq; ...
- mysql中创建函数时报错信息
报错信息如下 ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its ...
- mysql中,创建包含json数据类型的表?创建json表时候的注意事项?查询json字段中某个key的值?
需求描述: 在mysql数据库中,创建包含json数据类型的表.记录下,在创建的过程中,需要注意的问题. 操作过程: 1.通过以下的语句,创建包含json数据类型的表 mysql> create ...
- MySql中创建存储过程
MySQL 存储过程是从 MySQL 5.0 开始增加的新功能.存储过程的优点有一箩筐.不过最主要的还是执行效率和SQL 代码封装.特别是 SQL 代码封装功能,如果没有存储过程,在外部程序访问数据库 ...
- mysql中各种复杂的增删改查
1.mysql查出数据表中连续出现三次或三次以上的数据 建一张表如下:表名为 number 1.1 要求找出num列连续出现三次或三次以上的数据: select * from number where ...
- mysql 中创建递归函数
1.在navicat中创建递归函数 BEGIN ) DEFAULT ''; ) default ''; ) default ''; ) default rootId; ; WHILE rootId i ...
随机推荐
- 【java】自定义异常类
目录结构: contents structure [+] 为什么需要自定义异常类 自定义异常的方式 实例 日常日志 一,为什么需要自定义异常类 当java中的异常类型没有能够满足我们所需的异常的时候就 ...
- struts2 标签变形和 样式class无效 问题解决方法
在jsp使用Struts2标签的时候会发现,出现严重变形问题. <s:textfield type="text" name="username" labe ...
- Snip for Mac(桌面截图工具)安装
1.软件简介 Snip 一款用于桌面截图的工具. 2.资源列表 链接 提取密码 系统要求 软件语言 Snip for Mac v2.0 (5771) fgab macOS 10.6.8 及以上 ...
- SQL 中 Arg的使用
今天在写SQL脚本时用到了Arg这个函数,发现了一个问题就是如果取平均数的字段是int类型那么,无论你怎么平均都不会有小数位出来. 因为Arg默认将你取的平均值转换为了你的字段对应的类型int.那么如 ...
- CListCtrl行高问题最终解决方法
原文链接: http://blog.csdn.net/benny5609/article/details/1967078 解决方案: 1. 设置List Control的属性 Owen Draw Fi ...
- Python 文件 seek() 方法
概述 Python 文件 seek() 方法用于移动文件读取指针到指定位置. 语法 seek() 方法语法如下: fileObject.seek(offset[,whence]) 参数 offset ...
- 【解决】网站运行一段时间后就无法访问,重启Tomcat才能恢复
[背景]重新部署了网站,运行环境是Linux(centOS6.5)+Tomcat7+mysql5,作了相关安全配置和系统优化工作: [问题]运行几天后,出现了网站无法访问的现象,具体是进入网站首页时页 ...
- 小程序踩过的一个小坑---解析二维码decodeURIComponent() url解码
因为我们需要用户扫码进入小程序,每一个货柜都有一个对应的二维码,当然每个二维码里的信息也不一样.用户扫码进入小程序之后,二维码的信息会以参数q带进去,而我们只能在onLoad事件中拿到这个参数, 但是 ...
- Netflix OSS、Spring Cloud还是Kubernetes? 都要吧!
Netflix OSS是由Netflix公司主持开发的一套代码框架和库,目的是解决上了规模之后的分布式系统可能出现的一些有趣问题.对于当今时代的Java开发者们来说,Netflix OSS简直就是在云 ...
- Android Eclipse Libs 的 jar 源码查看 (或者新版本ADT无法查看jar的源码)
问题背景:在使用比较新的ADT的时候,无法导入Jar中的源码包查看源码.只好自己打开压缩包,实在恼火.在半年前,只好这样. 问题解决方案:我就以 " android-support-v4.j ...