SpringFrameworkを使用したDB操作


- [はじめに](#はじめに)
- [Controller・Repository・Entity・DBの関係性](#controllerrepositoryentitydbの関係性)
- [JpaRepositoryインターフェース](#jparepositoryインターフェース)
  - [findAll(全件検索)](#findall全件検索)
  - [findBy○○(部分検索)](#findby部分検索)
  - [saveAndFlush(更新)](#saveandflush更新)
  - [saveAndFlush(変更)](#saveandflush変更)
  - [deleteBy○○(削除)](#deleteby削除)

# はじめに

今年(2023年)の４月から未経験でIT企業に就職しました。Springを使用したDB操作について自身のアウトプットを目的にまとめました。間違っている箇所等があればご指摘いただけますと幸いです。

使用するテーブルはcharactersテーブルです。ChatGPTに作成してもらったので年齢とか誕生日は間違っていそうですが
今回は気にしないようにしています。

```
-- ドラえもんキャラクターテーブル--
CREATE TABLE characters (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  age INT,
  species VARCHAR(50),
  birthdate DATE
);

INSERT INTO characters (id, name, age, species, birthdate)
VALUES
(1, 'Doraemon', 100, 'Robotic Cat', '2112-09-03'),
(2, 'Nobita', 10, 'Human', '2112-08-07'),
(3, 'Shizuka', 10, 'Human', '2113-01-01'),
(4, 'Gian', 10, 'Human', '2112-11-20'),
(5, 'Suneo', 10, 'Human', '2112-10-02');
```

テーブルは下記のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/8d4d05b6-751f-a73c-64cb-abf0f5b3547f.png)

今回使用するファイルは<br>
Controller→CharacterController.java
Repository→CharacterRepository.java
Entity→Character.java
View→○○.html
です。

# Controller・Repository・Entity・DBの関係性

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/d6c400b4-cb97-ead1-da0c-7bf022eb90ce.png)

# JpaRepositoryインターフェース

JpaRepositoryは、Spring Data JPAフレームワークが提供するインターフェースの一つです。このインターフェースは、データベースの操作を行うための一般的なメソッドを提供し、開発者が簡単にデータベースへのアクセスを実現できるようにします。

JpaRepositoryは、Spring Data JPAのリポジトリ層を実装するための基本的なCRUD（Create, Read, Update, Delete）操作をサポートします。

## findAll(全件検索)

このメソッドは、データベース内のすべてのエンティティを取得するために使用されます。

```CharacterController.java
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class CharacterController {

 @Autowired
 private CharacterRepository characterRepository;

 //全件検索
 @RequestMapping("/doraemon1")
 public String process1(Model m) {
  List<Character> characters = characterRepository.findAll();

  m.addAttribute("characters", characters);

  return "display1";
 }

}
```

```CharacterRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CharacterRepository extends JpaRepository<Character, Integer> {
}
```

```Character.java
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "characters")
public class Character {
 @Id
 private int id;
 private String name;
 private int age;
 private String species;
 private String birthdate;
 
 public Character() {}
 
 public Character(int id, String name, int age, String species, String birthdate) {
  this.id = id;
  this.name = name;
  this.age = age;
  this.species = species;
  this.birthdate = birthdate;
 }
 
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public String getSpecies() {
  return species;
 }
 public void setSpecies(String species) {
  this.species = species;
 }
 public String getBirthdate() {
  return birthdate;
 }
 public void setBirthdate(String birthdate) {
  this.birthdate = birthdate;
 }
 
 
}
```

```display1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>全件検索</title>
</head>
<body>
<table border="1">
 <tr>
  <th>ID</th><th>NAME</th><th>AGE</th><th>species</th><th>birthdate</th>
 </tr>
 <tr th:each="character: ${characters}">
  <td th:text="${character.id}"></td>
  <td th:text="${character.name}"></td>
  <td th:text="${character.age}"></td>
  <td th:text="${character.species}"></td>
  <td th:text="${character.birthdate}"></td>
 </tr>
</table>
</body>
</html>
```

検索結果は下記のようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/7d23d732-88f7-a840-75ad-24a09bc7cd8c.png)
しっかり全部のデータが取れていることが確認できる。

## findBy○○(部分検索)

このメソッドは、指定された条件に基づいてエンティティを検索するために使用されます。
ここではID=1のDoraemonを取得する。

```CharacterController.java
package com.example.myapp;

import java.util.List;
import java.util.Optional;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class CharacterController {

 @Autowired
 private CharacterRepository characterRepository;

 // 部分検索
 @RequestMapping("/doraemon2")
 public String process2(Model m) {
  Character c = null;
  Optional<Character> record = characterRepository.findById(1);

  if (!record.isEmpty()) {
   c = record.get();
  }

  m.addAttribute("character", c);

  return "display2";

 }
}

```

```CharacterRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CharacterRepository extends JpaRepository<Character, Integer> {
}
```

```Character.java
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "characters")
public class Character {
 @Id
 private int id;
 private String name;
 private int age;
 private String species;
 private String birthdate;
 
 public Character() {}
 
 public Character(int id, String name, int age, String species, String birthdate) {
  this.id = id;
  this.name = name;
  this.age = age;
  this.species = species;
  this.birthdate = birthdate;
 }
 
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public String getSpecies() {
  return species;
 }
 public void setSpecies(String species) {
  this.species = species;
 }
 public String getBirthdate() {
  return birthdate;
 }
 public void setBirthdate(String birthdate) {
  this.birthdate = birthdate;
 }
 
 
}
```

```display2.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>部分検索</title>
</head>
<body>
<table border="1" th:if="${character} !=null">
 <tr>
  <th>ID</th><th>NAME</th><th>AGE</th><th>SPECIES</th><th>BIRTHDATE</th>
 </tr>
 <tr>
  <td th:text="${character.id}"></td>
  <td th:text="${character.name}"></td>
  <td th:text="${character.age}"></td>
  <td th:text="${character.species}"></td>
  <td th:text="${character.birthdate}"></td>
 </tr>
</table>
<div th:if ="${character} == null">
 存在しません
</div>
</body>
</html>
```

部分検索の結果は下記のようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/bdf5f8f0-eeaf-00ab-267a-8486ac67f616.png)
実際に、id=1のDoraemonが取得できていることがわかる。

存在しないIDのときは存在しませんと表示させる。

## saveAndFlush(更新)

このメソッドはInsert,Update,Deleteを反映するメソッドです。今回は、id=6にDoramiを追加します。

```CharacerController.java
package com.example.myapp;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class CharacterController {

 @Autowired
 private CharacterRepository characterRepository;

 // 更新
 @RequestMapping("/doraemon3")
 @Transactional
 public String process3(Model m) {
  Character c = new Character(6, "Dorami", 100, "Robotic Cat", "2112-12-24");

  characterRepository.saveAndFlush(c);

  m.addAttribute("message", "更新完了");

  return "display3";
 }
}

```

```CharacterRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CharacterRepository extends JpaRepository<Character, Integer> {
}
```

```Character.java
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "characters")
public class Character {
 @Id
 private int id;
 private String name;
 private int age;
 private String species;
 private String birthdate;
 
 public Character() {}
 
 public Character(int id, String name, int age, String species, String birthdate) {
  this.id = id;
  this.name = name;
  this.age = age;
  this.species = species;
  this.birthdate = birthdate;
 }
 
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public String getSpecies() {
  return species;
 }
 public void setSpecies(String species) {
  this.species = species;
 }
 public String getBirthdate() {
  return birthdate;
 }
 public void setBirthdate(String birthdate) {
  this.birthdate = birthdate;
 }
 
 
}
```

```display3.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>更新・変更・完了</title>
</head>
<body>
<div th:text="${message}"></div>
</body>
</html>
```

更新結果は下記のようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/731cbc15-fc36-a13a-9cd1-629843cc56db.png)
id=6にDoramiが更新されていることがわかる。

## saveAndFlush(変更)

ここでは、id=6のDoramiをid=6のminiDoraに変更する。

```CharacterController.java
package com.example.myapp;

import java.util.List;
import java.util.Optional;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class CharacterController {

 @Autowired
 private CharacterRepository characterRepository;
 
 // 変更
 @RequestMapping("/doraemon4")
 @Transactional
 public String process4(Model m) {
  Character c = new Character(6, "miniDora", 100, "Robotic Cat", "2112-12-24");

  characterRepository.saveAndFlush(c);

  m.addAttribute("message", "変更完了");

  return "display3";
 }
}

```

```CharacterRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CharacterRepository extends JpaRepository<Character, Integer> {
}
```

```Character.java
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "characters")
public class Character {
 @Id
 private int id;
 private String name;
 private int age;
 private String species;
 private String birthdate;
 
 public Character() {}
 
 public Character(int id, String name, int age, String species, String birthdate) {
  this.id = id;
  this.name = name;
  this.age = age;
  this.species = species;
  this.birthdate = birthdate;
 }
 
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public String getSpecies() {
  return species;
 }
 public void setSpecies(String species) {
  this.species = species;
 }
 public String getBirthdate() {
  return birthdate;
 }
 public void setBirthdate(String birthdate) {
  this.birthdate = birthdate;
 }
 
 
}
```

```display3.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>更新・変更・完了</title>
</head>
<body>
<div th:text="${message}"></div>
</body>
</html>
```

変更前のテーブル：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/6e666288-9c6c-653b-c92b-c973b0019aea.png)
変更後のテーブル：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/55944a18-1667-d1f6-07a5-d689cba0e9f4.png)
したがって、id=6の部分がDoramiからminiDoraに変わっていることがわかる。

## deleteBy○○(削除)
このメソッドは、指定された条件に一致するエンティティを削除するために使用されます。
ここでは、id=6を削除する。

```CharacterController.java
package com.example.myapp;

import java.util.List;
import java.util.Optional;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class CharacterController {

 @Autowired
 private CharacterRepository characterRepository;

 // 削除
 @RequestMapping("/doraemon5")
 @Transactional
 public String process5(Model m) {

  characterRepository.deleteById(6);

  m.addAttribute("message", "削除完了");

  return "display3";
 }
}

```

```CharacterRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CharacterRepository extends JpaRepository<Character, Integer> {
}
```

```Character.java
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "characters")
public class Character {
 @Id
 private int id;
 private String name;
 private int age;
 private String species;
 private String birthdate;
 
 public Character() {}
 
 public Character(int id, String name, int age, String species, String birthdate) {
  this.id = id;
  this.name = name;
  this.age = age;
  this.species = species;
  this.birthdate = birthdate;
 }
 
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
 public String getSpecies() {
  return species;
 }
 public void setSpecies(String species) {
  this.species = species;
 }
 public String getBirthdate() {
  return birthdate;
 }
 public void setBirthdate(String birthdate) {
  this.birthdate = birthdate;
 }
 
 
}
```

```display3.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>更新・変更・完了</title>
</head>
<body>
<div th:text="${message}"></div>
</body>
</html>
```

変更前テーブル:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/6e7d4150-d47b-a14e-2c1b-feb4c09b6c60.png)
変更後テーブル:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752598/c511352e-60ba-c6b6-fb5b-3830cdd9cee9.png)
となり、id=6のminiDoraがなくなっていることが確認できる。