📝

はじめてのSpringBoot7 ~JDBCその2:QueryFor系~

2020/12/21に公開

はじめに

はじめまして
私はJavaを研修で少しかじった程度でSpringBootを使用した開発に参加し、てんやわんやしております森田和華です。
全く分からない中から少しずつ調べて実装をしていますが、自分の学習の為にも記事にして残しておこうと思い作成しております。
参考にしていただける際はそのあたりを念頭に置いたうえで参考にしていただければと思います。
もし私の記事を読んでおかしなところなどありましたらご指摘いただけると嬉しいです。
前回までの記事はこちらです。
はじめてのSpringBoot1 ~プロジェクトの作成~
はじめてのSpringBoot2 ~DB接続~
はじめてのSpringBoot3 ~ログイン機能その1~
はじめてのSpringBoot4 ~ログイン機能その2~
はじめてのSpringBoot5 ~ログイン機能その3~
はじめてのSpringBoot6 ~JDBCその1~

環境

SpringBootバージョン:2.4.0
Javaバージョン:8
DB:MySQL 8.0
IDE:eclipse

今回の目標

前回はとりあえずJDBCの動作を確認しました。
範囲が広くなってしまうので今回は
・queryForObject
・queryForMap
・queryForList
動作の違い、細かな記法を勉強していきます。

それぞれのメソッドの動き

・queryForObject
・queryForMap
・queryForList
については、取得対象の違う取得用メソッドです。(SELECT)

queryForObject:デフォルトの機能では1レコードの1項目を取得する(RowMapperを指定することで1レコードを指定したオブジェクトととして取得することが出来る)
queryForMap:1レコードの内容をMapとして取得する
queryForList:複数行のレコードを取得する
ざっくりと表にまとめてみると以下のようになります。

【queryForObject】

バインド変数を利用せず1レコードの1項目を取得する

JDBCtestRepository.java
//追記部分のみ記載	
public Integer findMaxId(){
	String sql ="SELECT Max(id) FROM book_sample";
	return jdbctemplate.queryForObject(sql,Integer.class);//検索結果は第二引数で指定したデータ型で返却される 
}
SampleContoroller.java
//追記部分のみ記載
Integer id = jdbcTestRepository.findMaxId();
model.addAttribute("id",id);
sample.html
//追記部分のみ記載
<div th:if="${id ne null}" th:text="'IDのMax値は'+${id}" ></div>

動作確認

最後の1行が今回取得のデータを表示した部分です。問題なく表示されています。

バインド変数を利用して1レコードの1項目を取得する

先ほどのファイルに追記・修正していきます。

JDBCtestRepository.java
//追記部分のみ記載
public String findTitleById(int id){

		String sql ="SELECT title FROM book_sample where id = ?"; //バインドパラメータは?で指定

		return jdbctemplate.queryForObject(sql,String.class,id);//第三引数でパラメータを指定
	}
//パラメータに配列を使用して複数set
public String findTitleByIdAndDelFlg(Object[] args){

		String sql ="SELECT title FROM book_sample WHERE id = ? AND delflg = ?"; //バインドパラメータは?で指定

		return jdbctemplate.queryForObject(sql,args,String.class);//第三引数でパラメータを指定
	}
SampleContoroller.java
//追記部分のみ記載
String titleAll = jdbcTestRepository.findTitleById(1);
Object[] args = new Object[] {2,0};
String titleNotDel = jdbcTestRepository.findTitleByIdAndDelFlg(args);

model.addAttribute("titleAll",titleAll);
model.addAttribute("titleNotDel",titleNotDel);
sample.html
//追記部分のみ記載
<div th:if="${titleAll ne null}" th:text="'titleAllは'+${titleAll}" ></div>
<div th:if="${titleNotDel ne null}" th:text="'titleNotDelは'+${titleNotDel}" ></div>

動作確認

最後の2行が今回取得のデータを表示した部分です。問題なく表示されています。

【queryForMap】

1行検索結果を取得

こちらも先ほどのファイルに追記・修正していきます。

JDBCtestRepository.java
//追記部分のみ記載
public BookEntity findBookById(int id){

		String sql ="SELECT * FROM book_sample where id = ?"; //バインドパラメータは?で指定
		Map<String,Object> result = jdbctemplate.queryForMap(sql,id);//第三引数でパラメータを指定
		//取得済みデータをエンティティにsetする
		BookEntity book =new BookEntity(); 
		book.setId(Integer.parseInt(result.get("id").toString()))
		book.setTitle((String)result.get("title"));
		book.setSummary((String)result.get("summary"));
		book.setClassification((String)result.get("classification"));
		book.setDelflg((int)result.get("delflg"));
		return book;
	}
SampleContoroller.java
//追記部分のみ記載
model.addAttribute("book",jdbcTestRepository.findBookById(1));
sample.html
//追記部分のみ記載
<div th:if="${book ne null}" th:text="Map取得">
	<div th:text="'ID:'+${book.id}"></div>
	<div th:text="'タイトル:'+${book.title}"></div>
	<div th:text="'概要:'+${book.summary}"></div>
	<div th:text="'分類:'+${book.classification}"></div>
</div>

MapではBookテーブルの値を保持する為のEntityを新たに作成します。

BookEntity.java
package com.elpmas.test.domain.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
@Table(name="book_sample")
public class BookEntity {

	@Id
	@Column(name="id")
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private int id;

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

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

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

	@Column(name="delflg")
	private int delflg;

}

動作確認

最後の選択行が今回取得のデータを表示した部分です。問題なく表示されています。

【queryForList】

複数行の検索結果を取得

それぞれのファイルに追記・修正していきます。

JDBCtestRepository.java
//追記部分のみ記載
public List<BookEntity> findBooksByDelflg(int delflg){

		String sql ="SELECT * FROM book_sample where delflg = ?"; //バインドパラメータは?で指定
		List<Map<String,Object>> resultList = jdbctemplate.queryForList(sql,delflg);//第三引数でパラメータを指定
		//取得済みデータをエンティティにsetする
		List<BookEntity> bookList =new ArrayList<BookEntity>();
		for(Map<String,Object> result:resultList)
		{
			BookEntity book =new BookEntity();
			book.setId(Integer.parseInt(result.get("id").toString()));//なぜかLong型で取得されているのでLong型→String型→Int型でキャストをかける。
			book.setTitle((String)result.get("title"));
			book.setSummary((String)result.get("summary"));
			book.setClassification((String)result.get("classification"));
			book.setDelflg((int)result.get("delflg"));
			bookList.add(book);
		}

		return bookList;
	}

Controllerは下記を追加します。

SampleContoroller.java
//追記部分のみ記載
model.addAttribute("bookList",jdbcTestRepository.findBooksByDelflg(0));

htmlファイルも下記を追記します。

sample.html
//追記部分のみ記載
<div th:if="${bookAll ne null}" th:each="book:${bookList}" >
	<div th:text="List取得"></div>
	<div th:text="'ID:'+${book.id}"></div>
	<div th:text="'タイトル:'+${book.title}"></div>
	<div th:text="'概要:'+${book.summary}"></div>
	<div th:text="'分類:'+${book.classification}"></div>
</div>

動作確認

最後の選択行が今回取得のデータを表示した部分です。問題なく表示されています。

次回

今回は
・queryForObject
・queryForMap
・queryForList
のメソッドをメインに勉強してきました。

次回は
おまけとして調べておきたいことがあるのでそちらを先にすすめます。
1.パラメータバインドを名前付き変数にする(?だとSQLの可読性が低いから)
2.検索結果が0件の時はどうなるのか(エラー?null?)

参考文献

Spring徹底入門 Spring FrameworkによるJavaアプリケーション開発 (著 株式会社NTTデータ)
https://www.shoeisha.co.jp/book/detail/9784798142470

Discussion