
이전의 데이터베이스 연결을 JDBC로만 했었는데 이를 JPA로 바꿀 예정이다.
또한, 작성일자와 수정일자를 Auditing을 적용하여 표현해보겠다.
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
해당 hibernate를 추가한다.
아래 3가지는 DB에 요청하는 모든 SQL을 보기좋게 출력해주기 위함이며
ddl-auto는 create, create-drop, update, validate, none 을 제공해준다.
// JPA 설정
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
해당 의존성을 추가한다.
entity를 jpa에서 사용할 수 있게끔 만들어주어야한다.
package com.sparta.memo.entity;
import com.sparta.memo.dto.MemoRequestDto;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity // JPA가 관리할 수 있는 Entity 클래스 지정
@Getter
@Setter //조심히 사용!!..
@Table(name = "memo") // 매핑할 테이블의 이름을 지정
@NoArgsConstructor
public class Memo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", nullable = false)
private String username;
@Column(name = "contents", nullable = false, length = 500)
private String contents;
public Memo(MemoRequestDto requestDto) {
this.username = requestDto.getUsername();
this.contents = requestDto.getContents();
}
public void update(MemoRequestDto requestDto) {
this.username = requestDto.getUsername();
this.contents = requestDto.getContents();
}
}
이렇게 @Entity 애너테이션으로 클래스를 지정하고 @Table 애너테이션으로 직접 DB의 memo 이름의 테이블과 매핑하여 사용하는 방식으로 진행하였다.
해당 repository를 JpaRepository를 상속받는 인터페이스로 우선 만들어 버릴것이다!
public interface MemoRepository extends JpaRepository<Memo, Long> {
}
package com.sparta.memo.service;
import com.sparta.memo.dto.MemoRequestDto;
import com.sparta.memo.dto.MemoResponseDto;
import com.sparta.memo.entity.Memo;
import com.sparta.memo.repository.MemoRepository;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
import java.util.List;
//비즈니스 로직
@Service
public class MemoService {
private final MemoRepository memoRepository;
public MemoService(MemoRepository memoRepository) {
this.memoRepository = memoRepository;
}
public MemoResponseDto createMemo(MemoRequestDto requestDto) {
// RequestDto -> Entity
Memo memo = new Memo(requestDto);
// DB 저장
Memo saveMemo = memoRepository.save(memo);
// Entity -> ResponseDto
MemoResponseDto memoResponseDto = new MemoResponseDto(memo);
return memoResponseDto;
}
public List<MemoResponseDto> getMomos() {
return memoRepository.findAll().stream().map(MemoResponseDto::new).toList();
}
@Transactional
public Long updateMemo(Long id, MemoRequestDto requestDto) {
//해당 메모 있는지 확인
Memo memo = findMemo(id);
// memo 내용 수정
memo.update(requestDto);
return id;
}
public Long deleteMemo(Long id) {
// 해당 메모가 DB에 존재하는지 확인
Memo memo = findMemo(id);
memoRepository.delete(memo);
return id;
}
private Memo findMemo(Long id){
// 해당 메모가 DB에 존재하는지 확인
return memoRepository.findById(id).orElseThrow(()->
new IllegalArgumentException("선택한 메모는 존재하지 않습니다.")
);
}
}
별로 달라지는 것은 없다!
왜냐 이전에 이미 repository에서 실행하는 메소드들의 이름을 jparepository에 있는 네임과 같이 코드를 짰었기 때문이다..
만약 다르게했다면 이것도 하나하나 찾아가면서 바꾸긴해야했을 것 같다.
여기에서 중요하다고 생각되는 부분은 updateMemo 메서드 위 Transactional 애너테이션이다.
먼저 JpaRepository를 보게되면

이러한 식으로 transactional 이 기본 클래스에는 readonly로만 되어있고, delete와 같이 삭제되는 부분이는 메소드 위에 readonly를 풀어놓은것을 확인할 수 있다.
그런데 이곳에 update와 같은 메소드는 없다고 jpa 포스트에서 말했었다!
이를 memo entity에서 update 메소드를 통해 수정해야하는 것이기 때문에 따로 JpaRepository에서 설정되어있지않아 해당 메소드 위에 Transactional을 따로 지정해준것이다.
package com.sparta.memo.entity;
import jakarta.persistence.*;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Timestamped {
@CreatedDate
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
//Java Date패키지나 calendar 같은 날짜랑 mapping할때 사용 // spring에서 date, time, timestamp
private LocalDateTime createdAt;
@LastModifiedDate
@Column
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime modifiedAt;
}
이 클래스를 추가하며, Memo entity에 해당 클래스를 상속하여 create와 modified 시간 컬럼을 추가한다.
또한, Response받았을 때도 두 컬럼이 필요하므로 LocalDateTime 타입으로 해당 컬럼들을 추가한다.
해당 클래스에도 auditing 관련 세팅을 해주어야한다.
package com.sparta.memo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing
@SpringBootApplication
public class MemoApplication {
public static void main(String[] args) {
SpringApplication.run(MemoApplication.class, args);
}
}
위 코드에서 import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing 이 두줄이 바로 그것이다.
해당 설정을 해서 auditing 기능을 사용할 수 있게 된다.
지금 우리 프로젝트에서 메모를 추가하면 가장 아래로 내려가게된다.
이렇게하면 최근에한게 계속 아래로 내려가서 확인하기 어려우니 내림차순으로 바꾸려고한다.
repository 인터페이스에 쿼리 메소드를 추가하면 쉽게 해결할 수 있다.
쿼리메소드 형식에 맞추어서
List<Memo> findAllByOrderByModifiedAtDesc();
메소드를 추가하고, service에 findAll부분을 해당 메소드로 변경하면된다.
순서대로 메소드를 뜯어서 보자면
findAllBy : 모든것을 찾을건데
OrderBy : 순서대로
ModifiedAtDesc : 수정시간을 내림차순으로!
라는 뜻이된다.