mysql 数据库 序列创建_在MySQL中创建实现自增的序列(Sequence)的教程
项目应用中,曾有以下一个场景:
在系统设计阶段就要求生成一个int类型的流水号,在考虑到采用多线程模式的情况下(虽然发生重复的概率较低但仍然存在一定的风险)。
所以想到了利用一个独立的自增的sequence来解决该问题。
当前数据库为:Mysql
由于MySQL和Oracle之间存在显著差异,并不具备相同的特性——尤其是无法直接使用序列号机制(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 ;
第五步:测试函数功能
当上述四步完成后,在数据库中可以创建一个名为'TestSeq'的数据字段,并将其设定为自增序列类型。字段会生成并建立名为'TestSeq'的数据序列列,并赋予其起始计数值为0以及递增步长为1。随后可以通过以下命令来管理该序列列: 首先使用INSERT INTO sequence VALUES ('TestSeq', 0, 1)这条命令会生成并建立名为'TestSeq'的数据序列列,并赋予其起始计数值为0以及递增步长为1。随后通过SETVAL('TestSeq', 10)这一命令会将指定序列'TestSeq'初始化为新的起始计数值10;通过CURRVAL('TestSeq')这一指令可以查询并返回当前的最大计数值;而NEXTVAL('Test Seq')则可以获取并返回该序列中的下一个计数位置
在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);
}
}
在应用开发中,还有一种采用Java代码实现模拟自增序列功能的方式。其具体实现思路是:建立一个用于存储sequence信息的数据表,并通过Java语言发送SQL语句指令来完成对该表中指定sequence名称值的增序操作。为确保操作的安全性,在相关修改操作前后需附加Synchronized关键字以实现锁机制控制。具体的代码实现虽已编写完成但因涉及敏感数据未公开展示,请根据现有配置自行测试验证
Oracle系统中, 序列提供了多个表和多个字段之间能够共享同一个唯一标识符的功能. MySQL中使用了自增字段来基本上能满足主键的需求. 然而, 自增列也存在一些限制:
a. 只能用于表中的一个字段,一张不能同时存在两个以上的自增列 ;
b. 自增列必须被定义为 key ( PK 或 FK ) ;
c. 自增列不能被多个表共用 ;
d. 当插入语句不包含自增字段或将数值字段设为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 中使用序列:
建立一个名为myseq的序列,并将其存储在sequence表中
查看当前已建序列: 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)
