# Spring Data JPAについて ## ものづくりメンバー用に作成しています ## JPAとは JAVAからDBに接続する方法は主に2通りあります。 1つ目がJDBCでもう一つが今から紹介するJPAです。 超簡単に説明すると、JDBCはSQL文を直接入力してDBを操作するのに対してJPAはSQL文を直接入力せずにDBを操作することができます。 なぜ直接SQLを入力しなくてもDBを操作できるのかというと、JPAは内部実装の中にhibernateを使っています。このhibernateとはO/Rマッパーとも呼ばれています。このO/RマッパーによってObjectとRDBを関連付けることができます。 これによりSQL文をメソッドとして実行することができます。 --- ## サンプルアプリ 何もなしに説明だけするのは難しいのでサンプルで作ったアプリがあるのでこれをつかって説明していきます。 ![](https://i.imgur.com/bfzTztO.png) まずこれがTOP画面です。これに好きな文字列をいれて投稿ボタンを押すと、 ![](https://i.imgur.com/d0bRT8k.png) このように文字列が追加されていきます。 これらの文字列はDBに保存をしているためウェブサイトを更新しても消えることはありません。 消したいときは文字列の左側にある削除ボタンを押すだけでDBから消すことができます。 ## コードの説明 コード全部の解説は大変のためDBに関するところだけしますがすべて知りたい方は自分も参考にしたサイトを貼っておくのでこちらを参照して下さい。[クリック](https://qiita.com/t-shin0hara/items/eaf44e4f48341616ab97) ``` package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org. springframework.validation. annotation. Validated; import org. springframework.web.bind.annotation.GetMapping; import org. springframework.web.bind.annotation.ModelAttribute; import org. springframework.web.bind.annotation.PostMapping; import com.example.demo.model.Comment; import com.example.demo.repository.CommentRepository; @Controller public class CommentController { private final CommentRepository repository; //@Autowired ← コンストラクタが1つの場合、@Autowiredは省略できます public CommentController(CommentRepository repository) { this.repository = repository; } @GetMapping("/") public String getAllComments(@ModelAttribute Comment comment, Model model) { // COMMENTテーブル:レコード全件取得 model.addAttribute("comments", repository.findAll()); return "list"; } @PostMapping("/add") public String addComment(@Validated @ModelAttribute Comment comment, BindingResult result, Model model) { model.addAttribute("comments", repository.findAll()); if (result.hasErrors()) { return "list"; } // COMMENTテーブル:コメント登録 repository.save(comment); // ルートパス("/") にリダイレクトします return "redirect:/"; } @GetMapping("/delete") public String deleteComment(@Validated @ModelAttribute Comment comment, BindingResult result, Model model) { model.addAttribute("comments", repository.findAll()); // COMMENTテーブル:レコード削除 repository.deleteById(comment.getId()); // ルートパス("/") にリダイレクトします return "redirect:/"; } } ``` これがWEBサイトにアクセスした際に行う処理等がかかれているメインのプログラムです。 まず、@Autowiredによって自動で[インスタンス](http://e-words.jp/w/%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9.html#:~:text=%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%81%A8%E3%81%AF%E3%80%81%E4%BA%8B%E5%AE%9F%E3%80%81%E4%BA%8B%E4%BE%8B,%E3%81%95%E3%82%8C%E3%82%8B%E3%81%93%E3%81%A8%E3%82%82%E3%81%82%E3%82%8B%E3%80%82)を生成してインジェクション(注入)してくれます。 その次に@GetMapping("/")によって(http://localhost:9000/)にアクセスした際の処理を書いています。また、今回はポート番号を変えて作成しているので9000となっています。 これによりアクセスした際には今まで書き込まれていた内容をDBから持ってくる必要があるためJDBCの場合はSQL文を記入しますがJPAはSQL文の代わりにメソッドを使います。 そこでSQL文の"SELECT * FROM テーブル名"に該当するのがrepository.findAll()メソッドです。 今回使っているHTMLに掲示板で文字を表示する際はHTMLのテーブルにいれて表示するためcommentsという属性の値を指定しています。 またrepository.findAll()がaddAttributeというメソッドの中にありますがこれはcommentsという属性の値のところにrepository.findAll()の実行結果を入れるという意味です。 ``` <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org/"> <head> <meta charset="UTF-8"> <title>CommentApp</title> </head> <body> <h3>コメント投稿アプリ</h3> <div th:if="${comments.size() == 0}"> 投稿されたコメントはありません。 </div> <table> <div th:each="comment : ${comments}" th:inline="text"> <tr> <td><a th:href="@{/delete?(id=*{comment.id})}"><button>削除</button></a></td> <td>&nbsp;[[${comment.content}]]</td> </tr> </div> </table> <hr> <form th:action="@{/add}" th:object="${comment}" method="post"> <input type="text" th:field="*{content}"> <button>投稿</button><br><small style="color:red" th:errors="*{content}"></small> </form> <br> </body> </html> ``` SQL文のSELECT文以外にもUPDATEやINSERT,DELETE文もありますがこれらもメソッドで表すことができます。 INSERTやUPDATE文のようにデータを追加したり、更新して保存する場合にはrepository.save(オブジェクト名)というメソッドで行うことができます。 今回のアプリで使っているオブジェクトはこれです↓ ``` package com.example.demo.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; import lombok.Getter; import lombok.Setter; @Getter @Setter @Entity public class Comment { @Id @GeneratedValue private Long id; @NotBlank @Size(max = 40) private String content; } ``` まず@Entityでテーブルに保存するクラス(エンティティ)であることを指定します。 そこから@Idによって対応するテーブルの主キーであることを指定して@GeneratedValueによって主キーの値を連番で自動的に割り当ててくれます。 今回はidのタイプをlongという形にしているだけなのでidの前にLongがついているだけです。後々このIDのタイプが大事になります。 最後にDELETEですがこれはrepository.deleteById(オブジェクト名.消したいID)で行うことができます。今回はすべてをまとめて消したいわけではないので1つずつIDを指定する形になっています。 またこれらのSQLの代わりにメソッドで実行するにはもう一つ大事なファイルが必要です。 ``` package com.example.demo.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.example.demo.model.Comment; public interface CommentRepository extends JpaRepository <Comment, Long> { } ``` このたった数行ですがこれがないと今までのSELECT文やINSERT、UPDATE、DELETE文は動きません。JpaRepositoryというクラスを継承することによってDBのSELECT文等の操作を可能としています。<>の中は,の前がエンティティ名で,の後がIDのタイプとなっています。これを指定することによってエンティティのDBの操作を可能としています。 ## まとめ こういうのを初めて書くのとわからないことだらけで始めているので間違っていることも多いと思いますがすいません。指摘して下されば訂正しておきます。 あとこれを見るより[ここ](https://qiita.com/t-shin0hara/items/eaf44e4f48341616ab97)を参考にして自分も書いているので簡潔に分かりやすくまとまっているのでみてみてください。