한 주간 배우면서 새로 알게된 개념이나 잘 못 알았던 개념을 서로 나누어 보아요.
컨트롤러에서 RequestParam VO로 받아도 될까?서비스 레이어에서 DTO↔Entity 간 변환을 담당한다면 서비스에서 다른 서비스 메서드 호출이 필요로 할 경우 어떻게 사용해야 할까요?로그가 이상하게 떠요 ㅜㅜ ✅h2 web 연결 안됨문제 ✅Save시에 Select 쿼리가 나와요 ✅원본객체와 저장된객체의 불일치 문제 ✅깨알 Live Template 만들어 단축키 등록CreatedBy 설정하기
컨트롤러에서 RequestParam VO로 받아도 될까?
서비스 레이어에서 DTO↔Entity 간 변환을 담당한다면 서비스에서 다른 서비스 메서드 호출이 필요로 할 경우 어떻게 사용해야 할까요?
로그가 이상하게 떠요 ㅜㅜ ✅
- → 오른쪽에 있는
Soft-Wrap
누르면 깔껌해짐

before

after

h2 web 연결 안됨문제 ✅
- 버전 변경 (2 → 1 버전 변경해보기)
- h2 DB 버전 문제
- 1.4.200 버전을 쓰신다면 문제가 없을 것으로 봅니다.
- 현재 h2 DB 최신(2.1.212) 버전을 다운 받아서 table을 확인하려 했지만 에러 발생
- 해결 방법
- 첫번째 pom.xml의 h2 db dependency의 버전을 설정한다.
- 두번째 application.properties나 yml 파일의 url을 확인하고 데이터베이스가 존재하는 지 확인한다.
- 저의 경우 url :
jdbc:h2:~/order
- order.trace, order.mv 파일을 확인한다
- 확인 방법
- 로컬디스트(c) → 사용자 → (자신폴더) → 파일 유무 확인
- 숨김 파일이라서 숨김 항복을 표시하신 후에 확인한다.
- 존재하고 있다면 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|


Save시에 Select 쿼리가 나와요 ✅
결론: @GeneratedValue 안쓰고 @Id 만 사용할 경우, JPA에서 persist대신 merge를 사용한다
→ 해당객체에
implement Persistable<String>
구현해주면 해결된다.1. 문제상황
save를 하는 경우 insert 쿼리만 날아가기를 희망
그러나 장문의 select 쿼리가 우선 날아가는것을 확인


2. 왜 이게 문제인가
다음 블로그에 해당 이슈가 자세히 설명되고 있습니다.
세줄로 간단히 요약하자면 다음과 같습니다
- JPA의 기본동작은 select → insert(혹은 update) 이다.
- 업데이트할 때에도 업데이트 필드만 선택적으로 하는것이 아닌 객체 전체가 바꿔지기 때문에 merge기능을 의도하고 사용해야 할 일은 거의 없다.
- 따라서
변경을 위해서는 변경감지(dirty-checking)
,저장을 위해서는 persist
만이 호출되도록 유도를 해야 실무에서 성능 이슈를 경험하지 않을 수 있다.
따라서 초기에 간단한 예제에서부터 의도하지 않은 쿼리를 잡아두어야 한다고 생각했습니다
3. 해결방법
해당객체에
implement Persistable<String>
구현해주기
JpaRepository 구현체(SimpleJpaRepository)의 save함수는
isNew함수로 새로 생성되는 객체인지, 기존에 존재해서 업데이트 되는 객체인지 판단

GeneratedValue로 자동생성해주는 경우
- save시 isNew가 자동적용됨

@Id 만 지정해 주었을 경우 (현재 Order의 상태)
- Persistable<String>을 implement해서
- getId()와 isNew()함수를 overriding 해주어야 함
- isNew에는 해당 객체가 새로운지 판단할 수 있는 로직을 작성한다
- 보통은 CreatedAt으로 판단
- (@CreatedDate)를 해놓으면 Persist 순간에 저장되기 때문에 한번 저장되면 null이 아님
@Override public boolean isNew() { return this.getCreatedAt()==null; }


insert 쿼리안나오는 문제 ✅
- @DataJPATest 에는 @Transactional 어노테이션 존재
saveAndFlush
하면 바로 날아감
- 근데 위에 문제를 해결하니 깔껌하게 insert가 나옴
원본객체와 저장된객체의 불일치 문제 ✅
결론 : 자동으로 설정해주는것에 수동으로 값을 넣어줘서 오류 발생함
→
@CreatedDate
붙인곳에 따로 수동으로 값을 할당해주지 말자문제상황
객체 생성후 저장하니 저장 데이터와 원본 데이터가 불일치함


결과 :
order - orderDatetime=2022-05-12T11:40:32.062
saveOrder - orderDatetime=2022-05-12T11:40:32.135686500

findOrder 해서 가져오면 문제없음..
Order와 saveOrder 비교는 필요없는걸까요?
왜문제인지
같은 트랜젝션 내에서는 order랑 findOrder가 같음을 보장해주어야 하는데 불일치하네요!!
해결
@CreatedDate를 작성하면 Persist 순간에 값을 할당해주는데
null을 피하기 위해 createdAt = LocalDatetime.now()를 작성하고 있었는데
어차피 persist때 넣어주니까 상관없음, 근데 할당한 값때문에 불일치가 발생함
- before

- after

return String 응답 테스트하기(json x)
.andExpect(content().string(containString(${기대하는String값}))
깨알 Live Template 만들어 단축키 등록
- 테스트 코드 작성할 때 유용하게 썼습니다.
- setting → editor → live Template에서 진행
- Abbreviation에 단축키 등록 예) tdd
- template text에 자신이 사용할 코드 작성
- 적용 후 사용



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