Spring Data JPA 기초
application.properties에 다음 설정 추가 (xml에 들어있던 오라클 접속에 대한 내용)
spring.jpa.database-platform=org.hibernate.dialect.OracleDialect
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
# none, create, create-drop, update, validate
spring.jpa.properties.hibernate.hbm2ddl.auto=create //none으로 해야 데이터 안지워짐
엔티티를 만들자
Member.java
package com.study.springboot.jpa;
import java.time.LocalDate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Builder
@Entity(name="JPAMEMBER01")
public class Member
{
@Id
@GeneratedValue
private Long id;
private String username;
@Column(name="create_date")
private LocalDate createDate;
}
- lombok => 엔티티 만드는 코드를 간결하게
- @Getter
- @AllArgsConstructor : 모든 컬럼을 이용해서 파라미터를 받는 생성자 만듬
- @NoArgsConstructor : default 생성자 생성
- @Builder : 필요한 값만 이용해서 멤버 개체 생성
MemberRepository.java
package com.study.springboot.jpa;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface MemberRepository extends JpaRepository<Member, Long>
{
// 제네릭타입 : long 이 아니라 Long으로 작성.
// 기본적인 Create, Read, Update, Delete 자동으로 생성
}
- jparepository를 상속한 memberRepository를 만들어 Repository로 등록
- 파라미터로 엔티티인 Member와 Member id의 데이터 타입(Long)을 두번째 파라미터로 넣음
- create, persist, read, find, update, delete, remove 다 자동으로 만들어짐
이 reposritory를 사용하는 service를 추가해보자
package com.study.springboot.jpa;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MemberService
{
@Autowired
private MemberRepository memberRepository;
public Member insert(Member member)
{
Member returnMember = memberRepository.save(member);
return returnMember;
}
public Optional<Member> select(Long id)
{
Optional<Member> member = memberRepository.findById(id);
return member;
}
public List<Member> selectAll()
{
return memberRepository.findAll();
}
public void delete(Long id)
{
memberRepository.deleteById(id);
}
public Member update(Member member)
{
// insert 메서드에서 사용한 방법과 똑같다.
// 키 값과 같은 값이 있으면 업데이트, 없으면 인서트
Member returnMember = memberRepository.save(member);
return returnMember;
}
}
- save: persist와 동일한 기능
- findById(id)에서 Id는 밑의 Id임

서비스를 url과 맵핑 시켜주는 컨트롤러를 추가해보자
MyController.java
package com.study.springboot.jpa;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class MyController
{
@Autowired
MemberService memberService;
@RequestMapping("/")
public String root() throws Exception {
return "menu";
}
@RequestMapping("/insert")
public String insert(@RequestParam("username") String username, Model model)
{
// 데이터 3개 정도 추가하고 테스트
Member member = Member.builder()
.username(username)
.createDate(LocalDate.now())
.build();
Member result = memberService.insert(member);
model.addAttribute("member", result);
return "insert";
}
@RequestMapping("/select")
public String select(@RequestParam("id") Long id, Model model)
{
Optional<Member> result = memberService.select(id);
if (result.isPresent())
{
model.addAttribute("member", result.get());
}
else
{
model.addAttribute("member", null);
}
return "select";
}
@RequestMapping("/selectAll")
public String selectAll(Model model)
{
List<Member> result = memberService.selectAll();
model.addAttribute("members", result);
return "selectAll";
}
@RequestMapping("/delete")
public String delete(@RequestParam("id") Long id)
{
memberService.delete(id);
return "delete";
}
@RequestMapping("/update")
public String update(Member member, Model model)
{
Member result = memberService.update(member);
model.addAttribute("member", result);
return "update";
}
}
- insert(), selclet(), selelctAll, delete(), update()호출
- builder() 이용해서 username과 LocalDate만 가지고 객체 만듬
- select로 member를 받았지만 값이 존재하지 않을 수도 있기 때문에 Optional 씀
- 이때 데이터가 있느냐 없느냐를 체크하는 것이 isPresent()
JpaRepository 활용

SQL문에 바인딩 되는 값들 출력해보려면? => 디버깅 편리
# show sql data binding
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.orm.jdbc.bind=trace
위의 코드 추가하면 됨
이제 Member엔티티를 수정해보자
package com.study.springboot.jpa;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Builder
@Entity(name="JPAMEMBER02")
public class Member
{
@Id
@GeneratedValue
private Long id;
private String name;
private String email;
}
MemberRepository.java
id 외에 name과 email로도 검색할 수 있도록 코드 추가하자
package com.study.springboot.jpa;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface MemberRepository extends JpaRepository<Member, Long>
{
// 제네릭타입 : long 이 아니라 Long으로 작성.
// 기본적인 Create, Read, Update, Delete 자동으로 생성
// findBy 뒤에 컬럼명을 붙여주면 이를 이용한 검색이 가능하다
Optional<Member> findByName(String keyword);
Optional<Member> findByEmail(String keyword);
// 다양한 확장이 가능하다.
List<Member> findByNameLike(String keyword);
List<Member> findByNameLikeOrderByNameDesc(String keyword);
List<Member> findByNameLikeOrderByNameAscEmailDesc(String keyword);
List<Member> findByNameLike(String keyword, Sort sort);
}
MemberService.java
package com.study.springboot.jpa;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
@Service
public class MemberService
{
@Autowired
private MemberRepository memberRepository;
public void insert()
{
Member member;
member = Member.builder().name("이순신").email("test1@test.com").build();
memberRepository.save(member);
member = Member.builder().name("강감찬").email("test2@test.com").build();
memberRepository.save(member);
member = Member.builder().name("을지문덕").email("test3@test.com").build();
memberRepository.save(member);
member = Member.builder().name("계백").email("test4@test.com").build();
memberRepository.save(member);
member = Member.builder().name("김유신").email("test5@test.com").build();
memberRepository.save(member);
member = Member.builder().name("연개소문").email("test6@test.com").build();
memberRepository.save(member);
member = Member.builder().name("양만춘").email("test7@test.com").build();
memberRepository.save(member);
member = Member.builder().name("김종서").email("test8@test.com").build();
memberRepository.save(member);
member = Member.builder().name("최영").email("test9@test.com").build();
memberRepository.save(member);
}
public List<Member> selectAll()
{
return memberRepository.findAll();
}
public Optional<Member> selectId(Long search)
{
Optional<Member> member = memberRepository.findById(search);
return member;
}
public Optional<Member> selectName(String search)
{
Optional<Member> member = memberRepository.findByName(search);
return member;
}
public Optional<Member> selectEmail(String search)
{
Optional<Member> member = memberRepository.findByEmail(search);
return member;
}
public List<Member> selectNameLike(String search)
{
List<Member> member = memberRepository.findByNameLike(search);
return member;
}
public List<Member> selectNameLikeNameDesc(String search)
{
List<Member> member = memberRepository.findByNameLikeOrderByNameDesc(search);
return member;
}
public List<Member> selectNameLike(String search, Sort sort)
{
List<Member> member = memberRepository.findByNameLike(search, sort);
return member;
}
}
- findByName(), findByEmail 등을 쓰는 controller를 만들어보자
MyController.java
package com.study.springboot.jpa;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MyController
{
@Autowired
MemberService memberService;
@RequestMapping("/")
public String root() throws Exception {
return "menu";
}
@RequestMapping("/insert")
public String insert(Member member, Model model)
{
memberService.insert();
return "insert";
}
@RequestMapping("/selectAll")
public String selectAll(Model model)
{
List<Member> result = memberService.selectAll();
model.addAttribute("members", result);
return "selectAll";
}
@RequestMapping("/selectById")
public String selectById(@RequestParam("id") Long search, Model model)
{
Optional<Member> result = memberService.selectId(search);
model.addAttribute("member", result.get());
return "select_id";
}
@RequestMapping("/selectByName")
public String selectByName(@RequestParam("name") String search, Model model)
{
Optional<Member> result = memberService.selectName(search);
model.addAttribute("member", result.get());
return "select_name";
}
@RequestMapping("/selectByEmail")
public String selectByEmail(@RequestParam("email") String search, Model model)
{
Optional<Member> result = memberService.selectEmail(search);
model.addAttribute("member", result.get());
return "select_email";
}
@RequestMapping("/selectByNameLike")
public String selectByNameLike(@RequestParam("name") String search, Model model)
{
String name = search + "%";
List<Member> result = memberService.selectNameLike(name);
model.addAttribute("members", result);
return "select_name_list";
}
@RequestMapping("/selectByNameLikeNameDesc")
public String selectByNameLikeNameDesc(@RequestParam("name") String search, Model model)
{
String name = search + "%";
List<Member> result = memberService.selectNameLikeNameDesc(name);
model.addAttribute("members", result);
return "select_name_list";
}
@RequestMapping("/selectByNameLikeOrder")
public String selectByNameLikeOrder(@RequestParam("name") String search, Model model)
{
String name = search + "%";
Sort sort = Sort.by(Sort.Order.desc("name"));
// Sort sort = Sort.by(Sort.Order.desc("name"), Sort.Order.asc("email"));
List<Member> result = memberService.selectNameLike(name, sort);
model.addAttribute("members", result);
return "select_name_list";
}
}
- /selectByName?name=을지문덕 같이 파라미터를 받아서 그 파라미터를 selelctName 메서드에 넣어줌
Sort sort = Sort.by(Sort.Order.desc("name"));
- name 순서를 desc로 sort하겠다 => .desc("email")하면 한번 더 email순서로 sort
- orderBy가 길어질 때 sort를 쓰는 것
페이지 처리
Member.java
generateValue 코드 추가해주기
package com.study.springboot.jpa;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Builder
@Entity(name="JPAMEMBER03")
public class Member
{
@Id
@SequenceGenerator (
name = "mySequence03",
sequenceName = "JPAMEMBER03_SEQ",
initialValue = 1,
allocationSize = 1
)
@GeneratedValue (generator = "mySequence03")
private Long id;
private String name;
private String email;
}
MemberRepository.java
package com.study.springboot.jpa;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface MemberRepository extends JpaRepository<Member, Long>
{
// 제네릭타입 : long 이 아니라 Long으로 작성.
// 기본적인 Create, Read, Update, Delete 자동으로 생성
// List<Member> findByNameLike(String keyword, Pageable pageable);
Page<Member> findByNameLike(String keyword, Pageable pageable);
}
- List로 리턴값을 받을 수도 있지만 page로 받아야 페이지 기능을 사용할 수 있음
- 위의 예제에서는 sort를 사용했지만 이번엔 pageable 사용
MemberService.java
@Service
public class MemberService
{
@Autowired
private MemberRepository memberRepository;
// public List<Member> selectNameLike(String search, Pageable pageable)
// {
// List<Member> member = memberRepository.findByNameLike(search, pageable);
// return member;
// }
public Page<Member> selectNameLike(String search, Pageable pageable)
{
Page<Member> member = memberRepository.findByNameLike(search, pageable);
return member;
}
}
MyController.java
@Controller
public class MyController
{
@Autowired
MemberService memberService;
@RequestMapping("/")
public String root() throws Exception {
return "menu";
}
@RequestMapping("/selectByNameLike")
public String selectByNameLike(@RequestParam("name") String search,
@RequestParam("page") String page,
Model model)
{
System.out.println("***"+ search +"***");
System.out.println("***"+ page +"***");
String name = search + "%";
Sort sort = Sort.by(Sort.Order.desc("name"));
int nPage = Integer.parseInt(page) - 1;
// 페이지는 0부터
Pageable pageable = PageRequest.ofSize(10).withPage(nPage).withSort(sort);
Page<Member> result = memberService.selectNameLike(name, pageable);
List<Member> content = result.getContent(); //10개 리스트
long totalElements = result.getTotalElements(); //24
int totalPages = result.getTotalPages();//3
int size = result.getSize();//10
int pageNumber = result.getNumber() + 1; // 0부터 시작하므로 +1
int numberOfElements = result.getNumberOfElements(); // content의 개수
//모델에 넣어서 출력해보자
model.addAttribute("members", content);
model.addAttribute("totalElements", totalElements);
model.addAttribute("totalPages", totalPages);
model.addAttribute("size", size);
model.addAttribute("pageNumber", pageNumber);
model.addAttribute("numberOfElements", numberOfElements);
return "select_name_list";
}
}
- name, page를 파라미터로 받음
- 정렬이 desc로 되게 sort 만들어줌
- PageRequest를 이용해서 페이지를 요청할 때 10개씩 한페이지에 나오게 하려면 ofSize 설정
- 전체 페이지개수는 withPage로 설정
- 이렇게 pageble개체를 만든 후 서비스에 selectNameLike 메소드를 넘겨줌 => 리턴값 result에 우리가 원하는 정보들이 다 들어있음
JPQL 기초
spring data jpa에서도 sql문을 직접 작성할 수 있음
- jpql은 엔티티임
- member.java는 위의 예제 그대로 사용하고 MemberRepository.java만 수정
1. JPQL
package com.study.springboot.jpa;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface MemberRepository extends JpaRepository<Member, Long>
{
// Page<Member> findByNameLike(String keyword, Pageable pageable);
// 일반 JPQL쿼리, from뒤는 엔티티 명 (소문자로 할 시 에러)
@Query("select m from JPAMEMBER03 m where m.name like :name1 order by m.id desc")
List<Member> findMembers(@Param("name1") String name2);
@Query("select m from JPAMEMBER03 m where m.name like :name1")
List<Member> findMembers(@Param("name1") String name2, Sort sort);
@Query("select m from JPAMEMBER03 m where m.name like :name1")
Page<Member> findMembers(@Param("name1") String name2, Pageable pageable);
}
- (데이터베이스가 아니라) 영속성 객체를 대상으로 query문을 만듬
- 쿼리문에 영속성 객체명을 바로 사용하면 안되고 aliias( 예제에서는 m)을 만들어서 사용해야함
2.일반 sql문
// 일반 SQL쿼리 : 테이블명 등 대소문자 가리지 않는다.
@Query(value = "select * from jpamember03 where name like :name1 order by id desc",
nativeQuery = true)
List<Member> findMembersNative(@Param("name1") String name2);
이 repository를 사용하는 service도 수정해주자
package com.study.springboot.jpa;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
@Service
public class MemberService
{
@Autowired
private MemberRepository memberRepository;
public List<Member> selectMembers1(String search)
{
List<Member> member = memberRepository.findMembers(search);
return member;
}
public List<Member> selectMembers2(String search, Sort sort)
{
List<Member> member = memberRepository.findMembers(search, sort);
return member;
}
public Page<Member> selectMembers3(String search, Pageable pageable)
{
Page<Member> member = memberRepository.findMembers(search, pageable);
return member;
}
public List<Member> selectMembers4(String search)
{
List<Member> member = memberRepository.findMembersNative(search);
return member;
}
}
MyController.java
package com.study.springboot.jpa;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class MyController
{
@Autowired
MemberService memberService;
@RequestMapping("/")
public String root() throws Exception {
return "menu";
}
@RequestMapping("/selectNameLike1")
public String selectMembers1(@RequestParam("name") String search,
Model model)
{
System.out.println("***1:"+ search +"***");
String name = search + "%";
List<Member> result = memberService.selectMembers1(name);
model.addAttribute("members", result);
return "select_name_list_1";
}
@RequestMapping("/selectNameLike2")
public String selectMembers2(@RequestParam("name") String search,
Model model)
{
System.out.println("***2:"+ search +"***");
String name = search + "%";
Sort sort = Sort.by(Sort.Order.asc("id"));
List<Member> result = memberService.selectMembers2(name, sort);
model.addAttribute("members", result);
return "select_name_list_1";
}
@RequestMapping("/selectNameLike3")
public String selectMembers3(@RequestParam("name") String search,
@RequestParam("page") String page,
Model model)
{
System.out.println("***3:"+ search +"***");
System.out.println("***3:"+ page +"***");
String name = search + "%";
Sort sort = Sort.by(Sort.Order.desc("id"));
int nPage = Integer.parseInt(page) - 1;
// 페이지는 0부터
Pageable pageable = PageRequest.ofSize(10).withPage(nPage).withSort(sort);
Page<Member> result = memberService.selectMembers3(name, pageable);
List<Member> content = result.getContent();
long totalElements = result.getTotalElements();
int totalPages = result.getTotalPages();
int size = result.getSize();
int pageNumber = result.getNumber() + 1; // 0부터 시작하므로
int numberOfElements = result.getNumberOfElements(); // content의 개수
model.addAttribute("members", content);
model.addAttribute("totalElements", totalElements);
model.addAttribute("totalPages", totalPages);
model.addAttribute("size", size);
model.addAttribute("pageNumber", pageNumber);
model.addAttribute("numberOfElements", numberOfElements);
return "select_name_list_2";
}
@RequestMapping("/selectNameLike4")
public String selectMembers4(@RequestParam("name") String search,
Model model)
{
System.out.println("***4:"+ search +"***");
String name = search + "%";
List<Member> result = memberService.selectMembers4(name);
model.addAttribute("members", result);
return "select_name_list_1";
}
}
'개발 > Backend' 카테고리의 다른 글
| [Spring Boot] 예제로 배우는 스프링부트 입문 | 배포 (0) | 2024.07.21 |
|---|---|
| [SpringBoot] 예제로 배우는 스프링부트 입문 | JPA 기초 (0) | 2024.07.21 |
| [Spring Boot] 예제로 배우는 스프링부트 입문 | JdbcTemplate (0) | 2024.07.15 |
| [Spring Boot] 예제로 배우는 스프링부트 입문 | Form값 검증 (0) | 2024.07.07 |
| [Spring Boot] 예제로 배우는 스프링부트 입문 | Web 기초 (0) | 2024.07.06 |