MySQL增加Sequence管理功能

项目应用中,曾有以下一个场景:

接口中要求发送一个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);  
    }  
}  

相关推荐