読者です 読者をやめる 読者になる 読者になる

アラカン"BOKU"のITな日常

人事評価と人工知能について考えたことがメインテーマです。

STS 3.8.3(Spring Boot 1.5.1) + JPA + MySQLでデータアクセスする

Spring Boot入門 プログラミング

Spring Boot + JPA + MySQLで簡単なデータアクセスのサンプルを作ってみます。

 

プライマリキーが一つの単純なテーブルばかりではないので、後のことも考えて、簡単と言いながら、ちょっとだけ実用を意識します。

 

今回の目標は、以下にします。

  1. 複数キーを持つテーブルを作る。
  2. そのテーブルに対するCRUDを、Jprepositoryで用意する。
  3. 一連のテーブルアクセスを、JUNITテストでやってみる。

 

まず、テーブルを作ります。名前は、person_entityにしています。

create table person_entity (
        pid VARCHAR(150) not null comment 'パーソンID'
      , item_id VARCHAR(150) not null comment '項目ID'
      , value VARCHAR(300) comment '値'
      , update_date TIMESTAMP comment '更新日'
      , constraint person_entity_PKC primary key (pid,item_id)
) comment 'パーソン' ;

 

対応するエンティティクラスを作ります。

名前付けルールで、クラス名は「PersonEntity」の必要があります。 

@Entity
@IdClass(value=PersonEntityKey.class)
public class PersonEntity {
     public PersonEntity(String id,String itemId,String value){
           super();
           setPid(id);
           setItemId(itemId);
           setValue(value);
     }
   @Id

    private String pid;

   @Id

    private String itemId;

    private String value;

    @Temporal(TemporalType.TIMESTAMP)

    private Date updateDate;

    @PrePersist
    @PreUpdate
     protected void now(){
          setUpdateDate(new Date());
     }

}

 ※ごちゃごちゃするので、getter、setterは省いて引用してます。

 

@Idというアノテーションがついているとプライマリキーです。

 

キーが一つの場合は、@Idを指定するだけで良いのですが、キーが2つ以上だと、@Idを2つ書くだけだとエラーになります。

 

それを回避するための定義が、「@IdClass(value=PersonEntityKey.class)」の部分です。

 

プライマリキーにする項目だけを定義したクラスをつくって、valueの後ろに指定します。今回の場合の中身はこんな感じです。

public class PersonEntityKey implements Serializable {

       private static final long serialVersionUID = 1L;
       private String pid;
       private String itemId;

※これもgettter、setterは省略してます。

 

このクラスを「@IdClass(value=PersonEntityKey.class)」の様に指定すれば、@Idを2つ指定してもエラーにならなくなり、後の操作は@Id一つの場合と同じように扱えます。

 

このエンティティクラスPersonEntityに対応する、リポジトリクラスを作ります。

@Repository
public interface PersonRepository extends JpaRepository<PersonEntity, PersonEntityKey> {
      // Select
      public List<PersonEntity> findByPid(String pid);
}

こんな感じで、 JpaRepositoryを継承したインタフェースを作るだけで、基本的なCRUDが提供されるので、超楽です。

 

<PersonEntity, PersonEntityKey>の部分は、対象とするエンティティクラスと、プライマリキーを収めたクラスを指定します。

 

しかも、エンティティクラスに、こう書いておくだけで、INSERT/UPDATE時に自動的に更新日付を記録してくれます。

@Temporal(TemporalType.TIMESTAMP)

private Date updateDate;

@PrePersist
@PreUpdate
protected void now(){
       setUpdateDate(new Date());
}

これは結構、手間が省けて助かりますね。 

 

とりあえず、pidを指定してselectしたいので、findByPidというメソッドを定義してます。これも、名前付けルールだけ気をつけて、定義だけしとけば中身は自動的に生成されます。(findBy・・の後ろの名前とDB物理名が一致しないと実行時エラーになります)

 

じゃあ、これで本当にCRUDできるのか、JUNITのテストケースを書いてみます。

@RunWith(SpringRunner.class)
@SpringBootTest
public class TestPersonRepository {

      @Autowired
      public PersonRepository personRepository;

      @Test
      public void test() {
            PersonEntity pe = new PersonEntity("001","001","value W 2 格納テスト");

            // Create(Insert)  

            personRepository.saveAndFlush(pe);

            //  Read(Select)

            List<PersonEntity> peList =         personRepository.findByPid("001");

            //  Update

            personRepository.saveAndFlush(pe);


            assertTrue(peList.get(0).getItemId().equals("001"));
      PersonEntity pe1 = peList.get(0);

            //  Delete
            personRepository.delete(pe1);
}

 saveAndFlush() というメソッドを2回よんでいるのは、レコードがなければInsert、あればupdate を自動で切り替えてくれるみたいなので、それを確認しているわけです。

 

これでJUNITテストを実行して、グリーンならOKです。

 

とりあえず、この程度の手間で、一通りのCRUDができて、かつ、単体テストまでできるのは有り難いですね。

 

もちろん、もっと複雑なSQLが必要な場合は、ダイレクトにSQLを書いたり、それなりの手間はかかります。

 

でも、今時、ガリガリと複雑なSQLばかりを書くのもスマートじゃないし、設計で考慮して、極力、このシンプルな手順で処理できるようにしたらいいのかなと思ってます。