きり丸の技術日記

技術検証したり、資格等をここに残していきます。

DBからJavaのResultSetにLocalDateTimeやBigInteger等の基本型以外の型を直接設定する

TwitterやJavaのオープンチャットででたまーにResultSetから直接LocalDateTimeBigIntegerを取得できずに、一旦Stringjava.sql.Dateで取得した後に変換している、ということを見かけることがありました。直接LocalDateTimeやBigIntegerで取得することができます。

今回の記事では、DBからJavaのResultSetを駆使し、JdbcTemplate#queryにてLocalDateTimeBigIntegerを取得する方法を記載します。

環境

  • Java
    • 15
  • org.springframework.boot
    • 2.5.2
  • org.flywaydb:flyway-core
    • 7.7.3
  • com.h2database:h2
    • 2.1.2.200
  • org.springframework.boot:spring-boot-starter-test
    • 2.5.2
  • org.springframework.boot:spring-boot-starter-jdbc
    • 2.5.2
  • org.mybatis.spring.boot:mybatis-spring-boot-starter
    • 2.2.0
  • org.mybatis.spring.boot:mybatis-spring-boot-starter-test
    • 2.2.0
  • Gradle

ゴール

JavaのJdbcTemplate#queryにてRLocalDateTimeBigIntegerを取得します。

要約

ResultSetgetObjectの第二パラメータに必要なクラスを指定します。

方法

事前準備

テーブルとデータを準備します。

CREATE TABLE BOOK
(
    isbn         VARCHAR(13) PRIMARY KEY,
    money        INT,
    number       INT,
    generate_date TIMESTAMP
);

INSERT INTO BOOK VALUES ('9784798126708', 1000, 10, '2021-07-02 12:34:56')

取得用のDtoを作成する

jdbcTemplateから取得するための型を用意します。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BookDto implements Serializable {
  private String isbn;
  private int money;
  private BigInteger number;
  private LocalDateTime generateDate;
}

Javaで取得する

JdbcTemplate#queryを使用します。ResultSetgetObjectの第二パラメータに必要なクラスを指定します。

今回の場合は、BigInteger.class, LocalDateTime.classを指定することができます。

protected List<BookDto> findBookList() {
  return jdbcTemplate.query("SELECT * FROM BOOK", (rs, i) ->
      BookDto.builder()
          .isbn(rs.getString("isbn"))
          .money(rs.getInt("money"))
          .number(rs.getObject("number", BigInteger.class))
          .generateDate(rs.getObject("generate_date", LocalDateTime.class))
          .build());
}

備考

単純にラップした自作型に関してはマッピングできないようです。ISBNクラスを作成してマッピングしようとしましたが、エラーログが出力されました。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BookDto implements Serializable {
  private Isbn isbn;
  private int money;
  private BigInteger number;
  private LocalDateTime generateDate;
}

@Value
@AllArgsConstructor
public class Isbn {
  private final String isbn;
}

protected List<BookDto> findBookList() {
  return jdbcTemplate.query("SELECT * FROM BOOK", (rs, i) ->
      BookDto.builder()
          .isbn(rs.getObject("isbn", Isbn.class))
          .money(rs.getInt("money"))
          .number(rs.getObject("number", BigInteger.class))
          .generateDate(rs.getObject("generate_date", LocalDateTime.class))
          .build());
}
Caused by: org.h2.jdbc.JdbcSQLFeatureNotSupportedException: 機能はサポートされていません: "kirimaru.biz.domain.book.Isbn"
Feature not supported: "kirimaru.biz.domain.book.Isbn" [50100-200]

素直に構造に合わせたRowMapperを作成しましょう。

        .isbn(new Isbn(rs.getString("isbn"))

ソースコード

単体テストも行えるようにしています。セットアップのためのFlyway等は今回の記事では解説しません。

終わりに

地味ながら、低くない頻度で見かけるので記事にしました。

やってることは簡単なので、困っている人に届くと嬉しいです。


この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。

f:id:nainaistar:20210702212124p:plain