inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[인프런 워밍업 스터디 클럽 0기_BE] 2주차 회고록 정리

dmstjd0214
0

요일 별 내용 정리

Day6

 

강의

여기서 더 나아가 @Configuration vs @Component

    private final BookJpaRepository bookJpaRepository;
    private final UserLoanHistoryRepository userLoanHistoryRepository;
    private final UserRepository userRepository;

    @Autowired
    public BookService(BookJpaRepository bookJpaRepository, UserLoanHistoryRepository userLoanHistoryRepository, UserRepository userRepository) {
        this.bookJpaRepository = bookJpaRepository;
        this.userLoanHistoryRepository = userLoanHistoryRepository;
        this.userRepository = userRepository;
    }

생성자를 통해 주입 받는 방식으로 가장 권장하는 방법입니다. @RequiredArgsConstructor를 사용하여 생성자를 생략할 수 있습니다. 여기서 @RequiredArgsConstructor은 롬복이 정의해놓은 어노테이션으로 final이나 notnull로 되어있는 생성자에 대한 내용을 자동으로 생성해주는 어노테이션입니다.

private JdbcTemplate jdbcTemplate;

@Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate
}

Setter에 의존성 주입을 하는 방법이지만 사용하지 않습니다.

@Autowired
private JdbcTemplate jdbcTemplate;

필드에 직접적으로 의존성 주입을 직접거는 방식이지만, Field injection is not recommended이라는 프레임워크 메세지와 함께 사용되지않는 방법입니다.

image강의에 대한 일부 내용으로 인터페이스를 생성하여 다형성을 활용해 메서드를 나눠놓았지만, 문제점은 어떤 곳에 대한 클래스를 사용해야할지 모르는 상황이 올 수 있는데 두가지 방법이 있습니다.

 

@Primary, @Qualifier 우선 순위

 

과제

노션 : https://silvercastle.notion.site/6-92b90a65eb4a4cfaa7241162fd8e3fa2?pvs=4

깃허브 : https://github.com/backgom1/Inflearn_BE0_Study/tree/main/ens-library-app/src/main/java/com/group/enslibraryapp/daliy/daysix

 

 

Day7

강의

  jpa:
    hibernate:
      ddl-auto: none
    properties:
      hibernate:
        format_sql:
        show_sql:
        dialect: org.hibernate.dialect.MySQL8Dialect
@Column(nullable = false , length = 20, name = "name")
  1. null확인, 길이, 이름을 지정합니다. 테이블의 컬럼을 지정하는 어노테이션입니다.

  2. name이 동일하다면 name은 생략하다. Column 어노테이션도 생략이 가능하다.

     

     

public interface UserRepository extends JpaRepository<User,Long> {
}
  1. 레포지토리 인터페이스를 생성하여 JpaRepository<엔티티 객체 ,엔티티 객체의 ID>를 입력해주면 Spring Data JPA 사용이 완료 됩니다.

    private final UserRepository userRepository;

    public void saveUser(UserCreateRequestDto request) {
        userRepository.save(new User(request.getName(), request.getAge()));
    }
  1. 생성자를 이용한 의존성 주입을 진행한 후 쿼리문을 날려 사용합니다. save는 이때 엔티티의 있는 필드명을 입력을 해줘야합니다.

기본적으로 제공하는 Spring JPA 메서드

Optional<타입>을 활용하여, null값에 대한 처리를 진행하여 코드에 대한 가독성 및 null처리를 유연하게 처리할 수 있습니다.

과제

해당 과제를 진행하면서 Stream문에 대한 사용방법과 도메인 객체를 만들면서 아 이땐 이렇게 했구나라는 대답을 얻을 수 있었습니다. 또한 왜 사용해야지 하면서 깊게깊게 공부하다보니 이런식으로 동작하는 구나에 대해 많이 배웠습니다.

또한 클래스와 엔드포인트가 동일한 문제를 겪으면서 프로젝트에 대한 패키지에 대해 다시 되돌아보는 시간이였습니다.

코치님이 말씀해주신 enum을 통해 분기처리를 작업하는 방향성에 대해 생각하지 못했는데 알게 되어 기뻤습니다.

노션 : https://silvercastle.notion.site/7-28ba1cb6c81a4972b6ec38a4cd69ef96?pvs=4

깃허브 : https://github.com/backgom1/Inflearn_BE0_Study/tree/main/ens-library-app/src/main/java/com/group/enslibraryapp/daliy/dayseven

 

 

Day 8

강의

//어노테이션을 달면 메서드 시작 아래에서 트랜잭션 시작
//함수가 예외없이 잘끝나면 commit
//아니면 rollback;
    @Transactional
    public void saveUser(UserCreateRequestDto request) {
        userRepository.save(new User(request.getName(), request.getAge()));
        throw new IllegalArgumentException("틀렸습니다.");
    }

트랜잭션 어노테이션을 통해 saveUser라는 곳에 트랜잭션이 시작되고, save를 진행하여 커밋을 대기하는 상황에 예외가 발생하여 rollback이 되어 데이터베이스상에 저장이 되지 않는 모습을 볼 수 있습니다.

image

    @Transactional(readOnly = true)
    public List<UserResponseDto> getUsers() {
        List<User> users = userRepository.findAll();
        return users.stream()
                .map(user -> new UserResponseDto(user.getId(), user.getName(), user.getAge()))
                .collect(Collectors.toList());
    }

select절은 @Transactional의 속성 중 readonly = true는 생성,수정,삭제에 대한 처리를 진행하지않고 조회만 해 성능 향상에 도움이 됩니다!!

여기서 알아야할점은 checkedException은 예외가 발생하여도 트랜잭션 작업에 롤백 상황이 있어도 커밋이 됩니다.

하지만 구글링을 통해 확인 해보았는데! try-catch및 개발자가 직접적으로 예외를 던져준다면, checkedException도 롤백을 진행할 수 있습니다. 꼭 checkedException은 트랜잭션 작업에 롤백이 안된다는 무조건적인것이 아니였습니다!!

Day 9

강의

 

Day10

강의

 @ManyToOne
 private User user;

JPA는 연관관계에 대해 사용하는 방법으로 @ManyToOne으로 묶어 사용했으며, 반대 방향에서는

@OneToMany(mappedBy = "user")
    private List<UserLoanHistory> userLoanHistoryList  = new ArrayList<>();

를 사용하여 양방향 연관관계에 대해 배웠습니다. 연관관계에 대한 주인은 주도권이 가지고있는 연결된 필드를 가진 사람이 주인이며mappedBy는 주인이 아닌 곳에 달아줘야하는것을 알았습니다. 또한 @ManyToOne를 가진 쪽이 주인인것으로 배웠으며, 연관관계에 많이 헷갈렸고 지금도 많이 헷갈렸지만, 조금씩 알아갔습니다.

또한 주인의 대한 setter를 사용해야 연관되어있는 엔티티에 값이 저장되며, 주인이 아닌곳에 저장시, 주인 엔티티가 저장이 되지 않는 것을 배웠습니다.

 

    public void loanBook(String bookName) {
        this.userLoanHistoryList.add(new UserLoanHistory(this, bookName));
    }

    public void returnBook(String bookName){
        UserLoanHistory targetHistory = this.userLoanHistoryList.stream()
                .filter(history -> history.getBookName().equals(bookName))
                .findFirst()
                .orElseThrow(IllegalArgumentException::new);
        targetHistory.doReturn();
    }

도메인 객체에 대한 관심사를 묶어 협력하여 도메인 계층에 비지니스로직이 들어간 코드를 보고 와.. 저렇게 할수도 있구나 이러면 기능적으로 명확해지겠구나라는 생각을 했고 연관관계에 대해 조금더 깊게 생각이 들었습니다.

그렇지만 연관관계에 대해 많이 묶여버린다면 사이드 이펙트에대한 고려와 성능상의 문제가 생길 수 있어 여러 아키텍쳐 공부 및 비지니스 요구사항에 대해 공부를 해야한다 느꼈으며, 아 아직 정말 많이 멀었다 생각했습니다. 그렇지만 해야할 일을 하나씩 진행하며 성장하고 있다는 기분을 받았고, 그것이 원동력을 만들어주었던 것 같습니다. 2주차에는 급하게 작성한 부분들때문에 부족해보이고 모자랐다 생각이 들었고, 다음 주차에서는 좀 더 신경을 많이 써서 진행을 해야겠다 생각했습니다.

또한 미니 프로젝트를 팀 별로 구성하여 작업을 진행해보며, 내가 미쳐 생각하지 못했던 부분, 내가 더 나은부분에 대해 토론을 하며 배워갈 예정입니다.

답변 0