- 숫자 형식
- 클러스터링 환경을 지원
키 생성은 데이터베이스 기반으로 구현하였으며 클러스터링 및 성능을 고려하여 키 생성을 담당하는 객체는 미리 정한 크기만큼 미리 수를 가져와 사용하는 방식으로 구현하였다.
이러한 방식이라면 키 생성을 위하여 매번 데이터베이스에 접속하지 않아도 되며, 다수의 키 생성기가 동작하더라도 중복키가 생성되지 않는다.
클래스구현은 springframework 를 사용하여 구현하였다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package architecture.common.jdbc.sequencer; public interface Sequencer { public abstract String getName(); public abstract long getNext() ; public abstract int getBlockSize(); public abstract void setBlockSize( int blockSize); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | package architecture.ee.jdbc.sequencer; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import architecture.common.jdbc.sequencer.Sequencer; public class SequencerFactory { private Log log = LogFactory.getLog(getClass()); private DataSource dataSource; public SequencerFactory(DataSource dataSource) { this .dataSource = dataSource; } public boolean isSetDataSource() { if (dataSource == null ) return false ; else return true ; } public void setDataSource(DataSource dataSource) { this .dataSource = dataSource; } public JdbcSequencer createJdbcSequencer( int sequenceID, String sequencerName, int blockSize) { JdbcSequencer impl = new JdbcSequencer(sequenceID); impl.setConfiguration(configuration); impl.setDataSource(dataSource); impl.setName(sequencerName); impl.afterPropertiesSet(); return impl; } public Map<integer sequencer= "" > getAllSequencer() { Map<integer sequencer= "" > sequencers = new HashMap<integer sequencer= "" >(); JdbcTemplate template = new JdbcTemplate(dataSource); List<jdbcsequencer> list = template.query( "SELECT SEQUENCER_ID, NAME, VALUE FROM V2_SEQUENCER" , new ResultSetExtractor<list dbcsequencer= "" >>() { public List<jdbcsequencer> extractData(ResultSet rs) throws SQLException, DataAccessException { List<jdbcsequencer> l = new ArrayList<jdbcsequencer>(); while (rs.next()) { int sequencerID = rs.getInt( 1 ); String name = rs.getString( 2 ); long value = rs.getLong( 3 ); JdbcSequencer sequencer = new JdbcSequencer(sequencerID); sequencer.setName(name); l.add(sequencer); } return l; } }); for (JdbcSequencer sequencer : list) { sequencer.setConfiguration(configuration); sequencer.setDataSource(dataSource); sequencers.put(sequencer.getSequencerId(), sequencer); } return sequencers; } } </jdbcsequencer></jdbcsequencer></jdbcsequencer></list></jdbcsequencer></integer></integer></integer> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | package architecture.ee.jdbc.sequencer; import java.sql.Types; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.support.JdbcDaoSupport; import architecture.common.jdbc.sequencer.Sequencer; public class JdbcSequencer extends JdbcDaoSupport implements Sequencer { private Log log = LogFactory.getLog(getClass()); private int type; private String name; private long currentID; private long maxID; private int blockSize; private Configuration configuration; public JdbcSequencer() { super (); } public JdbcSequencer( int seqType) { super (); this .type = seqType; this .blockSize = 10 ; this .currentID = 0L; this .maxID = 0L; } public int getSequencerId(){ return type; } public String getName() { return name; } public void setName(String name) { this .name = name; } /** * @return * @uml.property name="blockSize" */ public int getBlockSize() { return blockSize; } public void setBlockSize( int blockSize) { this .blockSize = blockSize; } public synchronized long getNext() { if (!(currentID < maxID)) { getNextBlock( 3 ); } long id = currentID; currentID++; return id; } private long createNewID( int type) { long newID = 1L ; getJdbcTemplate().update(getBoundSql( "INSERT INTO V2_SEQUENCER (VALUE,NAME,SEQUENCER_ID) VALUES (?, ?, ?)" ).getSql(), new Object[]{newID, name, type}, new int []{Types.INTEGER, Types.VARCHAR, Types.INTEGER }); return newID; } private int getNextSequencerId(){ int max = getJdbcTemplate().queryForInt( "SELECT MAX ( SEQUENCER_ID ) + 1 FROM V2_SEQUENCER" ); return max + 1 ; } /** * * * @param count 실패하였을 경우 재 시도 횟수 */ private void getNextBlock( int count) { boolean success = false ; long currentID = 1 ; try { currentID = getJdbcTemplate().queryForLong( "SELECT VALUE FROM V2_SEQUENCER WHERE SEQUENCER_ID = ?" , new Object[] { this .type }, new int [] { Types.INTEGER }); } catch (IncorrectResultSizeDataAccessException e) { this .type = getNextSequencerId(); currentID = createNewID( this .type); } long newID = currentID + blockSize; success = ( 1 == getJdbcTemplate().update( "UPDATE V2_SEQUENCER SET VALUE = ? WHERE SEQUENCER_ID = ? AND VALUE = ?" , new Object[] { newID, type, currentID }, new int [] { Types.INTEGER, Types.INTEGER, Types.INTEGER })); if (success) { this .currentID = currentID; this .maxID = newID; } if ( !success ){ try { Thread.sleep(75L); } catch (InterruptedException e) {} getNextBlock( count - 1 ); } } @Override public boolean equals(Object obj) { JdbcSequencer other = (JdbcSequencer)obj; return other.getSequencerId() == getSequencerId(); } } |
싱글톤 형태로 생성하여 사용하면 되며 테이블은 아래와 같이 생성한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | CREATE TABLE V2_SEQUENCER ( SEQUENCER_ID INTEGER NOT NULL , NAME VARCHAR2(200) NOT NULL , VALUE INTEGER NOT NULL , CONSTRAINT V2_SEQUENCER_PK PRIMARY KEY (SEQUENCER_ID) ); CREATE UNIQUE INDEX V2_SEQUENCER_NAME_IDX ON V2_SEQUENCER ( NAME ); COMMENT ON TABLE "V2_SEQUENCER" IS '애플리케이션 전역에서 사용되는 시퀀서 정보' ; COMMENT ON COLUMN "V2_SEQUENCER" . "SEQUENCER_ID" IS '시퀀서 ID' ; COMMENT ON COLUMN "V2_SEQUENCER" . "NAME" IS '시퀀서 이름' ; COMMENT ON COLUMN "V2_SEQUENCER" . "VALUE" IS '시퀀서 값' ; |
댓글 없음:
댓글 쓰기