In the project application, there was the following scenario:
an int type serial number is required to be sent in the interface. Due to the multi-threading mode, if timestamps are used, there may be duplicates (of course, the probability is very small).
So I thought of using an independent self-incrementing sequence to solve this problem.
The current database is: mysql
, because mysql is not the same as oracle, and does not support direct sequence, so it is necessary to create a table to simulate the function of sequence. The reason for the sql statement is as follows:
Step 1: Create the --Sequence management table
Step 2: Create -- a function that takes the current value
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 ;
Step 3: Create -- a function that takes the next value
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 ;
Step 4: Create -- a function to update the current value
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 ;
Step 5: Test the function function
When the above four steps are completed, you can use the following data to set the name of the sequence to be created, set the initial value, and get the current value and the next value.
- INSERT INTO sequence VALUES ('TestSeq', 0, 1);----Add a sequence name and initial value, as well as the self-amplification degree
- SELECT SETVAL('TestSeq', 10);---Set the initial value of the specified 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: In the application, there is also a way to use java code to simulate the self-incrementing sequence. The specific idea is to create a table to store the sequence, and then call the sql statement through java to query and modify the value of the specified sequence name in this table. , please add synchronized in this way. The specific code will not be uploaded here, because it has been implemented and has not been tested.
In oracle, sequence provides multiple tables and multiple fields that can share a unique value. There are self-increasing columns in Mysql, which can basically meet the requirements of PK. However, there are restrictions on auto-incrementing columns:
a. It can only be used for one field in the table, and one cannot have more than two auto-increment columns at the same time;
b. Self-incrementing columns must be defined as key (PK or FK);
c. Self-incrementing columns cannot be shared by multiple tables;
d. When the insert statement does not include an auto-increment field or sets its value to NULL, the value will be filled in automatically.
In the case where the order of the fields is not required to increase, the sequence can be implemented in Mysql. Let's look at the following example:
DROPTABLE IF EXISTS sequence; -- Build a sequence table and specify that the seq column is an unsigned large integer that supports unsigned values: 0 (default) to 18446744073709551615 (0 to 2^64–1). CREATETABLE sequence ( name VARCHAR(50)NOTNULL, current_value BIGINTUNSIGNED NOTNULL DEFAULT 0, increment INTNOT NULL DEFAULT 1, PRIMARYKEY (name) – The existence of duplicate seqs is not allowed. ) ENGINE=InnoDB; DELIMITER / DROPFUNCTION IF EXISTS currval / CREATEFUNCTION currval(seq_name VARCHAR(50)) RETURNSBIGINT BEGIN DECLAREvalue BIGINT; SELECTcurrent_value INTOvalue FROMsequence WHEREupper(name) = upper(seq_name);-- 大小写不区分. RETURNvalue; END; / DELIMITER ; DELIMITER / DROPFUNCTION IF EXISTS nextval / CREATEFUNCTION nextval (seq_name VARCHAR(50)) RETURNSBIGINT BEGIN DECLAREvalue BIGINT; UPDATEsequence SETcurrent_value = current_value + increment WHEREupper(name) = upper(seq_name); RETURNcurrval(seq_name); END; / DELIMITER ; DELIMITER / DROPFUNCTION IF EXISTS setval / CREATEFUNCTION setval (seq_name VARCHAR(50), value BIGINT) RETURNSBIGINT BEGIN UPDATEsequence SETcurrent_value = value WHEREupper(name) = upper(seq_name); RETURNcurrval(seq_name); END; / DELIMITER ;
在 SQL 中使用序列:
创建序列,往sequence表插入值即可:
mysql>insertinto sequence set name='myseq';
查看当前已建序列:
mysql>select* fromsequence;
+-------+---------------+-----------+ | name | current_value | increment | +-------+---------------+-----------+ | myseq | 0 | 1 | +-------+---------------+-----------+ 1 row in set (0.00 sec)
获得序列的下一个值,第一次使用,因此值为1:
mysql>selectnextval('myseq');
+------------------+ | nextval('myseq') | +------------------+ | 1 | +------------------+ 1 row in set (0.00 sec)