集群下synchronized的问题和序列表的实现
自行实现的序列表,用synchronized 进行查询和更新,
但是集群部署的时候,因为有多台应用,synchronized并没有用。
解决方案:
集群后synchronized失效是必然的,类似的同步操作必须转换为通过全局的同步互斥机制,例如数据库锁,这样会造成性能的急剧下降,如果系统有大量sychronized的处理不适合做集群。
考虑乐观锁策略
oracle下,建议直接调用数据库的序列实现。
mysql下的话,不支持直接的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); } } |

浙公网安备 33010602011771号