前回の記事では、3層アーキテクチャについての説明とプレゼンテーション層とビジネスロジック層を分離させる処理について説明をしてきました。
今回はデータ・アクセス層についての説明をしていきたいと思います。
データ・アクセス層は、データの検索や操作をしたり、データの永続化を管理したりする役割を担っている部分で、データを永続化するためのRepository層についての処理を記述していきたいと思います。
そして、データの検索や操作をしたり、データの永続化をするためには、データベースの知識が必要不可欠なので、データベースについても触れていきます。
今回のファイル構成は、以下になります。
クリックして展開
.
├── .gradle
├── .idea
├── build
├── gradle
└── src
├── main
| ├── java
| | └── com
| | └── example
| | └── practice
| | PracticeApplication.java
| | ├── web
| | | ├── order
| | | | └── OrderController.java
| | | |
| | | └── IndexController.java
| | └── domain
| | └── order
| | └── OrderEntity.java
| | └── OrderService.java
| | └── OrderRepository.java
| |
| └── resources
| ├── static
| ├── templates
| | └── order
| | └── list.html
| └── index.html
| schema.sql
| data.sql
| application.properties
└── test
.gitignore
build.gradle
gradlew.bat
HELP.md
settings.gradle
MyBatisとH2コンソール
Javaデータベースを扱うためのフレームワークとして、「MyBatis」があります。
MyBatisはJavaのアプリケーションとリレーショナルデータベースとのやりとりを簡略化する役割を担っています。
そして、今回はH2コンソールを使って、データベースの操作をしていきたいと思います。
まずは、MyBatisとH2コンソールを使うために、build.gradleに依存関係を追加します。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
追加をしたら、ビルドをし直して、「http://localhost:8080/h2-console」にアクセスすると、下記のような画面になっていることを確認してください。
一旦、ここまででブラウザは終了して、application.propertiesにデータベースの設定を追加します。
application.propertiesは、Spring Bootで用意されてあるデフォルトの設定値ではなく、環境独自の設定設定を行うためのファイルになります。
application.propertiesにデータベースを設定するコードを追加します。
userとパスワードは任意なので適宜修正してください。
spring.thymeleaf.prefix=file:src/main/resources/templates/
spring.datasource.data-source-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:its;DB_CLOSE_ON_EXIT=TRUE;MODE=MySQL
spring.datasource.username=user
spring.datasource.password=user
そして、「H2 Console」は、data.sql(DML、データ初期化)とschema.sql(DDL、テーブル生成)の2つをsrc/main/resourcesディレクトリ下に作成しておけば、自動でファイルをロードしてファイル内のSQLを実行してくれます。
先に、schema.sqlについて説明をしていきます。
schema.sqlはDDL(データ定義言語)と呼ばれます。
DDLはデータベースの構造や、テーブル、ビュー、インデックス、プロシージャなどのオブジェクトを定義するためのものです。
主なものとして、
・CREATE
テーブル、ビュー、またはインデックスなどの新しいデータベースオブジェクトを作成します。
・ALTER
既存のデータベースオブジェクトを変更するために使用します。
・DROP
既存のデータベースオブジェクトを削除するために使用します。
・TRUNCATE
テーブルのすべての行を削除します。
・RENAME
既存のデータベースオブジェクトの名前を変更するために使用します。
orderEntityの情報をもとにshema.sqlにTABLEを作成します。
テーブルを新規に作成する場合は、CREATE TABLEを使います。
書き方は以下の通りです。
CREATE TABLE テーブル名 (
カラム名 データ型 オプション,
);
次に、TABLEの中身について説明をします。
データ型は、文字列型、数値型、日付型・時刻型、論理値型があります。
文字列型
文字列型はテキストデータを格納するために使用されます。代表的なものには「VARCHAR」や「CHAR」がある。「VARCHAR」は可変長の文字列を格納し、必要なスペースだけを使用する一方で、「CHAR」は固定長の文字列を格納し、指定された長さに合わせてスペースが埋められます。数値型
数値型は数値データを格納するために使用されます。主要な数値型には「INT」(整数型)、「DECIMAL」(固定小数点型)、および「FLOAT」(浮動小数点型)などがあります。これらは算術演算を実行する際に使用され、データベース内の計算や集計に役立ちます。日付型・時刻型
日付型と時刻型は日付や時刻の情報を格納するために使用されます。代表的なものには「DATE」(日付型)、「TIME」(時刻型)、および「DATETIME」(日付時刻型)などがあります。これらの型は、イベントのタイムスタンプを記録したり、時間ベースのデータを管理する際に使用されます。論理値型
論理値型は真偽値(真または偽)を格納するために使用されます。主に「BOOLEAN」型があり、条件の評価やフラグの管理に使用されます。真偽値は通常、条件式の結果や状態の表現に使用されます。オプション
CREATE TABLEの主なオプションは4つあります。
1.NOT NULL
これはnull値を許可しない
2.PRIMARY KEY
これは主キーを設定する
3.UNIQUE
重複を許可しない
4.DEFAULT
デフォルト値を設定する
以下が、テーブルの書き方をもとに作ったschema.sqlです。
CREATE TABLE ORDERS (
order_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
order_date VARCHAR(255) NOT NULL,
company_no INT NOT NULL,
company_name VARCHAR(255),
item_no INT NOT NULL,
item VARCHAR(255),
quantity INT DEFAULT 0,
unit_price INT DEFAULT 0,
price INT DEFAULT 0
);
DMLは、データベース内のデータを挿入、更新、および削除するために使用されます。
・SELECT
データベース内の1つまたは複数のテーブルからデータを取得するために使用されます。
・INSERT
テーブルに新しいデータを挿入するために使用されます。
・UPDATE
テーブルの既存のデータを変更するために使用されます。
・DELETE
テーブルからデータを削除するために使用されます。
次にdata.sqlについての説明になります。
OrderServiceの12行目~16行目の部分をそのまま、INSERTします。
return List.of(new OrderEntity(1000, "20230801", 1000,
"株式会社あいうえお", 1000, "パソコン", 1, 100000,
100000), new orderEntity(1001, "20230802", 1001,
"株式会社ABCD", 1001, "デスクトップ", 2, 60000,
120000));//
INSERT文は書き方は以下の通りです。
INSERT INTO テーブル名 (列名1, 列名2,...) VALUES (値1, 値2,...);
data.sqlは以下のようになります。
insert into ORDERS(order_id,order_date,company_no,company_name,item_no,item,quantity,unit_price,price)
values (1000, '20230801', 1000, '株式会社あいうえお', 1000, 'パソコン', 1, 100000,100000);
insert into ORDERS(order_id,order_date,company_no,company_name,item_no,item,quantity,unit_price,price)
values (1001, '20230802', 1001,'株式会社ABCD', 1001, 'デスクトップ', 2, 60000,120000);
再度、http://localhost:8080/h2-consoleを開いて、「ORDERS」のテーブルをクリックすると、「SELECT * FROM ORDERS」が表示されるので、クリックすると、INSERTしたデータが表示されます。
Repository層
では、ここから本題に入りたいと思います。
Repository層はインターフェースです。
Repository層はデータベースへのアクセスや操作を行うためのメソッドを提供する役割を果たします。
これにより、データベースへの操作が抽象化され、ビジネスロジック層やプレゼンテーション層からのデータベース操作が簡潔で効率的に行えるようになります。
src/main/java/com/example/practice/domain/orderのディレクトリにOrderRepositoryを作成します。
作成するときはclassではなく、interfaceにしてください。
以下がOrderRepositoryの内容になります。
package com.example.practice.domain.order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/*
@Mapperをつけることでメソッドを呼び出すときに
自動的に適切なSQLクエリを実行し、
データベースとの間で情報をやり取りできる。
*/
@Mapper
public interface OrderRepository {
/*
SQLクエリを指定して、データベースから全ての注文情報を取得するメソッドです。
@Selectアノテーションにより、このメソッドはMyBatisが自動的にSQLクエリとして認識し、実行します。
"select * from orders"は、ordersテーブルからすべてのカラムを取得するSQLクエリです。
*/
@Select("select * from orders")
/*
取得した注文情報をorderEntityクラスのリストとして返します。
これにより、このインタフェースを呼び出すと、MyBatisが自動的にデータベースから注文情報を取得してリストとして返します。
*/
List<OrderEntity> findAll();
}
OrderServiceを以下のように変更する。
package com.example.practice.domain.order;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor // コンストラクタインジェクションを実現するLombokアノテーション
public class OrderService {
private final OrderRepository repository; // OrderRepositoryのインスタンスを格納するフィールド
public List<OrderEntity> findAll() {
return repository.findAll(); // OrderRepositoryから全ての注文エンティティを取得して返す
}
}
まとめ
Repository層はデータベースへのアクセスや操作を提供するインターフェースで、ビジネスロジック層やプレゼンテーション層からデータベース操作が行えるようにします。MyBatisを使ってSQLクエリを実行するOrderRepositoryを作成し、その中で注文情報を取得するメソッドを定義しました。これにより、データベースから注文情報を取得してリストとして返すことができます。
OrderServiceでは、OrderRepositoryのインスタンスを利用してデータベースから注文情報を取得し、その結果をビジネスロジック層で扱える形に整形して提供します。
ビジネスロジック層からOrderServiceのメソッドを呼び出すことで、データベースの操作やデータの取得が行えるようになります。
このように、3層アーキテクチャを導入することで、アプリケーションの各層を疎結合に保ちながら、保守性や拡張性を向上させることができます。
そして、MVC(Model-View-Controller)パターンを組み合わせることで、データベース操作からプレゼンテーションまでのフローを効果的に管理し、アプリケーションの各機能を分割・再利用可能なコンポーネントとして構築することができます。
これにより、アプリケーションのメンテナンスや開発がスムーズに行えるほか、チーム内の協力やコードの可読性も向上します。3層アーキテクチャとMVCの組み合わせは、モダンなソフトウェア開発において重要な設計原則となっています。