概要

Spring Bootは、データベースアクセスにSpring Dataを使用します。
Spring Dataは、JPAやMongoDBなどのデータストアへのアクセスを抽象化する層です。

自分はJPAを使います。

作らなくちゃいけないもの

Entityクラス

データベースのテーブルへ対応するクラスです。

すでにデータベースが用意されているのであれば、NetBeansの機能を使って生成するのが簡単です。

[File]>[New File]メニューから、Persistence > Entity Classes from Databaseとたどれば、データベースのテーブルからEntityクラスを生成できます。

Repositoryインターフェース

Entityを操作するインターフェースです。org.springframework.data.repository.Repository<T, ID extends Serializable>の派生インターフェースにします。

派生インターフェースとして、あらかじめ次のものが用意されています。

インターフェース 解説
CrudRepository 一般的なCread/Read/Update/Delete操作が定義されています
PagingAndSortingRepository ソートとページング付きの全検索が定義されています。CrudRepositoryを継承しています。

使い方

Repositoryインターフェースに対して@Autowired等で依存しておくと、Springが自動的にプロキシインスタンスを作成してくれます。


@Component
public class SomeClass {
  // ...
  @Autowired
  private SomeRepository someRepository;
  // ...
}

あとは定義されているメソッドを呼び出せばよいです。

CRUD以外の操作をしたい

CrudRepositoryにあらかじめ用意されているCRUD以外の操作をしたいときのやり方です。

方法1 - 命名規約にそったメソッドを実装

以下の命名規約にそったメソッドを実装すると、メソッド名に応じて振る舞いが用意されます。

  • find...By
  • read...By
  • get...By
  • query...By
  • stream...By Java 8のStreamを返します。
  • count...By
  • exists...By
  • delete...By
  • remove...By

最初に出てくるByより後ろが検索式になります。

...の副式部分にはDistinctや、リレーション先のEntity名等が入ります。

検索式いろいろ

あらかじめいろいろなものが用意されています。

2016/11/11追記 【Spring Data JPA】自動実装されるメソッドの命名ルール に解説がありました。

検索式  
2項目をAndで結ぶ findByFirstnameAndLastname(String lastname)  
2項目をOrで結ぶ findByFirstnameOrLastname(String firstname, String lastname)  
2項目の間 findByCreateDateBetween(Date since, Date to)  
After/GreaterThan    
GreaterThanEqual    
Before/LessThan    
LessThanEqual    
IsNull    
IsNotNull    
NotIn    
In    
StartingWith/EndingWith/Containing    
NotContaining    
Like    
NotLike    
大文字小文字を無視 findByFirstnameIgnoreCase(String firstname)  
ソート findAllOrderByFirstnameAsc() findAllOrderByFirstnameDesc()  

副式...に入るもの

副式 解説
Distinct SQLのDISTINCTと一緒です。
Top<数字> / First<数字> 先頭から<数字>レコード分を返します。
エンティティ名 リレーション先のエンティティを返します。

方法2 - @Queryをつけたメソッドを実装

例えば、このようになります。


@Query("SELECT u FROM User WHERE u.firstname = :firstname")
List<User> findByFirstname(String firstname);

@Queryの中身はJPQLでよいのかな?

Spring Expression Languageも使えます。

方法3 - Customクラスを作る

命名規約やJPQLでは足りない機能を実装するときには、Customクラスを作ります。

例えば、もともとこんなRepositoryインターフェースがあったとしたら、

UserRepository.java

public interface UserRepository extends CrudRepository<User, Long> {}

まずは独自の機能をもったインターフェースを作ります。

UserRepositoryCustom.java

public interface UserRepositoryCustom {
  public void executeSomeOperation(User user);
}

もともとあったインターフェースに継承させます。

UserRepository.java

public interface UserRepository extends CrudRepository<User, Long>, UserRepositoryCustom {}

さらに実装を作ります。


public class UserRepostitoryImpl implements UserRepositoryCustom {
    public void executeSomeOperation(User user) {
       // なにか特別な処理
    }
}

もう少し詳しく書きました。 > Customクラスを使用してデータベースアクセスする

テストする

Repositoryインターフェースをテストします。

テストにはHSQLデータベースを使用します。

pom.xmlを変更

テストのスターター、JDBCドライバ、いつものjunitを依存ライブラリに追加します。

2016/11/11編集 junitとhamcrestは、スターターに入っていたので不要でした。

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <scope>test</scope>
        </dependency>

テスト用アプリケーションクラスの作成

アプリケーションクラスがなければ作成します。

src/test/java/com/example/TestApplicationi.java

package com.example;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories("com.example.repository")
public class TestApplication {
    
}

普通は@SpringBootApplicationだけで足りるのですが、Repositoryクラスが別にあるので@EnableJpaRepositoriesを付けています。

テストクラスの作成

@RunWithを付けて、テストランナーを指定します。

@SpringBootTest@Transactionalは何をやっているのかわかりません。 :sweat:

2016/11/17 追記 @SpringBootTest@Transactionalは不要でした。@DataJpaTestを付けるだけでよいです。これをつければSQLもログ出力してくれます。

src/test/java/com/example/repository/UserRepositoryTest.java

package com.example.repository;

import com.example.entity.User;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@DataJpaTest
public class UserRepositoryTest {
    
    @Autowired
    private UserRepository instance;
    
    @Before
    public void setUp() {
       // 初期データの用意等
    }

    @Test
    public void testFindSomething() {
       // テストを書く
    }
}

参考リンク