Spring boot H2 DB

강서진·2023년 12월 19일

4번째 필수 강좌 Part 1. ch3. 1~5강 요약

Lombok

Lombok 라이브러리는 보일러플레이트 코드를 자동으로 생성해주는 편리한 라이브러리로, 컴파일할 때 사용한 애너테이션을 애너테이션 프로세서를 통해 1차로 빌드한 후 롬복을 통해 자동생성되는 코드를 추가해줘야 정상적으로 작동한다.

	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'

DTO가 있다고 할 때, 원래는 Getter, Setter 등을 하나씩 다 만들어주었다. IDE의 자동완성 기능이 추가되어 이 기능도 간편해졌지만, 변수 이름이 바뀌거나 하면 일일이 수정해주어야 했는데, Lombok의 애너테이션을 사용하면 일일이 바꿔줄 필요 없이 변경사항이 자동으로 반영되기 때문에 편리하다.

@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DevDTO {
    String name;
    Integer age;
    LocalDateTime startAt;
}

Lombok을 사용하면 Getter, Setter 이외에도 toString, Constructor도 손쉽게 만들어줄 수 있다.

  • @NoArgsConstructor
    생성O, 초기화X인 생성자 메서드
  • @AllArgsConstructor
    생성과 동시에 초기화가 가능한 생성자 메서드
  • @RequiredArgsConstructor
    필수인(=final 이 붙었거나 non-null 키워드가 붙은) Argument를 가진 생성자 메서드

위의 언급된 메서드뿐만 아니라 Equal and Hashcode까지도 포함한 메서드를 자동생성해주는 애너테이션이 @Data이다. 하지만 보안을 이유로 toString을 재정의할 필요가 없을 때도 있고, 불필요한 기능이 추가될 수도 있어서 실무에서는 잘 사용하지 않는다고 한다.

또, @Builder라는 패턴이 존재한다.

DevDTO devDTO = DevDTO.builder()
	.name("e")
    .age(25)
    .startAt(LocalDateTime.now())
    .build();

@Builder 애너테이션을 붙이면 간단한 패턴으로 새 객체를 생성할 수 있게 된다. @Builder를 사용하면 코드의 응집력이 높아지고, 동작이 바뀌더라도 수정할 부분이 줄어든다.

@UtilityClass는 빈으로 등록하지 않고, static method를 가지고 날짜변환 ,숫자 변환 등의 정적인 로직을 돌리는 Utility 클래스를 만드는 데 사용한다. 더이상 상속을 받지 못하게 하고, 생성자를 프라이빗으로 만드는 등 다양한 기능을 가지고 있다.

H2DB

H2는 메모리 데이터베이스로, 테스트 용도로 많이 쓰인다. H2에 접근하려면 콘솔이 필요한데, 그러려면 application.properties에 설정을 추가해주어야 한다.
우선 application.yaml로 파일 확장자를 변경한 후 내용을 추가한다.

spring:
  h2:
    console:
      enabled: true

서버를 구동해보면,

H2 console available at '/h2-console'. Database available at 'jbdc:h2:....'

하고 url이 뜬다.

localhost:8080/h2-console을 입력하면 db 접속 콘솔이 뜨는데, JDBC URL에 url을 넣고 connect를 눌러주면 메모리에 생성된 DB에 접근할 수 있다.

커맨드 창에 sql문을 입력하면 작동한다.

H2DB는 메모리 DB로, 서버를 끄면 데이터가 전부 날아가며, 구동할 때마다 새로 생기고 새로운 url이 발행된다. 즉 서버를 킬 때마다 DB를 새롭게 세팅해주어야 한다.

Entity

DB에 저장할 객체 엔티티를 만든다. @Entity 애너테이션을 달아주는데, Entity는 Primary Key를 요구하므로 @Id와 @GeneratedValue를 설정해준다.

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Developer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    private DeveloperLevel developerLevel;

    @Enumerated(EnumType.STRING)
    private DeveloperSkillType developerSkillType;

    private Integer experienceYEars;
    private String memberId;
    private String name;
    private Integer age;

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;
}

Enum을 사용해 developerLevel과 developerSkillType을 설정하고, @CreatedDate와 @LastModifiedDate를 사용해 생성 날짜와 수정 날짜를 받는다. 이를 Auditing이라고 하는데, 이 기능을 사용하려면 DeveloperApplication에 @EnableJpaAuditing을 추가한다.

또, DB에 Developer 엔티티를 저장할 수 있도록 JpaRepository를 상속받는 레포지토리 인터페이스를 만든다.

@Repository
public interface DeveloperRepository extends JpaRepository<Developer, Long> {
}

추가로 DMakerService를 생성하고, DeveloperRepository를 @RequiredArgsConstructor로 주입받는다.
기존에는 @Autowired와 @Inject를 사용했으나, 테스트에 불편하다는 단점이 있었다. 이를 개선하여 생성자에 주입을 받는 방식으로 바꿨지만, 주입받을 Repository가 여러 개일 경우 생성자를 계속 고치는 것도 번거로워 @RequiredArgsConstructor를 사용하게 되었다.

@Service
@RequiredArgsConstructor
public class DMakerService {
    private final DeveloperRepository developerRepository;
}

DeveloperEntity를 하나 DB에 저장하는 메서드를 만들고, 이를 호출해본다.

// DMakerService
	@Transactional
    public void createDeveloper(){
        Developer developer = Developer.builder()
                .developerLevel(DeveloperLevel.JUNIOR)
                .developerSkillType(DeveloperSkillType.FRONT_END)
                .experienceYears(2)
                .name("T")
                .age(25)
                .build();
        developerRepository.save(developer);
    }
    
// DMakerController

기본적으로 데이터를 저장하거나 생성할 때는 POST 메서드로 요청을 보내야 하지만, 지금은 간단하게 테스트하는 용이므로 GET 메서드로 호출하였다.

@GetMapping("/create-dev")
    public void testDeveloper(){
        dMakerService.createDeveloper();
    }

새로 H2DB를 만든 후 보면, DEVELOPER라는 테이블이 생성되어 있다. /create-dev를 호출하면 새로운 객체가 저장된 것을 확인할 수 있다.

그런데 CREATED_AT과 UPDATED_AT이 null로 들어가 있다.
이는 Entity에 @EntityListeners(AuditingEntityListener.class)를 빼먹어서 그렇다.

수정하면 시간이 잘 찍힌다.

0개의 댓글