[Toy Project] JPA Custom Sequence Generator 적용

최지나·2023년 10월 19일
4

이전 포스팅에서 JPA Entity 설계 시, 각 테이블의 Primary key 값을 [구분 문자] + "_" + sequence 의 형태로 만드는 계획을 세웠다

하지만, sequence의 관리 (증감)을 서비스 단에서 조절하게 되면 제품 등록|
삭제|업데이트 등 다양한 요청을 동시에 (여러 thread)에서 받았을 때 seq가 꼬일 수 있기에, JPA의 custom sequence generator 를 사용하여 sequence가 자동 증가되도록 변경하였다 😺

이를 구현하기 위해 CustomSequenceGenerator를 생성했다 :) 또한, Product 등록 뿐만 아니라 Category 등록 API도 생성하였다.


코드

CustomSequenceGenerator.java

  • "다음" custom sequence를 생성해주는 generator
  • JPA entity에서 prefix라는 parameter로 보내주는 값을 읽은 뒤, 이를 "_"를 구분자로 split한 뒤, db에서 해당 entity의 next seq와 합치는 작업을 수행
public class CustomSequenceGenerator extends SequenceStyleGenerator {

  private String prefix = "_";
  private int incrementSize = 1;

  @Override
  public Serializable generate(
      SharedSessionContractImplementor session,
      Object object) throws HibernateException {
    String sequenceName = prefix + "seq";

    Connection connection = null;
    try {
      ConnectionProvider connectionProvider = session
          .getFactory()
          .getServiceRegistry()
          .getService(ConnectionProvider.class);
      connection = connectionProvider.getConnection();

      PreparedStatement preparedStatement = connection.prepareStatement(
          "SELECT nextval('" + sequenceName + "')");
      ResultSet resultSet = preparedStatement.executeQuery();

      if (resultSet.next()) {
        int nextValue = resultSet.getInt(1);
        String generatedId = (prefix.contains("_") ? prefix.split("_")[0] : "") + "_" + nextValue;
        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) {
    super.configure(type, params, serviceRegistry);
    String parameterPrefix = params.getProperty("prefix");
    if (parameterPrefix != null) {
      prefix = parameterPrefix;
    }

    String incrementSizeParam = params.getProperty("increment_size");
    if (incrementSizeParam != null) {
      incrementSize = Integer.parseInt(incrementSizeParam);
    }

  }
}

주의

  • 이 때 incrementSize를 설정해주지 않으면 생성된 Custom Sequence Generator의 incrementBy가 50이 default로 설정된다
    • category_1, 다음으로 category_51이 생성되는 것이다

Category.java

  • @Parameter(name = "prefix", value = "category_code_") 해당 부분을 통해 CustomSequenceGenerator에 prefix 문자 값을 전달
  • @Parameter(name = "increment_size", value = "1") 해당 부분을 통해 seq가 1씩 증가되도록 설정
@Table(name = "category")
public class Category {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "category_code_seq")
  @GenericGenerator(name = "category_code_seq", strategy = "com.madeg.logistics.entity.CustomSequenceGenerator", parameters = {
      @Parameter(name = "prefix", value = "category_code_"), @Parameter(name = "increment_size", value = "1") })
  @Column(name = "category_code", unique = true, nullable = false)
  private String categoryCode;

  @ManyToOne
  @JoinColumn(name = "parent_category_code", referencedColumnName = "category_code")
  private Category parentCategory;

  @Column(name = "name", nullable = false)
  private String name;

  @Column(name = "description")
  private String description;

요청 확인

최상위 카테고리 과일 생성

  • 카테고리 등록 API 요청

  • DB Insert

    • 요청 시 category 코드는 요청하지 않았으나, category_1 pk가 custom sequence generator를 통해 자동 생성 된 것을 확인할 수 있다

하위 카테코리 딸기 🍓 생성

  • 카테코리 등록 API 요청

  • DB

    • 마찬가지로 category_code가 자동 생성 됨을 확인할 수 있다

자기참조 Entity 확인

  • category 테이블은 category_code가 parent_category_code를 바라보고 있는 자기 참조 구조이다. 이를 Category 등록 요청을 통해 확인해 보았다

  • 입력한 부모 카테고리 코드가 category 테이블에 존재하지 않을 경우, 카테고리 자체가 등록되지 않음을 확인할 수 있었다!


이전 포스팅에서 정리한 개선이 필요한 사항 중 custom sequence generator에 관련한 내용을 수정하였다. 남은 개선 사항들도 하나씩 수정해 나아갈 계획이다 🖊️🖊️

profile
의견 나누는 것을 좋아합니다 ლ(・ヮ・ლ)

2개의 댓글

comment-user-thumbnail
2023년 10월 19일

잘봤습니다만 ㅎ, 화면은 없나요?

1개의 답글