当前位置: 首页 > news >正文

Mysql 实现 序列的使用

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

?
1
2
3
4
5
6
7
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;

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 ;

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 ;

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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语句查询下一个值,这样就解决了流水号唯一的问题。
贴出部分代码(已测试通过)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 中实现序列,再来看下面一个例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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表插入值即可:

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

查看当前已建序列:

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

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

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

 

转载于:https://www.cnblogs.com/nierzhao/p/6893033.html

相关文章:

  • 转载 FreeNAS的安装和简单配置 http://freenas.cn/?p=342
  • (转载)Linux 多线程条件变量同步
  • 编程语言类型划分
  • 关于sublime text 3 pylinter的错误提示
  • nil的使用
  • #Java第九次作业--输入输出流和文件操作
  • 路径层、裁剪区域
  • to_char函数 官方文档详解(数字格式转换和日期转换)
  • 【代码笔记】iOS-NSJSONSerializationDemo
  • java做http接口
  • Android异步载入全解析之开篇瞎扯淡
  • python版本与编码的区别
  • hdu5304 Eastest Magical Day Seep Group#39;s Summer 状压dp+生成树
  • Visual Studio - 引入动态库
  • iOS private-api-checker私有API检测
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • Docker 笔记(2):Dockerfile
  • git 常用命令
  • gulp 教程
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • Redux系列x:源码分析
  • 程序员该如何有效的找工作?
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 多线程事务回滚
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 面试总结JavaScript篇
  • 我这样减少了26.5M Java内存!
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (2)STL算法之元素计数
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (ZT)薛涌:谈贫说富
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .bat文件调用java类的main方法
  • .Net程序猿乐Android发展---(10)框架布局FrameLayout
  • .NET开发者必备的11款免费工具
  • .NET委托:一个关于C#的睡前故事
  • @RestControllerAdvice异常统一处理类失效原因
  • [ web基础篇 ] Burp Suite 爆破 Basic 认证密码
  • []串口通信 零星笔记
  • [android] 切换界面的通用处理
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [AutoSar]BSW_OS 01 priority ceiling protocol(PCP)
  • [BUG]vscode插件live server无法自动打开浏览器
  • [C++11 多线程同步] --- 条件变量的那些坑【条件变量信号丢失和条件变量虚假唤醒(spurious wakeup)】
  • [Electron]ipcMain.on和ipcMain.handle的区别
  • [HNOI2008]Cards
  • [IDF]啥?
  • [J2ME]如何替换Google Map静态地图自带的Marker
  • [LeetCode] Max Points on a Line
  • [LeetCode]—Add Binary 两个字符串二进制相加