Id Generation Service

시스템 개발 시 공통적으로 많이 쓰이는 기능 중의 하나로, 유일한 ID를 생성하기 위해 사용할 수 있다. 주로 데이터베이스에 새로운 레코드를 추가하기 위해 ID를 받거나 혹은 파일 시스템에 새로이 파일을 생성하고자 할때 유일한 파일명을 보장 받기 위해 유일한 ID가 필요하다. Id Generation 서비스에 대한 구현체는 3가지이며, 다음은 각 구현체별 사용법이다.

UUIdGenerationService

새로운 ID를 생성하기 위해 UUID 생성 알고리즘을 이용하여 16 바이트 길이의 ID를 생성한다. 다음과 같은 설정을 가질 수 있다.
Tag Name config:configuration Attribute Description Required Default Value Child Tag
ROOT address
address 공간 상의 유일성을 보장하기 위해 IP 주소나 네트웍 카드의 MAC 주소를 값으로 지정한다. IP 주소일 경우 필드간의 구분은 “.”로 하고, MAC 주소일 경우는 “:”로 한다. 지정하지 않으면 UUIdGenerationService는 내부에서 MAC 주소를 랜덤하게 생성한다. False 랜덤 생성

Samples

  • Configuration
  • 다음은 IdGernerationService에서 사용할 UUIdGernerationService와 그 속성을 정의한 applicationContext-idgeneration.xml 의 일부이다. MAC Address를 기반으로 유일한 Id를 생성하는 UUIdGenerationService Bean을 정의하고 있다.
    <bean name="UUIdGenerationService" class="anyframe.core.idgen.impl.UUIdGenerationService">
       <config:configuration>
          <address>00:00:F0:79:19:5B</address>
       </config:configuration>
    </bean>
  • TestCase
  • 다음은 앞서 정의한 속성 설정을 기반으로 하여 UUIdGenerationService로부터 유일한 id를 추출하는 IdGenerationServiceTest.java 코드의 일부이다.
    /**
     * UUIdGeneration을 이용한 testcase
     */
    public void testUUIdGeneration() throws Exception {
    	IIdGenerationService id = (IIdGenerationService) context
    			.getBean("UUIdGenerationService");
    	// 신규 ID를 받아온다.			
    	String newId=id.getNextStringId();
    	if(newId==null)
    		throw new Exception("fail to get UUIdgeneration");
    }

SequenceIdGenerationService

새로운 ID를 생성하기 위해 Database의 SEQUENCE 문을 사용하는 서비스이다. 다음과 같은 설정을 가질 수 있다.
Property Name
Description
Required
Default Value
dataSource SequenceIdGenerationService를 사용하는 경우 필요하다. Database 연결을 위한 DataSourceService를 지정한다.
Y
N/A

Tag Name
Attribute Name
Description
Required
Default Value
Child Tag
config:configuration
query
config:configuration big-decimals long 타입의 ID 대신 BigDecimal 타입의 ID를 사용하고자 할 때 정의한다.
N
false
query SEQUENCE SQL을 value로써 지정한다.(Database에 의존적이다.)
Y
N/A

Samples

  • Configuration
  • 다음은 SuquenceIdGernerationService의 속성을 정의한 applicationContext-idgeneration.xml 의 일부이다. SuquenceIdGernerationService는 common_datasource를 통하여 Connection 객체를 얻게 되며, idsequence라는 이름의 Sequence를 사용한다. 따라서, 다음 속성 기반의 SuquenceIdGernerationService 실행을 위해서는 idsequence라는 이름의 Sequence가 생성되어 있어야 한다.
    <bean name="SequenceIdGenerationService" 
        class="anyframe.core.idgen.impl.SequenceIdGenerationService" 
        destroy-method="destroy">
        <property name="dataSource">
           <ref bean="common_datasource"/>
        </property>
        <config:configuration  big-decimals="true">	
           <query>SELECT NEXT VALUE FOR idsequence FROM DUAL</query>		
        </config:configuration>
    </bean>
  • TestCase
  • 다음은 앞서 정의한 속성 설정을 기반으로 하여 sequenceIdgenerationService를 이용하여 유일한 id를 추출하는 IdGenerationServiceTest.java 코드의 일부이다.
    /**
     * SequenceIdGeneration 이용한 testcase
     */
    public void testSequenceIdGeneration() throws Exception {
        IIdGenerationService id = (IIdGenerationService) context
            .getBean("SequenceIdGenerationService");
        // 다음 스트링ID를 받아온다.			
        String newId = id.getNextStringId();
        // 다음 스트링 ID는 초기값 0을 주었으므로 0이 될 것이다. 
        // cf)CREATE SEQUENCE idsequence START WITH 0	
        if (!newId.equals("0"))
            throw new Exception("fail to get SequenceIdgeneration");
    }

TableIdGenerationService

TableIdGenerator는 ID를 관리하는 특정 테이블을 이용하여 유일한 Id를 얻는다. ID 관리를 위한 이 테이블은 table_name(CHAR 또는 VARCHAR타입), next_id(integer type)과 같이 두 칼럼을 필요로 한다.
또한 Generation Strategy 을 적용할 경우, TableIdGeneration Service는 신규 id에 정의된 Strategy를 적용한 결과값을 전달해준다.
TableIdGeneration Service는 다음과 같은 설정을 가질 수 있다.
Property Name
Description
Required
Default Value
dataSource TableIdGeneration Service를 사용하는 경우 필요하다. Database 연결을 위한 DataSourceService를 지정한다.
Y
N/A
strategy Id Generation Strategy를 지정한다. 기본적으로 prefix, 신규 Id, fillChar를 조합한 Id를 전달하는 MixPrefix를 사용한다.
N
N/A

Tag Name
Attribute Name
Description
Required
Default Value
Child Tag
config:configuration block-size ID를 발급할 때마다 매번 데이터베이스에 접속한다면 시스템 성능 저하를 가져오므로, 한번에 TableIdGenerationService 내에서 발급 받아올 ID의 개수를 정할 수 있다.
N
10
config:configuration table 현재까지 발급한 ID를 저장하기 위한 테이블 이름.
N
ids
config:configuration key-table 어떤 것에 발급하는 ID인지를 저장하기 위한 키 이름. 예를 들어, Order와 Product, 두 가지에 ID를 발급할 상황이라면 하나는 key-table 속성값으로 “order”, 또다른 하나는 "product"라고 지정할 수 있다.
N
id
config:configuration big-decimals Long 타입의 ID 대신 BigDecimal 타입의 ID를 사용하고자 할 때 쓴다.
N
id

Samples

  • Configuration
  • 다음은 TableIdGernerationService의 속성을 정의한 applicationContext-idgeneration.xml 의 일부이다. TableIdGernerationService는 기본적으로 mixPrefix Strategy를 적용하고 있으며, test 테이블에 유일한 id를 제공하기 위해 ids라는 ID 관리 테이블을 사용할 것이다. 따라서, 다음 속성 기반의 TableIdGernerationService 실행을 위해서는 ids라는 테이블에 [TABLE_NAME:test, NEXT_ID:초기값]와 같은 정보가 추가되어 있어야 한다.
    <bean name="TableIdGenerationService" 
        class="anyframe.core.idgen.impl.TableIdGenerationService" 
        destroy-method="destroy">
        <property name="dataSource" ref="common_datasource"/>
        <property name="strategy" ref="mixPrefix"/>
        <config:configuration  block-size="1" table="ids" key-table="test"/>
    </bean>
  • TestCase
  • 다음은 앞서 정의한 속성 설정을 기반으로 하여 tableIdgenerationService를 이용하여 유일한 id를 추출하는 IdGenerationServiceTest.java 코드의 일부이다.
    /**
     * TableIdGeneration 이용한 testcase
     */
    public void testTableIdGeneration() throws Exception {
    	IIdGenerationService id = (IIdGenerationService) context
    	   .getBean("TableIdGenerationService");
    	// 다음 스트링 ID를 받아온다.	
    	String newId = id.getNextStringId();
     
    	//다음 스트링 ID는 초기값 0을
    	//주었으므로 "TEST-****0"이 될 것이다. 
    	// cf)INSERT INTO ids VALUES('test','0')
    	// 0앞의 prefix는 configuration의 mixPrefix에서 설정할 수 있다.	
    	if (!newId.equals("TEST-****0"))
    	  throw new Exception("fail to get TableIdgeneration");
    }
  • [참고] JTA Transaction Service를 사용하는 경우
  • JTA Transaction Service와 TableIdGernerationService를 함께 사용하는 경우, TableIdGernerationService는 Transaction 범주에서 제거하도록 한다.(제거하지 않은 경우, TableIdGernerationService 내에서 DB Connection 객체를 handling 하는 부분에서 에러 발생) 이를 위해 다음과 같이 Table Id Generation Service에서 사용할 DataSource를 추가로 정의하여 매핑시켜주고 Transaction에도 참여하지 않도록 한다.

    다음은 TableIdGernerationService에서 사용하는 DataSource의 속성을 정의한 applicationContext-datasource.xml 예제이다. JTA Transaction Service 사용 시 DataSource는 JNDI DataSource로 설정하여 사용하고, TableIdGernerationService에서 사용할 DataSource는 JNDI DataSource가 아닌 DBCPDataSource 등의 JDBC Driver를 이용한 DataSource를 이용하여 설정한다.
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    	<property name="jndiName" value="java:testDS"/>
    	<property name="jndiTemplate" ref="jnditemplate"/>
    </bean>
    <bean id="jnditemplate" class="org.springframework.jndi.JndiTemplate">
    	<property name="environment">
    		<props>
    			<prop key="java.naming.factory.initial">
    				org.jnp.interfaces.NamingContextFactory
    			</prop>
    			<prop key="java.naming.provider.url">
    				jnp:localhost:1099
    			</prop>
    		</props>
    	</property>
    </bean>
    
    <bean id="idgenDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
        destroy-method="close">
    	<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
    	<property name="url" value="jdbc:oracle:thin:@server.ip:1521:orcl"/>
    	<property name="username" value="user"/>
    	<property name="password" value="password"/>
    	<property name="defaultAutoCommit" value="false"/>
    </bean>
    다음은 TableIdGernerationService이 Transaction에 참여하지 않도록 정의한 applicationContext-transaction.xml 예제이다.
    <tx:advice id="noTxAdvice" transaction-manager="txManager">
    	<tx:attributes>
    		<tx:method name="*" rollback-for="Exception" propagation="NOT_SUPPORTED"/>
    	</tx:attributes>
    </tx:advice>
    
    <aop:config>
    	<aop:pointcut id="executionMethods" 
    	    expression="execution(* anyframe.core.idgen..impl.TableIdGenerationService.*(..))"/>
    	<aop:advisor advice-ref="noTxAdvice" pointcut-ref="executionMethods"/>
    </aop:config>
    다음은 TableIdGernerationService에 idgenDataSource를 설정한 applicationContext-product-idgen.xml 예제이다.
    <bean id="idGenProduct" class="anyframe.core.idgen.impl.TableIdGenerationService" 
        destroy-method="destroy">
    	<property name="dataSource" ref="idgenDataSource" />
    	<property name="strategy" ref="mixPrefixProduct" />
    	<config:configuration block-size="10" table="ids" key-table="PRODUCT" />
    </bean>

How to use a Generation Strategy

TableIdGeneration Service를 사용할 때, 유일한 id 생성 시 generation strategy를 적용할 수 있다.
generation strategy를 사용하려면 아래와 같은 방법 중 하나를 택한다.
  • dependency injection을 사용한 strategy 참조
  • <bean name="Ids-TestWithGenerationStrategy" 
        class="anyframe.core.idgen.impl.TableIdGenerationService" 
        destroy-method="destroy">
        <property name="dataSource" ref="util_datasource"/>
        <property name="strategy" ref="mixPrefix"/>
    
        <config:configuration  block-size="1" table="idstest" key-table="test"/>
    </bean>	
    <bean name="mixPrefix" class="anyframe.core.idgen.impl.strategy.MixPrefix">
    
    	<property name="prefix" value="TEST-"/>
        <property name="cipers" value="5"/>
        <property name="fillChar" value="*"/>
    </bean>
  • Id 생성시 bean id 직접 사용
  • id = idGenerator.getNextStringId("mixPrefix");
    
  • Id 생성시 strategy instance 사용
  • MixPrefix strategy = new MixPrefix("SMPL-", 5, '#');
    id = idGenerator.getNextStringId(strategy);
    

MixPrefix property 정의 방법

Anyframe Core의 TableIdGenerationService에서는 anyframe.core.idgen.impl.strategy.MixPrefix라는 기본적인 generation strategy를 제공한다. MixPrefix는 id generation strategy의 한 종류로, id 생성시 신규 id와 prefix, fillChar를 조합한다. 예를 들어 prefix가 'TEST-'이고 fillChar가 '0'이고 TableIdGenerationService를 통해 전달된 id가 '12', cipers가 5이면 전달된 id의 값은 'TEST-00012'가 된다.
<bean name="mixPrefix" class="anyframe.core.idgen.impl.strategy.MixPrefix">

    <property name="prefix" value="TEST-"/>
    <property name="cipers" value="5"/>
    <property name="fillChar" value="*"/>
</bean>

Id Generation Strategy를 implements하는 방법

starategy를 개발하기 위해서는 anyframe.core.idgen.IdGenerationStrategy를 implemensts 해야한다. 또한 makeId(String originalId) 메소드를 통해 특정 Strategy가 적용된 id를 return하도록 한다. MixPrefix안의 makeId의 구현 예는 다음과 같다.
public class MixPrefix implements IdGenerationStrategy
 {
    public String makeId(String originalId) {

            return prefix + StringUtil.fillString(originalId, fillChar, cipers);
    }	
}

Resources

  • 다운로드
  • 샘플 테스트 코드를 포함하고 있는 anyframe-idgenerationtest-src.zip 파일을 다운받은 후, 테스트 환경 설정 을 참조하여 위에서 제시한 예제 코드를 실행해 볼 수 있다.
    Name
    Download
    anyframe-idgenerationtest-src.zip
    Download