출처
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8
스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
김영한 강사님
H2는 처음 들어본다!
흥미롭다..
원래 DB 설정하느라 1시간 버려야 되는거 아닌가? (환경 설정이랑 척진 사람)
금방 설치 할 수 있어서 편리했다!
고대의 개발 방식
자바는 Database와 연동하기 위해서는 무조건 jdbc
가 필요함
build.gradle
에 라이브러리를 추가해줘야 함
Datasource
를 생성자 주입으로 spring으로 부터 받아준다.String sql = "insert ~~";
Datasource
객체로부터 Connection
객체를 받아준다.Connection conn = dataSoruce.getConnection();
PreparedStatement
객체를 만들어주고 excute 해준다.private Connection getConnection() {
return DataSourceUtils.getConnection(dataSource);
}
private void close(Connection conn) throws SQLException {
DataSourceUtils.releaseConnection(conn, dataSource);
}
application.properties
파일이 태초부터 있어서 그냥 사용 할 수 있는 것도 매우 인상적이다.
개방-폐쇄 원칙(OCP, Open-Closed Principle)
이 부분이 신기한게 생각해보면 나는 이걸 .. 해 본적이 없는 것이다...! 회사에서 juit 사용 할 때도 그냥 ES 질의 시에만 해보고! TDD 공부 해볼 때도 순수 자바에서만 해봤기 때문에!! 흥미로웠다.
테스트를 진행해보는데 이해하기 힘든 일이 일어났다.
insert 과정을 테스트하고 있으니까 분명히 insert는 일어 날 것인데 list로 조회해보면 insert 된 멤버를 찾을 수가 없었다. 그리고 게다가 동일한 이름에 대해서는 validate를 하고 있어서 exception이 떨어져야 되는데 안 떨어진다! 그냥 ui로 추가를 해봤을 때는 너무 잘 들어가는 사태 발생. 심지어 id까지 38로 늘어난 상황!
근데 생각해보면.. 테스트를 하는데 이게 DB에 영향을 미쳐도 되는걸까..? 테스트하는 데이터가 DB에 쌓이게 될텐데 쌓이지 않는게 맞지 않나? 라는 생각이 들었고 또 커뮤니티를 뒤져봤다... 근데 사실 그 뒤에 설명해주실 예정이었다...
@Transactional
어노테이션에 의해 트랜잭션을 시작하고 테스트 완료 후에 롤백 해주고 있었다. 이렇게 바로 설명해주시는데 강의 멈춰놓고.. insert 이후에 commit이 안된건가 하고 직접 commit을 때리고 있었다;
@SpringBootTest
: 스프링 컨테이너와 테스트를 함께 실행한다는 의미이다!
설정이 너무 쉬워서 신기하다..
좋은 테스트는! 순수 자바 테스트로 만들어졌을 확률이 더욱 크다! (흥미로움)
Mybatis와 비슷한 라이브러리로 JDBC API에서 본 반복 코드를 대부분 제거해준다.
생성자가 하나인 경우에 @Autowired를 생략 할 수 있다.
public Optional<Member> findByName(String name) {
List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper());
return result.stream().findAny();
}
private RowMapper<Member> memberRowMapper() {
return (rs, rowNum) -> {
Member member = new Member();
member.setId(rs.getLong(rs.getString("id")));
member.setName(rs.getString("name"));
return member;
};
}
코드를 입력해보는 내내 나는 Mybatis 인간이라서 그런지 쿼리문이 저렇게 코드에 들어가 있는게 가독성이 좋아보이지는 않았다. 뭔가 상수화해서 관리하는 건가? 어떻게 저렇게 코드에 슥 넣어 둘 수 있는걸까? 만약에 100줄 정도의 복잡한 쿼리의 경우에는 어떻게 하려는걸까...?
RowMapper
라는 것도 처음봐서 벅벅..
insert 나올 때는 약간 ES가 떠올랐다.. 너무 Mybatis 종속 인간이 되버린걸까..? 과연 이게 편리한 걸까(!!!)
장기적으로 쿼리 같은 걸 관리하려면 Mybatis가 필요해 보이는걸? 이라는 생각을 했다.
결국엔 SQL은 개발자가 관리를 하게 되는데 JPA를 사용하면 JDBCtemplate/Mybatis가 제공하는 기존의 반복 코드 줄이기는 물론이고 기본적인 SQL도 JPA가 제공해줘서 개발 생산성이 올라간다!
SQL과 데이터 중심의 설계 -> 객체 중심의 설계
위에서 Mybatis가 편리한거 아닌가? 라고 생각했는데 바로 JPA를 알려주시면서 구글 트랜드로 JPA의 중요성을.. 강조해주셨다...😂 아애 처음보는 개념이다!
ORM (Object Relational Mapping)
@Entity
어노테이션을 통해서 해당 객체와 DB 매핑이 이루어 질 수 있다.
JPA는 EntityManager
를 통해서 동작한다. build.gradle
에서 추가한 라이브러리에 의해서 현재 데이터베이스와 매핑을 해주기 때문에 EntityManager
를 주입받아서 사용하면 된다.
어렵다 ㅜ^ㅜ..
강의 따라하면서
https://www.inflearn.com/questions/237621
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
이런 오류가 났다...
댓글 따라했더니 해결됬다..
강의는 버전이 1.4였나 그런데 최신으로 받아서 생기는 문제인것 같은데.. 수정 사항을 다시 지우고 돌리니까 오류가 나지 않았다. 도대체 뭘까; 시간을 너무 많이 써서 우선 넘어간다..
JPA를 편리하게 사용하도록 도와주는 기술이여서 JPA를 먼저 학습한 뒤에 사용해야 함
관계형 데이터베이스를 사용하는 경우 스프링 데이터 JPA를 사용해야 함
...?
이건 뭔가 JPA 당했다라는 말이 맞을 정도로 그냥 코드가 확 줄어들어 버렸다.. 헙🤢
public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
@Override
Optional<Member> findByName(String name);
}
스프링 데이터 JPA가 SpringDataJpaMemberRepository 를 스프링 빈으로 자동 등록 해준다.
공통 JpaRepository<Member, Long>를 확인해보면 기본적으로 구현이 되어 있는 것을 확인 할 수 있다. 기본적인 pk를 통한 CRUD와 같은 작업은 이미 구현이 되어 있다!
인터페이스(SpringDataJpaMemberRepository)의 이름을 정의 해주는 것 만으로.. 단순한 작업을 진행 할 수 있다!
실무 > JPA, 스프링 데이터 JPA (기본) + Querydsl(동적 쿼리) + JPA(네이티브 쿼리)를 사용한다.
JPA 개념이 너무;; 익숙하지 않아서 프로젝트에 반영하려면 따로 더 공부가 필요할 것 같다. 개념이 안서서 흐린눈 하고 싶지만 편리해보여서 모른척하기에는 양심에 찔리는 기분이다.. 화이팅..