一個生成全局唯一Sequence ID的高并發(fā)工廠類 (Java)
發(fā)表于10個月前(2013-03-21 17:26)
閱讀( 593) | 評論( 1)
14人收藏此文章,
我要收藏
贊0
Sequence是數(shù)據(jù)庫系統(tǒng)按照一定規(guī)則自動增加的數(shù)字序列,。這個序列一般作為代理主鍵(因?yàn)椴粫貜?fù)),,沒有其他任何意義,。
Sequence是數(shù)據(jù)庫系統(tǒng)的特性,有的數(shù)據(jù)庫實(shí)現(xiàn)了Sequence,,有的則沒有,。比如Oracle、DB2,、PostgreSQL數(shù)據(jù)庫實(shí)現(xiàn)Sequence, 而MySQL,、SQL Server、Sybase等數(shù)據(jù)庫沒有Sequence,。
那么如何給一個不支持Sequence的數(shù)據(jù)庫增加支持呢,?
下面將給出Java版本的代碼。這個代碼還實(shí)現(xiàn)了對 Sequence ID的高效緩存,,并不是每一次調(diào)用都會對數(shù)據(jù)庫進(jìn)行訪問,,在高并發(fā)環(huán)境下性能優(yōu)異。
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() { |
|