一个生成全局唯一Sequence ID的高并发工厂类 (Java)
发表于10个月前(2013-03-21 17:26)
阅读( 593) | 评论( 1)
14人收藏此文章,
我要收藏
赞0
Sequence是数据库系统按照一定规则自动增加的数字序列。这个序列一般作为代理主键(因为不会重复),没有其他任何意义。
Sequence是数据库系统的特性,有的数据库实现了Sequence,有的则没有。比如Oracle、DB2、PostgreSQL数据库实现Sequence, 而MySQL、SQL Server、Sybase等数据库没有Sequence。
那么如何给一个不支持Sequence的数据库增加支持呢?
下面将给出Java版本的代码。这个代码还实现了对 Sequence ID的高效缓存,并不是每一次调用都会对数据库进行访问,在高并发环境下性能优异。
1. SequenceId.java
03 | public class SequenceId { |
04 | public static final long NOT_FOUND = 0 ; |
05 | private static final long STEP = 100 ; |
06 | private final SequenceIdProvider provider; |
07 | private final String name; |
08 | private final long beginValue; |
11 | protected SequenceId(SequenceIdProvider provider, String name, long beginValue) { |
12 | this .provider = provider; |
14 | this .beginValue = beginValue; |
17 | if (beginValue <= 0 ) { |
18 | throw new IllegalArgumentException( "begin value must be great than zero." ); |
22 | public String getName() { |
26 | public synchronized long nextVal() { |
28 | value = provider.load(name); |
29 | if (value <= NOT_FOUND) { |
30 | value = beginValue - 1 ; |
32 | provider.store(name, value + STEP); |
37 | if (value % STEP == 0 ) { |
38 | provider.store(name, value + STEP); |
2. SequenceIdProvider.java
03 | public interface SequenceIdProvider { |
05 | public SequenceId create(String name); |
07 | public SequenceId create(String name, long begin); |
09 | public long load(String name); |
11 | public void store(String name, long value); |
3. JdbcSequenceIdProvider.java
004 | import javax.sql.DataSource; |
006 | public class JdbcSequenceIdProvider implements SequenceIdProvider { |
008 | private static final String TABLE_NAME = "_SEQUENCE_" ; |
009 | private final DataSource dataSource; |
011 | public JdbcSequenceIdProvider(DataSource dataSource) { |
012 | this .dataSource = dataSource; |
014 | confirmTableExists(); |
018 | public SequenceId create(String name) { |
019 | return new SequenceId( this , name, 1 ); |
023 | public SequenceId create(String name, long begin) { |
024 | return new SequenceId( this , name, begin); |
027 | private void confirmTableExists() { |
028 | Connection conn = null ; |
030 | conn = dataSource.getConnection(); |
032 | ResultSet rs = conn.getMetaData().getTables( null , null , TABLE_NAME, null ); |
033 | boolean found = rs.next(); |
037 | Statement stmt = conn.createStatement(); |
038 | String sql = "create table " + TABLE_NAME + " (name varchar(50) not null, next_val long not null, primary key(name))" ; |
042 | } catch (SQLException e) { |
043 | throw new RuntimeException(e); |
049 | private void close(Connection conn) { |
053 | } catch (SQLException e) { |
054 | throw new RuntimeException(e); |
060 | public long load(String name) { |
061 | long value = SequenceId.NOT_FOUND; |
062 | Connection conn = null ; |
064 | conn = dataSource.getConnection(); |
065 | String sql = "select next_val from " + TABLE_NAME + " where name=?" ; |
066 | PreparedStatement ps = conn.prepareStatement(sql); |
067 | ps.setString( 1 , name); |
068 | ResultSet rs = ps.executeQuery(); |
070 | value = rs.getLong( 1 ); |
074 | } catch (SQLException e) { |
075 | throw new RuntimeException(e); |
083 | public void store(String name, long value) { |
084 | Connection conn = null ; |
086 | conn = dataSource.getConnection(); |
087 | String sql = "update " + TABLE_NAME + " set next_val=? where name=?" ; |
088 | PreparedStatement ps = conn.prepareStatement(sql); |
089 | ps.setLong( 1 , value); |
090 | ps.setString( 2 , name); |
091 | int updated = ps.executeUpdate(); |
095 | sql = "insert into " + TABLE_NAME + " (name, next_val) values (?,?)" ; |
096 | ps = conn.prepareStatement(sql); |
097 | ps.setString( 1 , name); |
098 | ps.setLong( 2 , value); |
102 | } catch (SQLException e) { |
103 | throw new RuntimeException(e); |
4. GlobalSequenceIdProvider.java
03 | import javax.sql.DataSource; |
05 | public class GlobalSequenceIdProvider { |
07 | private static final SequenceId global; |
08 | private static final SequenceId table1; |
09 | private static final SequenceId table2; |
12 | SequenceIdProvider provider = new JdbcSequenceIdProvider(getDataSource()); |
13 | global = provider.create( "global" ); |
14 | table1 = provider.create( "table1" ); |
15 | table2 = provider.create( "table2" , 1000 ); |
18 | public static long nextVal() { |
19 | return global.nextVal(); |
22 | public static long nextVal_table1() { |
23 | return table1.nextVal(); |
26 | public static long nextVal_table2() { |
27 | return table2.nextVal(); |
30 | private static DataSource getDataSource() { |
|