2022년 4월 16일(토)
[스파르타코딩클럽] Spring 심화반 - 4주차 - 1
ORM : Object-Relational Mapping
cf) ORM 없이도 개발 가능, 백엔드 개발자도 DB 에 대해 잘 알고 있어야 함 (DB 테이블 설계, SQL 성능 확보 등의 사유로)
영속성 컨텍스트
함수 밑에 줄의 Line 번호 있는 곳을 클릭 ⇒ 브레이크 포인트 (디버깅할 위치) 설정
브레이크 포인트 빨간 동그라미에서 마우스 오른쪽 버튼 클릭 / Thread 클릭, Make Default 클릭
스프링 기동 시 디버깅 모드 선택
브레이크 포인트 부분에서 디버깅 가능한지 확인
데이터베이스 로그 세팅
// resources > application.properties
spring.h2.console.enabled=true
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:./myselectdb;AUTO_SERVER=TRUE
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type.descriptor.sql=trace
server.port=8090
"Step Over" 를 클릭해서 줄 이동을 하면서 DB 테이블 변경내용,
Entity 저장 시
Entity 조회 시
'1차 캐시' 사용의 장점
Entity 삭제
Entity 업데이트 방법
DB의 연관관계 필요성
JPA 연관관계 설정방법
@Enitity
public class Order {
@OneToMany
private List<Food> foods;
@OneToOne
private Coupon coupon;
}
---------------------------------------------
@Entity
public class User {
@ManyToMany
List<Restaurant> likeRestaurants;
}
구현시 Database 상황
Spring Data JPA에서는
기본제공 기능 예시
// 1. 상품 저장
Product product = new Product(...);
productRepository.save(product);
// 2. 상품 전체 조회
List<Product> products = productRepository.findAll();
// 3. 상품 전체 개수 조회
long count = productRepository.count();
// 4. 상품 삭제
productRepository.delete(product);
public interface ProductRepository extends JpaRepository<Product, Long> {
// (1) 회원 ID 로 등록된 상품들 조회
List<Product> findAllByUserId(Long userId);
// (2) 상품명이 title 인 관심상품 1개 조회
Product findByTitle(String title);
// (3) 상품명에 word 가 포함된 모든 상품들 조회
List<Product> findAllByTitleContaining(String word);
// (4) 최저가가 fromPrice ~ toPrice 인 모든 상품들을 조회
List<Product> findAllByLpriceBetween(int fromPrice, int toPrice);
}
// (5) 연관관계가 있을경우, 포함된 객체 안의 값을 읽고 싶을 때는 _ 사용 (페이지화 사용 아래 참고)
Page<Product> findAllByUserIdAndFolderList_Id(Long userId, Long folderId, Pageable pageable);
// (6) 찾고자 하는 대상이 여러개 일때(Name : ["신발", "바지"]), 뒤에 In을 사용
List<Folder> findAllByNameIn(List<String> folderNames);
// model
@Setter
@Getter // get 함수를 일괄적으로 만들어줍니다.
@NoArgsConstructor // 기본 생성자를 만들어줍니다.
@Entity // DB 테이블 역할을 합니다.
public class Folder {
// ID가 자동으로 생성 및 증가합니다.
@GeneratedValue(strategy = GenerationType.AUTO)
@Id
private Long id;
@Column(nullable = false)
private String name;
@ManyToOne
@JoinColumn(name = "USER_ID", nullable = false)
private User user;
public Folder(String name, User user) {
this.name = name;
this.user = user;
}
}
// RequestDto
@Getter
public class FolderRequestDto {
List<String> folderNames;
}
// Controller
@RestController
public class FolderController {
private final FolderService folderService;
@Autowired
public FolderController(FolderService folderService) {
this.folderService = folderService;
}
@PostMapping("api/folders")
public List<Folder> addFolders(
@RequestBody FolderRequestDto folderRequestDto,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
List<String> folderNames = folderRequestDto.getFolderNames();
User user = userDetails.getUser();
List<Folder> folders = folderService.addFolders(folderNames, user);
return folders;
}
}
// Service
@Service
public class FolderService {
private final FolderRepository folderRepository;
@Autowired
public FolderService(FolderRepository folderRepository) {
this.folderRepository = folderRepository;
}
// 로그인한 회원에 폴더들 등록
public List<Folder> addFolders(List<String> folderNames, User user) {
List<Folder> folderList = new ArrayList<>();
for (String folderName : folderNames) {
Folder folder = new Folder(folderName, user);
folderList.add(folder);
}
return folderRepository.saveAll(folderList);
}
// 로그인한 회원이 등록된 모든 폴더 조회
public List<Folder> getFolders(User user) {
return folderRepository.findAllByUser(user);
}
}
// Repository
public interface FolderRepository extends JpaRepository<Folder, Long> {
List<Folder> findAllByUser(User user);
}
import org.springframework.data.domain.Page;
// 로그인한 회원이 등록한 관심 상품 조회
@GetMapping("/api/products")
public Page<Product> getProducts(
@RequestParam("page") int page,
@RequestParam("size") int size,
@RequestParam("sortBy") String sortBy,
@RequestParam("isAsc") boolean isAsc,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
Long userId = userDetails.getUser().getId();
page = page - 1;
return productService.getProducts(userId, page, size, sortBy, isAsc);
}
// Service
// 회원 ID 로 등록된 상품 조회
public Page<Product> getProducts(Long userId, int page, int size, String sortBy, boolean isAsc) {
Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
Sort sort = Sort.by(direction, sortBy);
Pageable pageable = PageRequest.of(page, size, sort);
return productRepository.findAllByUserId(userId, pageable);
}
// Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
Page<Product> findAllByUserId(Long userId, Pageable pageable);
}