스프링 입문 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
수강 중@SpringBootTest
어노테이션 붙이기 : 스프링 컨테이너와 테스트 함께 실행 (실제 스프링 구동)통합테스트 (integration test)
: spring, db 등을 함께 구동하는 테스트단위테스트 (unit test)
: 이전에 했던대로 컨테이너 없이 기능단위로 테스트하는 것. 통합테스트보다 훨씬 속도가 빠르기 때문에 단위테스트를 잘 만드는 것이 중요함.commit
을 해야 반영됨. 바로 반영되는 것처럼 보이는 것들도 사실 auto-commit
이 되는 것@transational
어노테이션: 테스트 시작 전 트랜잭션 시작 -> 쿼리 실행 -> 항상 rollback
-> DB 변경 없으므로 다음 테스트에 영향 주지 않음 (@Test
에 붙었을 때만 rollback. 일반 service 등에 붙었을땐 정상동작)@Commit
어노테이션 붙이기JdbcTemplate
, MyBatis
등 라이브러리는 JDBC API의 반복코드 대부분 제거해주지만 sql은 직접 작성해야 함. 여전히 실무에서 많이 사용.SimpleJdbcInsert
: 테이블명, 인덱스 컬럼명 받아서 insert query 알아서 생성ORM (Object-Relational Mapping)
: 객체와 관계형 데이터베이스 테이블을 매핑하는 기술jpa
: 인터페이스만 제공하며 entity 매핑 필요함 => 구현체로 hybernate
사용EntityManager
주입 받아야 함jpql
이라는 쿼리 언어 사용 : 객체지향으로 쿼리 작성 가능@Transactional
필요show-sql=true # jpa가 날리는 sql 쿼리 볼 수 있음
ddl-auto=none # 테이블 없을 땐 class보고 알아서 테이블도 생성해주지만(create), 현재 있으므로 패스
ALTER TABLE MEMBER ADD PW VARCHAR(20)
실행해 컬럼 맞춰주니 해결됨javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not prepare statement
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1626)
at org.hibernate.query.Query.getResultList(Query.java:165)
at com.ticktack.homeytest.repository.JpaMemberRepository.findByName(JpaMemberRepository.java:35)
...
at com.ticktack.homey_test.service.MemberServiceIntegrationTest.회원가입(MemberServiceIntegrationTest.java:37)
...
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "MEMBER0.PW" not found; SQL statement:
select member0.id as id1_0, member0.name as name2_0, member0.pw as pw3_0 from member member0 where member0.name=? [42122-200]
...
Querydsl
라이브러리 이용JdbcTemplate
, mybatis
등등 섞어서 사용공통 관심 사항(cross-cutting concern)
: 여러 메소드, 기능, 파일에 공통적으로 적용해야 할 사항핵심 관심 사항 (core concern)
: 서비스 핵심 로직공통 관심 사항
과 핵심 관심 사항
의 분리@Aspect
@Component // spring bean으로 등록
public class TimeTraceAop {
@Around("execution(* com.ticktack.homey_test..*(..))") // 패키지 모든 곳에 적용 가능 (aop around로 검색)
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("START : " + joinPoint.toString());
// START : execution(List org.springframework.data.jpa.repository.JpaRepository.findAll())
try {
return joinPoint.proceed(); // 여기에서 기존 서비스 로직 등 실행되는 듯
} finally { // try 이후 실행
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("END : " + joinPoint.toString() + " " + timeMs + "ms");
// END : execution(String com.ticktack.homey_test.Controller.MemberController.list(Model)) 222ms
}
}
}