2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

データベーススペシャリスト試験の問題の実装が、プログラム学習に使えないかやってみる

2
Last updated at Posted at 2025-12-21

この記事は AI エージェント機能で進化した JetBrains の開発体験をシェアしよう by JetBrains Advent Calendar 2025 の22日目の記事です。


新しい言語やフレームワークに触れるとき、何をつくるのか迷うことはありませんか? いつも作るものを決めている方もいるでしょうが、バリエーションに欠けます。そこで、↓の記事のようにデータベーススペシャリスト試験の設計問題を題材に実装してみるのはありなのではと思いました。

しかし、問題を即実装というわけにもいきません。問題と解答から設計を起こす必要があります。この記事のように設計の勉強が目的ならいくらでも時間をかければいいけど、実装をやりたいのにこれは面倒です。

が、いまやAIの時代! この企画カレンダーの説明にも 計画 → 実装 → テスト/インスペクション の一連を IDE の中で完結させる工夫を歓迎します。 とあります。AIの力で試験問題から実装の間を簡単にできるのではないのか?
ということで、 令和3年の午後I、問1 データベース設計 を題材としてAIに設計をしてもらい、それを実装するという流れを試していこうと思います。

試験問題の詳細は 問題解答 を参照ください。

この記事でやること

  • ぱっと見大丈夫そうな設計をAIにつくらせる
  • IFとサービスを軽く実装してみる
  • Java、Springは正直なんでもいい

使用ツールとバージョン

  • IntelliJ IDEA Ultimate 2025.3.1
  • Spring Boot 4.0.1
  • Java (openjdk version "25.0.1" 2025-10-21)

IntelliJ IDEAは無料版でも問題ありません。
AI利用もこの記事程度なら無料枠で足りると思います

https://www.jetbrains.com/ja-jp/idea/download


この記事ではAIを使っていきます。IntelliJには最初からAIツールも入っており、無料で利用可能です。↓にJetbrains AIのサービスがまとまっています。最新のIntelliJでは同じAI Chat枠で全てのAIサービスが使用できるようになっています。この記事では Junie を使っていきます。

初期プロジェクトの作成

初めてのIntelliJの人がいるか知りませんが、いちから。プロジェクトを作成します。JDKとJavaを 25 に変更してます。

スクリーンショット 2025-12-19 20.08.59.png

SpringのDependenciesは Spring WebMySQL Driver を入れておきます。あとで足せばいいのでなんでも大丈夫です。

スクリーンショット 2025-12-19 20.25.07.png

プロジェクト作成が終わったらビルドを通します。右上の Run で実行、TamaCatが起動したサービスにアクセスするか聞いてくるので、 Open を選択して、動いていることを確認できました。

スクリーンショット 2025-12-19 20.15.58.png

設計

この記事はここからです。試験問題をそのまま渡して設計をお任せしましょう。とりあえず、ER図とユースケース図、シーケンス図を作ってもらいます。プロジェクトディレクトリの直下に docs/ を作成してそこにドキュメントを入れていくことにします。

AI_Chat
# Input
以下リンクの問題を題材にシステム実装を行います。
問1、ポイントシステムのデータベース設計の問題を対象に設計をします。
まずユースケース図、ER図、シーケンス図をdocs配下に作成してください。

https://www.ipa.go.jp/shiken/mondai-kaiotu/gmcbt8000000apad-att/2021r03a_db_pm1_qs.pdf
https://www.ipa.go.jp/shiken/mondai-kaiotu/gmcbt8000000apad-att/2021r03a_db_pm1_ans.pdf

# Output
令和3年度 春期 データベーススペシャリスト試験 午後I 問1「ポイントシステムのデータベース設計」に基づき、以下のドキュメントを作成しました。
作成したドキュメント
•ユースケース図 (docs/usecase.puml)
  ◦会員、システム管理者、バッチ処理による主要な機能を定義しました。
•ER図 (docs/er-diagram.puml)
  ◦会員、店舗、商品、注文、ポイント明細、ポイント種別、キャンペーンの各エンティティとリレーションを設計しました。
  ◦通常ポイントと期間限定ポイント(キャンペーン紐付け)の管理に対応しています。
•シーケンス図 (docs/sequence-diagram.puml)
  ◦会員が店舗で商品を購入し、ポイントの利用および付与が行われる一連の処理フローを記述しました。
設計のポイント
•ポイント明細に「有効期限」と「キャンペーンコード」を持たせることで、期間限定ポイントの管理を可能にしました。
•会員テーブルに「現在ポイント残高」を保持し、パフォーマンスに配慮しつつ、ポイント明細との整合性を保つ設計としています。
•トランザクション制御により、注文登録とポイント更新の原子性を保証するフローをシーケンス図に反映しました。

適当に投げても動いてくれる。さすがAI時代!
指定したディレクトリにファイルが作成されたのでみていきます。

作成されたファイルは一部 Graphviz が必要でした。
必要になったらインストールしてください

https://graphviz.org/download/

er-diagram.puml

er-diagram-0.png

sequence-diagram.puml

sequence-diagram-0.png

usecase.puml

usecase-0.png

作成されたファイルの内容は試験問題とは異なるし、シーケンス図は足りないと思いますが、このまま進めます。ここで重要なのは 使えそうな設計 なので問題ありません。
この設計を実装し終わった後に改修課題として使用してください。

実装

設計はできたので、あとは実装していくだけです。
ここではざっくりどんなコードになるか見たいと思います。Junieに会員のユースケースを対象にIFを作ってもらうことにしました。

AI_Chat
# Input
会員のユースケースを実装します。インターフェースを作成してください。

# Output
会員のユースケース(商品購入、ポイント利用、残高参照、情報登録・変更)を実現するためのインターフェースとDTOを作成しました。
作成したファイル
•サービスインターフェース
  ◦src/main/java/com/example/r3pm/service/MemberService.java: 会員の主要なアクション(登録、更新、残高参照、注文処理)を定義。
•DTO (Data Transfer Objects)
  ◦src/main/java/com/example/r3pm/dto/MemberDTO.java: 会員基本情報の受け渡し用。
  ◦src/main/java/com/example/r3pm/dto/PointBalanceDTO.java: ポイント残高および有効期限付き明細の参照用。
  ◦src/main/java/com/example/r3pm/dto/OrderRequestDTO.java: 商品購入時の注文・ポイント利用リクエスト用。
  ◦src/main/java/com/example/r3pm/dto/OrderResponseDTO.java: 注文完了時の結果(付与ポイント、新残高など)用。

設計のポイント
•MemberService#placeOrder メソッドにより、「商品を購入する(UC1)」と「ポイントを利用する(UC2)」を一つのトランザクション的な処理として扱えるように設計しました。
•PointBalanceDTO 内に PointDetailDTO を持たせることで、期間限定ポイントの有効期限なども参照可能な構造にしました。
•ER図のデータ構造(会員番号がVARCHAR(10)など)に合わせ、適切なデータ型を採用しています。

古めかしいコードが出力されました。
DTOは長いので折りたたみにしておきます。興味あれば見てください。

作成されたDTOファイル
com/example/r3pm/dto/MemberDTO.java
package com.example.r3pm.dto;

public class MemberDTO {
    private String memberId;
    private String name;
    private String email;
    private Integer currentPointBalance;

    // Getters and Setters
    public String getMemberId() { return memberId; }
    public void setMemberId(String memberId) { this.memberId = memberId; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public Integer getCurrentPointBalance() { return currentPointBalance; }
    public void setCurrentPointBalance(Integer currentPointBalance) { this.currentPointBalance = currentPointBalance; }
}
com/example/r3pm/dto/OrderRequestDTO.java
package com.example.r3pm.dto;

public class OrderRequestDTO {
    private String memberId;
    private String shopCode;
    private Integer totalAmount;
    private Integer usePoints;

    // Getters and Setters
    public String getMemberId() { return memberId; }
    public void setMemberId(String memberId) { this.memberId = memberId; }
    public String getShopCode() { return shopCode; }
    public void setShopCode(String shopCode) { this.shopCode = shopCode; }
    public Integer getTotalAmount() { return totalAmount; }
    public void setTotalAmount(Integer totalAmount) { this.totalAmount = totalAmount; }
    public Integer getUsePoints() { return usePoints; }
    public void setUsePoints(Integer usePoints) { this.usePoints = usePoints; }
}
com/example/r3pm/dto/OrderResponseDTO.java
package com.example.r3pm.dto;

public class OrderResponseDTO {
    private String orderId;
    private Integer earnedPoints;
    private Integer newBalance;

    // Getters and Setters
    public String getOrderId() { return orderId; }
    public void setOrderId(String orderId) { this.orderId = orderId; }
    public Integer getEarnedPoints() { return earnedPoints; }
    public void setEarnedPoints(Integer earnedPoints) { this.earnedPoints = earnedPoints; }
    public Integer getNewBalance() { return newBalance; }
    public void setNewBalance(Integer newBalance) { this.newBalance = newBalance; }
}
com/example/r3pm/dto/PointBalanceDTO.java
package com.example.r3pm.dto;

import java.time.LocalDate;
import java.util.List;

public class PointBalanceDTO {
    private String memberId;
    private Integer totalBalance;
    private List<PointDetailDTO> details;

    public static class PointDetailDTO {
        private Integer points;
        private LocalDate expiryDate;
        private String campaignName;

        // Getters and Setters
        public Integer getPoints() { return points; }
        public void setPoints(Integer points) { this.points = points; }
        public LocalDate getExpiryDate() { return expiryDate; }
        public void setExpiryDate(LocalDate expiryDate) { this.expiryDate = expiryDate; }
        public String getCampaignName() { return campaignName; }
        public void setCampaignName(String campaignName) { this.campaignName = campaignName; }
    }

    // Getters and Setters
    public String getMemberId() { return memberId; }
    public void setMemberId(String memberId) { this.memberId = memberId; }
    public Integer getTotalBalance() { return totalBalance; }
    public void setTotalBalance(Integer totalBalance) { this.totalBalance = totalBalance; }
    public List<PointDetailDTO> getDetails() { return details; }
    public void setDetails(List<PointDetailDTO> details) { this.details = details; }
}

Serviceをみると、会員のユースケースが揃っているのがわかります。ロジックを書いていくだけの状態になっていますね。

com/example/r3pm/service/MemberService.java
package com.example.r3pm.service;

import com.example.r3pm.dto.MemberDTO;
import com.example.r3pm.dto.OrderRequestDTO;
import com.example.r3pm.dto.OrderResponseDTO;
import com.example.r3pm.dto.PointBalanceDTO;

/**
 * 会員に関するユースケースを扱うサービスインターフェース
 */
public interface MemberService {

    /**
     * 会員情報を登録する (UC4)
     * @param memberDTO 会員情報
     * @return 登録された会員情報
     */
    MemberDTO registerMember(MemberDTO memberDTO);

    /**
     * 会員情報を変更する (UC4)
     * @param memberDTO 変更する会員情報
     * @return 変更後の会員情報
     */
    MemberDTO updateMember(MemberDTO memberDTO);

    /**
     * ポイント残高を参照する (UC3)
     * @param memberId 会員番号
     * @return ポイント残高情報
     */
    PointBalanceDTO getPointBalance(String memberId);

    /**
     * 商品を購入し、ポイントを利用・付与する (UC1, UC2)
     * @param orderRequest 注文リクエスト
     * @return 注文結果
     */
    OrderResponseDTO placeOrder(OrderRequestDTO orderRequest);
}

ユースケースまでコードに落とすことができたので、あとはロジックの実装、DBへの永続化、Webコントローラ、ルートの作成など実際に動くところを作成していくだけです。

ここまでで、データベーススペシャリスト試験の問題から設計を起こし、実装に移るところまでを見ました。この先どう作るかは楽しんでもらえればと思います。わからなければJunieはじめAIがあります。ベストプラクティスも訊けば教えてくれます。

IntelliJでのエラー調査が便利になっていた

本題とは関係ないですが、IntelliJでのエラー調査体験が良かったので紹介します。

サーバ側でエラーが発生したとき、コンソールにスタックトレースが表示されますが、そこに Explain with AI アイコンが表示されていました。
これをクリックすればAIが原因を調査してくれます。便利。

スクリーンショット 2025-11-17 21.44.26.png

また、画面側でJavascriptエラーが発生したとき、TamaCatを使用していると画像のようにWarningを表示してくれました。devツールを使用しなくても認識できます。便利。

スクリーンショット 2025-11-17 21.49.57.png

記事書き終えてから、カレンダーの担当日までにIntelliJ、Springともにバージョンし、全部書き直すことになりしました。AIの出力結果が違うのでね。うまく終わっていると嬉しいです。

題材にしたデータベーススペシャリスト試験ですが、来年度からCBT方式に変更となります。作図をどうするのか気になるのですが、それよりも「新制度に移行した最初の試験は難易度が下がる」という性質があるようなので、気になる方いれば来年の受験がおすすめです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?