[JPA] Custom ID Sequence Generator 생성하기

koline·2024년 1월 8일

JPA

목록 보기
5/11

Custom ID Sequence Generator 생성하기


이전 포스팅에서 JPA의 ID 생성전략에 대해 작성했는데, 그 외에도 애플리케이션내부에서 또는 데이터베이스에 사전에 직접 정의해 둔 Sequence를 통해 ID를 생성하는 방식도 있다.




@GenericGenerator


이렇게 JPA에서 제공하는 GenerationType이 아닌 직접 생성한 ID Generator를 사용하고 싶을 때 사용하는 것이 @GenericGenerator 어노테이션이다.

@Entity
@Table(name="test_table")
public class TestEntity {

	// Generator에 넘겨줄 파라미터값
    private static final String ID_GEN_PARAM = "TEST";

    @Id
    @GenericGenerator(
            name = "idGenerator",
            type = CustomSequenceGenrator.class
            parameters = {
            	@Parameter(
                	name = "ID_GEN_PARAM",
                    value = ID_GEN_PARAM
                )
            }
    )
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idGenerator")
    @Column(name = "TEST_ID")
    private String id;

}

만약 미리 정의해둔 ID 생성 시퀀스가 파라미터를 필요로 하지 않는다면 @GenericGeneratorparameters 속성은 제외해도 된다.

생성된 값을 id 필드에 매핑해줘야 하기 때문에 @GeneratedValue 어노테이션도 함께 사용해줘야 한다. 이 때 @GeneratedValuegenerator 속성은 @GenericGeneratorname 속성과 맞춰줘야 한다.




IdentifierGenerator


이제 실제 ID 생성을 담당하는 CustomSequenceGenrator.class를 생성해야한다. 이름은 아무렇게나 지어도 상관없는데 중요한건@GenericGenerator에게 type 속성으로 이 클래스를 전달하기만 하면 된다.

hibernate에서 제공하는 IdentifierGenerator 인터페이스를 상속받아 implement 하면된다.

@Slf4j
public class CustomSequenceGenrator implements IdentifierGenerator {

	// 파라미터를 사용하지 않으면 필요 없다.
	private String ID_GEN_PARAM = "";

    @Override
    public Serializable generate(
            SharedSessionContractImplementor session,
            Object object
    ) throws HibernateException {
        Connection connection = null;
        try {
            ConnectionProvider connectionProvider = session
                    .getFactory()
                    .getServiceRegistry()
                    .getService(ConnectionProvider.class);
            connection = connectionProvider.getConnection();

			// 파라미터를 사용하지 않는다면 SELECT nextval() 로 해도 된다.
            PreparedStatement preparedStatement = connection.prepareStatement(
                    "SELECT nextval('" + ID_GEN_PARAM + "')");
            ResultSet resultSet = preparedStatement.executeQuery();

            if (resultSet.next()) {
                String generatedId = resultSet.getString(1);
                return generatedId;
            }
        } catch (SQLException e) {
            throw new HibernateException("Unable to generate sequence", e);
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    log.debug("Unexpected error occurs while closing the connection");
                }
            }
        }
        return null;
    }

	// 파라미터를 사용하지 않는다면 이 메서드는 오버라이드하지 않아도 무관하다.
	@Override
    public void configure(
            Type type,
            Properties params,
            ServiceRegistry serviceRegistry
    ) throws HibernateException {
    	// @GenericGenerator의 parameters 속성으로 전달해준 @Parameter의 name 속성
    	String idGenParam = params.getProperty("ID_GEN_PARAM");
        if (idGenParam != null) {
        	this.ID_GEN_PARAM = idGenParam;
        }
    }
}

idGenerator의 생성이 완료되었다. 이제 Entity의 생성 요청(INSERT 쿼리)이 발생하면 자동으로 id 생성 시퀀스를 작동시키는 쿼리 요청을 보내고 반환된 값을 Entity의 id로 설정하여 INSERT 될 것이다.

만약 데이터베이스의 Sequence를 사용하는 것이 아닌 애플리케이션 내에서 id를 생성하려고 한다면 generate 메서드에서 해당 동작을 수행 후 해당 값을 return 해주면 된다.



참고


[Database][MySQL] ID 생성 procedure 및 function 생성 - 유사 Sequence 기능

[우아한기술블로그]데이터 베이스의 자동증가 값을 기본키로 사용할 수 없을때는?

profile
개발공부를해보자

0개의 댓글