HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🚀
Random Bit Flip
/
✈️
[2기 - 아만드] 8주차 RBF
✈️

[2기 - 아만드] 8주차 RBF

주차
SpringBoot Part4
회고일
May 13, 2022
참여자
멘토
Property
tag
한 주간 배우면서 새로 알게된 개념이나 잘 못 알았던 개념을 서로 나누어 보아요.
컨트롤러에서 RequestParam VO로 받아도 될까?서비스 레이어에서 DTO↔Entity 간 변환을 담당한다면 서비스에서 다른 서비스 메서드 호출이 필요로 할 경우 어떻게 사용해야 할까요?로그가 이상하게 떠요 ㅜㅜ ✅h2 web 연결 안됨문제 ✅Save시에 Select 쿼리가 나와요 ✅원본객체와 저장된객체의 불일치 문제 ✅깨알 Live Template 만들어 단축키 등록CreatedBy 설정하기
 

컨트롤러에서 RequestParam VO로 받아도 될까?

서비스 레이어에서 DTO↔Entity 간 변환을 담당한다면 서비스에서 다른 서비스 메서드 호출이 필요로 할 경우 어떻게 사용해야 할까요?

 

로그가 이상하게 떠요 ㅜㅜ ✅

  • → 오른쪽에 있는 Soft-Wrap 누르면 깔껌해짐
    • notion image
before
notion image
after
notion image

h2 web 연결 안됨문제 ✅

  • 버전 변경 (2 → 1 버전 변경해보기)
  • h2 DB 버전 문제
    • 1.4.200 버전을 쓰신다면 문제가 없을 것으로 봅니다.
    • 현재 h2 DB 최신(2.1.212) 버전을 다운 받아서 table을 확인하려 했지만 에러 발생
    • notion image
    • 해결 방법
      • 첫번째 pom.xml의 h2 db dependency의 버전을 설정한다.
      • notion image
      • 두번째 application.properties나 yml 파일의 url을 확인하고 데이터베이스가 존재하는 지 확인한다.
        • 저의 경우 url : jdbc:h2:~/order
          • order.trace, order.mv 파일을 확인한다
        • 확인 방법
          • 로컬디스트(c) → 사용자 → (자신폴더) → 파일 유무 확인
          • 숨김 파일이라서 숨김 항복을 표시하신 후에 확인한다.
          • notion image
          • 존재하고 있다면 order.mv ,order.trace 파일을 삭제한다.
      • 세번째 h2.server 파일 설정
        • 다음과 같이 h2.server 파일에 복붙한다.
        #H2 Server Properties #Wed May 11 14:15:47 KST 2022 11=Generic Oracle|oracle.jdbc.driver.OracleDriver|jdbc\:oracle\:thin\:@localhost\:1521\:XE|sa 12=Generic MS SQL Server 2000|com.microsoft.jdbc.sqlserver.SQLServerDriver|jdbc\:microsoft\:sqlserver\://localhost\:1433;DatabaseName\=sqlexpress|sa 13=Generic MS SQL Server 2005|com.microsoft.sqlserver.jdbc.SQLServerDriver|jdbc\:sqlserver\://localhost;DatabaseName\=test|sa 14=Generic PostgreSQL|org.postgresql.Driver|jdbc\:postgresql\:test| 15=Generic MySQL|com.mysql.jdbc.Driver|jdbc\:mysql\://localhost\:3306/test| 16=Generic HSQLDB|org.hsqldb.jdbcDriver|jdbc\:hsqldb\:test;hsqldb.default_table_type\=cached|sa 17=Generic Derby (Server)|org.apache.derby.jdbc.ClientDriver|jdbc\:derby\://localhost\:1527/test;create\=true|sa 18=Generic Derby (Embedded)|org.apache.derby.jdbc.EmbeddedDriver|jdbc\:derby\:test;create\=true|sa 19=Generic H2 (Server)|org.h2.Driver|jdbc\:h2\:~/order|sa 0=Generic JNDI Data Source|javax.naming.InitialContext|java\:comp/env/jdbc/Test|sa 1=Generic Teradata|com.teradata.jdbc.TeraDriver|jdbc\:teradata\://whomooz/| 2=Generic Snowflake|com.snowflake.client.jdbc.SnowflakeDriver|jdbc\:snowflake\://accountName.snowflakecomputing.com| 3=Generic Redshift|com.amazon.redshift.jdbc42.Driver|jdbc\:redshift\://endpoint\:5439/database| 4=Generic Impala|org.cloudera.impala.jdbc41.Driver|jdbc\:impala\://clustername\:21050/default| webSSL=false 5=Generic Hive 2|org.apache.hive.jdbc.HiveDriver|jdbc\:hive2\://clustername\:10000/default| 6=Generic Hive|org.apache.hadoop.hive.jdbc.HiveDriver|jdbc\:hive\://clustername\:10000/default| 7=Generic Azure SQL|com.microsoft.sqlserver.jdbc.SQLServerDriver|jdbc\:sqlserver\://name.database.windows.net\:1433| 8=Generic Firebird Server|org.firebirdsql.jdbc.FBDriver|jdbc\:firebirdsql\:localhost\:c\:/temp/firebird/test|sysdba webAllowOthers=false 9=Generic SQLite|org.sqlite.JDBC|jdbc\:sqlite\:test|sa webPort=8082 10=Generic DB2|com.ibm.db2.jcc.DB2Driver|jdbc\:db2\://localhost/test|
         
      • 마지막으로 잘 동작하는 지 확인한다.
      notion image
      notion image
       
       

Save시에 Select 쿼리가 나와요 ✅

결론: @GeneratedValue 안쓰고 @Id 만 사용할 경우, JPA에서 persist대신 merge를 사용한다 → 해당객체에 implement Persistable<String> 구현해주면 해결된다.
 
1. 문제상황
save를 하는 경우 insert 쿼리만 날아가기를 희망
그러나 장문의 select 쿼리가 우선 날아가는것을 확인
notion image
notion image
2. 왜 이게 문제인가
다음 블로그에 해당 이슈가 자세히 설명되고 있습니다.
세줄로 간단히 요약하자면 다음과 같습니다
  • JPA의 기본동작은 select → insert(혹은 update) 이다.
  • 업데이트할 때에도 업데이트 필드만 선택적으로 하는것이 아닌 객체 전체가 바꿔지기 때문에 merge기능을 의도하고 사용해야 할 일은 거의 없다.
  • 따라서 변경을 위해서는 변경감지(dirty-checking) , 저장을 위해서는 persist 만이 호출되도록 유도를 해야 실무에서 성능 이슈를 경험하지 않을 수 있다.
 
따라서 초기에 간단한 예제에서부터 의도하지 않은 쿼리를 잡아두어야 한다고 생각했습니다
3. 해결방법
해당객체에 implement Persistable<String> 구현해주기
JpaRepository 구현체(SimpleJpaRepository)의 save함수는
isNew함수로 새로 생성되는 객체인지, 기존에 존재해서 업데이트 되는 객체인지 판단
notion image
GeneratedValue로 자동생성해주는 경우
  • save시 isNew가 자동적용됨
    • notion image
@Id 만 지정해 주었을 경우 (현재 Order의 상태)
  • Persistable<String>을 implement해서
  • getId()와 isNew()함수를 overriding 해주어야 함
  • isNew에는 해당 객체가 새로운지 판단할 수 있는 로직을 작성한다
  • 보통은 CreatedAt으로 판단
    • (@CreatedDate)를 해놓으면 Persist 순간에 저장되기 때문에 한번 저장되면 null이 아님
    • @Override public boolean isNew() { return this.getCreatedAt()==null; }
      notion image
      notion image
 
 
 
insert 쿼리안나오는 문제 ✅
  • @DataJPATest 에는 @Transactional 어노테이션 존재
  • saveAndFlush 하면 바로 날아감
  • 근데 위에 문제를 해결하니 깔껌하게 insert가 나옴
 
 

원본객체와 저장된객체의 불일치 문제 ✅

결론 : 자동으로 설정해주는것에 수동으로 값을 넣어줘서 오류 발생함 → @CreatedDate 붙인곳에 따로 수동으로 값을 할당해주지 말자
문제상황
객체 생성후 저장하니 저장 데이터와 원본 데이터가 불일치함
notion image
notion image
결과 :
order - orderDatetime=2022-05-12T11:40:32.062
saveOrder - orderDatetime=2022-05-12T11:40:32.135686500
notion image
findOrder 해서 가져오면 문제없음..
Order와 saveOrder 비교는 필요없는걸까요?
save랑 find 만 잘 동작하면 될것 같긴 하네요..? x
왜문제인지
같은 트랜젝션 내에서는 order랑 findOrder가 같음을 보장해주어야 하는데 불일치하네요!!
해결
@CreatedDate를 작성하면 Persist 순간에 값을 할당해주는데
null을 피하기 위해 createdAt = LocalDatetime.now()를 작성하고 있었는데
어차피 persist때 넣어주니까 상관없음, 근데 할당한 값때문에 불일치가 발생함
  • before
notion image
  • after
notion image
 
 
return String 응답 테스트하기(json x)
.andExpect(content().string(containString(${기대하는String값}))
 

깨알 Live Template 만들어 단축키 등록

  • 테스트 코드 작성할 때 유용하게 썼습니다.
  • setting → editor → live Template에서 진행
  • Abbreviation에 단축키 등록 예) tdd
  • template text에 자신이 사용할 코드 작성
  • 적용 후 사용
notion image
notion image
notion image

CreatedBy 설정하기

@Bean public AuditorAware<String> auditorProvider(){ return () -> Optional.of(${CreatedBy가 될 ID값}); }
 
  • GRASP
    • 책임할당에 기반한 객체 설계 원칙