Spring入門コンテンツ Relational Data Access(リレーショナルデータにアクセス)をインポートする方法と解説


ここでは、
Spring入門コンテンツ「Relational Data Access(リレーショナルデータにアクセス)」をインポートする方法と、このコンテンツについて、紹介します。

動作環境


以下の環境に入門コンテンツをインポートしました。

・Windows10 64bit

・Eclipse 2018-12(Eclipse 4.10)

・Java 8

・Spring Boot 2.1.3(Spring Tool Suite 4)

※下記の記事で構築した開発環境を利用

Spring Tool Suite 4の開発環境構築(Eclipseにインストール)|STS4

入門コンテンツのインポート

まず、Eclipseで「ファイル」>「新規」>「その他」を選択します。「ウィザードを選択」画面で、「Spring 入門コンテンツのインポート」を選択して、「次へ」ボタンをクリックします。




次に、「入門コンテンツのインポート」画面で「Relational Data Access」を選択して、「完了」ボタンをクリックして、インポートします。





・ビルドタイプ

Mavenを選択

・コードセット

初期、起動にチェック

初期:プロジェクト「gs-relational-data-access-initial」をインポート

起動:プロジェクト「gs-relational-data-access-complete」をインポート

*この記事では、プロジェクト「gs-relational-data-access-completeについて、紹介します。

最後に、入門コンテンツ「Relational Data Accessがインポートされたことを確認します。




Relational Data Access(リレーショナルデータにアクセス)

この入門コンテンツでは、SpringのJdbcTemplateを使用して、リレーショナルデータベースのデータにアクセスする方法を学習します。


JdbcTemplateについて

Springは、JdbcTemplateと呼ばれるテンプートクラスを提供しています。

JdbcTemplateを使用すると、SQLリレーショナルデータベースとJDBCを使った操作が簡単になります。

JdbcTemplateがJDBCコードのリソース取得、接続管理、例外処理、および一般的なエラーチェックを引き受けてくれますので、実際のロジックを作成する作業に集中することができます。


H2 DataBase(H2データベース)

この入門コンテンツでは、リレーショナルデータベースにH2を使用しています。

Spring Bootは、H2とインメモリリレーショナルデータベースをサポートしており、自動的に接続を作成します。


Spring Boot アプリケーションの実行

gs-relational-data-access-complete」を右クリックして、「実行」>「Spring Boot App」を選択します。



Spring Boot アプリケーションを実行すると、顧客テーブルの作成、顧客情報のデータ登録、顧客情報のデータ検索が行われます。

このデータアクセスの実行結果がコンソールに出力されますので、以下の出力情報を確認して、データアクセスの実行結果を確認します。

*出力される情報については、以下のアプリケーションクラスのソースコードをみて、確認できます。

・出力情報
...

2019-04-14 21:02:12.170  INFO 1244 --- [           main] hello.Application                        : Creating tables

...

2019-04-14 21:02:12.639  INFO 1244 --- [           main] hello.Application                        : Inserting customer record for John Woo

2019-04-14 21:02:12.639  INFO 1244 --- [           main] hello.Application                        : Inserting customer record for Jeff Dean

2019-04-14 21:02:12.654  INFO 1244 --- [           main] hello.Application                        : Inserting customer record for Josh Bloch

2019-04-14 21:02:12.654  INFO 1244 --- [           main] hello.Application                        : Inserting customer record for Josh Long

2019-04-14 21:02:13.157  INFO 1244 --- [           main] hello.Application                        : Querying for customer records where first_name = 'Josh':

2019-04-14 21:02:13.189  INFO 1244 --- [           main] hello.Application                        : Customer[id=3, firstName='Josh', lastName='Bloch']

2019-04-14 21:02:13.205  INFO 1244 --- [           main] hello.Application                        : Customer[id=4, firstName='Josh', lastName='Long']

...


アプリケーション(Application)


・アプリケーションクラス

Application.java

・ソースコード
package hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@SpringBootApplication
public class Application implements CommandLineRunner {

    private static final Logger log = LoggerFactory.getLogger(Application.class);

    public static void main(String args[]) {
        SpringApplication.run(Application.class, args);
    }

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Override
    public void run(String... strings) throws Exception {

        log.info("Creating tables");

        jdbcTemplate.execute("DROP TABLE customers IF EXISTS");
        jdbcTemplate.execute("CREATE TABLE customers(" +
                "id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))");

        // Split up the array of whole names into an array of first/last names
        List<Object[]> splitUpNames = Arrays.asList("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long").stream()
                .map(name -> name.split(" "))
                .collect(Collectors.toList());

        // Use a Java 8 stream to print out each tuple of the list
        splitUpNames.forEach(name -> log.info(String.format("Inserting customer record for %s %s", name[0], name[1])));

        // Uses JdbcTemplate's batchUpdate operation to bulk load data
        jdbcTemplate.batchUpdate("INSERT INTO customers(first_name, last_name) VALUES (?,?)", splitUpNames);

        log.info("Querying for customer records where first_name = 'Josh':");
        jdbcTemplate.query(
                "SELECT id, first_name, last_name FROM customers WHERE first_name = ?", new Object[] { "Josh" },
                (rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name"))
        ).forEach(customer -> log.info(customer.toString()));
    }
}


Spring Boot アプリケーションを実行すると、Application.mainメソッドが実行されます。

mainメソッド

パラメータ
    args - String配列(要素数0)

戻り値
    なし

Spring BootのSpringApplication.runメソッドを実行して、アプリケーションを起動します。

JdbcTemplateフィールド

JdbcTemplateフィールドに@Autowiredを付与して、Springコンテナに管理されているBean(JdbcTemplateのインスタンス)をJdbcTemplateフィールドに代入します。

* spring-jdbcを使用すると、Spring Bootは、自動的にJdbcTemplateのインスタンスを生成します。@Autowired JdbcTemplateフィールドは、自動的に、このJdbcTemplateのインスタンスをロードして、利用可能にします。

runメソッド

パラメータ
    strings - String配列要素数0

戻り値

    なし

Applicationクラスは、Spring BootのCommandLineRunnerインターフェースを実装していますので、SpringApplication.runメソッドを実行すると、アプリケーション・コンテキストがロードされた後に、このApplication.runメソッドが実行されます。

JdbcTemplateクラスを使用したデータアクセス処理について、

まず、JdbcTemplate.executeメソッドを実行して、引数に指定したSQL文(DROP、CREATE)を発行して、顧客テーブル(customers)を作成します。

次に、JdbcTemplate.batchUpdateメソッドを実行して、引数に指定したSQL文(INSERT)を使用して、バッチ処理により、顧客テーブルに顧客情報のデータを登録します。

最後に、JdbcTemplate.queryメソッドを実行して、引数に指定したSQL文(SELECT)を使用して、顧客テーブルから条件に一致した顧客情報のデータを検索します。

また、上記のデータアクセスの実行結果をコンソールに出力します

*JdbcTemplateクラスのexecute(String sql)メソッドは、引数の単一のSQL文(通常はDDLステートメント)を発行します。


*JdbcTemplateクラスのbatchUpdate(String sql, List<Object[]> batchArgs)メソッドは、引数の実行するSQL文とSQL文にバインドする情報(SQL文の「?」にセットされる変数)を使用して、バッチ処理を実行します。

上記のように、insert文で複数行のデータをテーブルに登録する場合は、JdbcTemplate.batchUpdateメソッドを使用するのが良いですが、単一行のデータをテーブルに登録する場合は、JdbcTemplate.updateメソッドを使用したほうが良いです。

また、JDBCに変数をバインドするように指示することによって、SQLインジェクション攻撃を回避するために、引数に「?」を使用しています。


*JdbcTemplateクラスのquery(String sql, @Nullable Object[] args, RowMapper<T> rowMapper)メソッドは、引数の実行するSQL文とSQL文にバインドする情報(SQL文の「?」にセットされる変数)と検索結果を各行ごとにマップするオブジェクトを使用して、条件に一致する情報を検索します。

上記の3つ目の引数は、検索結果の各行をCustomerオブジェクトに変換するために使用されるJava 8のラムダです。

顧客情報(Customer)

・顧客情報クラス

Customer.java

・ソースコード
package hello;

public class Customer {
    private long id;
    private String firstName, lastName;

    public Customer(long id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return String.format(
                "Customer[id=%d, firstName='%s', lastName='%s']",
                id, firstName, lastName);
    }

    // getters & setters omitted for brevity
}

顧客情報クラスは、顧客テーブルから取得した顧客情報(顧客の姓名)を保持します。

補足情報

%d:10進整数
%s:文字列

メモ


Spring Bootには、接続プールの設定やカスタマイズのための多くの機能があります。例えば、インメモリデータベースの代わりに外部データベースに接続するための機能です。

Configure a DataSource - Spring Boot Reference Guid(Spring Boot 2.1.3)

参考

Relational Data Access - Spring




スポンサーリンク

0 件のコメント :

コメントを投稿