[Spring Boot] JPAでデータベースに接続

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

以前の記事で、JPAを扱えるJpaRepositoryを使ったデータベース接続について書きました。
今回は、同じくJpaRepositoryを使用しますが、前回とは違う使い方です。
JPAはJQPLというSQLに似た簡易クエリが搭載されていて、 実行するとSQLに変換されてデータベースにクエリを投げます。

環境

Mac OSX 10.10.5 Yosemite
PostgreSQL 9.5.1
Spring Boot 1.3.6

テーブル:mydata

CREATE TABLE mydata (
  id VARCHAR(2) NOT NULL UNIQUE 
  , title VARCHAR(10)
  , count INTEGER
  , PRIMARY KEY(id)
);

INSERT INTO mydata VALUES
 ('1','aaa',1),('2','bbb',1),('3','ccc',null),('4','ddd',1),('5','eee',null),('6','fff',1),('7','ggg',null);
postgres=# select * from mydata ;
 id | title | count 
----+-------+-------
 1  | aaa   |     1
 2  | bbb   |     1
 3  | ccc   |      
 4  | ddd   |     1
 5  | eee   |      
 6  | fff   |     1
 7  | ggg   |      
(7 rows)

コード

gradle(依存関係のみ抜粋)

dependencies {
	compile('org.springframework.boot:spring-boot-starter-data-jpa')
	compile('org.springframework.boot:spring-boot-starter-jdbc')
	compile('org.projectlombok:lombok:1.16.6')
	compile('org.springframework.boot:spring-boot-starter-web')
	runtime('org.postgresql:postgresql')
	testCompile('org.springframework.boot:spring-boot-starter-test') 
}

application.yml

spring:
  datasource:
    url: jdbc:postgresql://localhost/postgres
    username: XXXXX
    password: YYYYY
    driverClassName: org.postgresql.Driver

エンティティ

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

import lombok.Data;

@Entity
@Data
@Table(name="mydata")
public class MyData {

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	private String id;
	
	private String title;
	
	private Integer count;
	
}

PostgreSQLのテーブル「mydata」のレコードを取得するのに使用します。

リポジトリ

import java.util.ArrayList;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MyRepository extends JpaRepository<MyData, String>{

	List<MyData> findById(String id);
	List<MyData> findByIdBetween(String start, String end);
	List<MyData> findByIdIn(String[] ids);
	List<MyData> findByIdNotIn(ArrayList<String> ids);
	
}

ここではメソッド名を組み合わせる事でJPQLクエリをできます。
詳しくは、ページ下部をご覧頂きたいですが、findBy〜(引数)で操れます。

10-13行目、クエリの取得結果をListで返します。
SQLが分かれば機能はメソッド名で分かってしまいます。

コントローラー

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

	@Autowired
	MyRepository repository;
	
	@RequestMapping("/select")
	public List<MyData> select(@RequestParam("id") String id) {
		List<MyData> list = repository.findById(id);
		return list;
	}
	
	@RequestMapping("/between")
	public List<MyData> between(@RequestParam("id1") String id1, @RequestParam("id2") String id2) {
		List<MyData> list = repository.findByIdBetween(id1, id2);
		return list;
	}
	
	@RequestMapping("/idin")
	public List<MyData> idIn(@RequestParam("id") String[] ids) {
		List<MyData> list = repository.findByIdIn(ids);
		return list;
	}	
	
	@RequestMapping("/idnotin")
	public List<MyData> idNotIn(@RequestParam("id") ArrayList<String> ids) {
		List<MyData> list = repository.findByIdNotIn(ids);
		return list;
	}

}

8行目、結果を分かりやすくするためにRestControllerを使用しました。
11-12行目、今回はサービスを経由せずに直接リポジトリをAutowiredで接続します。

14-18行目、メソッドselect()
接続アドレスは、「http://localhost:8080/select?id=任意の数字」。
15行目、引数にアドレスの「id=任意の数字」を取得。
16行目、クエリを実行結果をListに入れます。
17行目、取得結果を画面に表示するため、returnにListを設定。

20-24行目、メソッドbetween()
接続アドレスは、「http://localhost:8080/between?id1=任意の数字&id2=任意の数字」。
21行目、今度は引数を2個id1とid2を取得しています。
22-23行目、メソッドselect()の16-17行目と同様です。

26-30行目、メソッドidIn()
接続アドレスは、「http://localhost:8080/idin?id=任意の数字,任意の数字,...」。
パラメータidを配列として引数で取得します。

32-36行目、メソッドidNotIn()
接続アドレスは、「http://localhost:8080/idnotin?id=任意の数字,任意の数字,...」。
こちらも同様にパラメータidを配列として引数で取得します。

実行結果

select()の実行結果

$ curl http://localhost:8080/select?id=3
[{"id":"3","title":"ccc","count":null}]

between()の実行結果

$ curl "http://localhost:8080/between?id1=2&id2=5"
[{"id":"2","title":"bbb","count":1},{"id":"3","title":"ccc","count":null},{"id":"4","title":"ddd","count":1},{"id":"5","title":"eee","count":null}]

curlで複数のパラメータを渡す為にURLをダブルクォーテーションで囲んでいます。

idNotIn()の実行結果

$ curl "http://localhost:8080/idin?id=2,3,4,5"
[{"id":"2","title":"bbb","count":1},{"id":"3","title":"ccc","count":null},{"id":"4","title":"ddd","count":1},{"id":"5","title":"eee","count":null}]

配列に複数の値を渡すにはカンマで区切ります。

idNotIn()の実行結果

$ curl "http://localhost:8080/idnotin?id=2,3,4,5"
[{"id":"7","title":"ggg","count":null},{"id":"1","title":"aaa","count":1},{"id":"6","title":"fff","count":1}]

コレクションに複数の値を渡す場合でもカンマで区切ります。

メソッド名の作成例と実行されるJPQL

JPQLのクエリはSQLの場合と違い、「SELECT * 」が省かれます。
また、大文字小文字を区別するので、間違えるとエラーが発生するので注意してください。

メソッド名の作成例 実行されるJPQL
findById(String id) FROM mydata WHERE id = '引数id'
findByIdNot(String id) FROM mydata WHERE id <> '引数id'
findByIdAndTitle(String id, String title) FROM mydata WHERE id = '引数id' and title = '引数title'
findByIdOrTitle(String id, String title) FROM mydata WHERE id = '引数id' or title = '引数title'
findByIdBetween(String start, String end) FROM mydata WHERE id BETWEEN '引数start' and '引数end'
findByIdLessThan(String id) FROM mydata WHERE id < '引数id'
findByIdGreaterThan(String id) FROM mydata WHERE id > '引数id'
findByCountIsNull() FROM mydata WHERE count IS NULL
findByCountIsNotNull() FROM mydata WHERE count IS NOT NULL
findByTitleLike(String word) FROM mydata WHERE title LIKE '引数word'
(ワイルドカードは引数に渡す時点で書いておく必要が有ります。)
findByTitleNotLike(String word) FROM mydata WHERE title LIKE '引数word'
findByIdOrderByTitleAsc(String id) FROM mydata WHERE id = '引数id' ORDER BY title ASC
findByIdOrderByIdDesc(String id) FROM mydata WHERE id = '引数id' ORDER BY id DESC
findByIdIn(String[] ids) FROM mydata WHERE id IN '引数に配列ids'
findByIdNotIn(ArrayList ids) FROM mydata WHERE id NOT IN '引数にコレクションids'

さいごに

紹介したメソッド名の作成例を参考に色々作成して試してみてください。
次回は、より低レベルのJPQLを扱ってみようと思います。