mysql自增函数_在MySQL中创建实现自增的序列(Sequence)的教程
本文主要阐述了在MySQL环境中构建自增序列的方法,并提供了两个具体案例以供参考。详细说明了两个具体案例,并对一些潜在问题进行了简要分析。如需进一步了解,请参考上述内容。
项目应用中,曾有以下一个场景:
在接口中需要生成一个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 ;
第五步:测试函数功能
完成上述四个步骤后,在以下数据中配置所需的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);
}
}
在实际应用场景中,在开发模拟自增序列的方法时,请考虑以下步骤:首先建立一个存储指定序列名称位置的数据表;随后会使用Java语言执行SQL语句来获取并更新该数据表中的相关信息。为了确保该操作具有原子性,请在此方案的基础上加入同步机制(Synchronized)。已完成该功能后未进行测试验证。
Oracle 的 sequence 功能允许多个表和字段共享一个唯一的值。 MySQL 提供自增列作为主键候选元组的有效实现方式。 然而需要注意的是自增列并非无限制的应用。
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)
