Spring boot

[입문] spring DB 접근 기술

생성자가 하나일 땐 Autowired 생략 가능

 

solid 원칙 - SRP(단일 책임 원칙), OCP(개방-폐쇄 원칙), LSP(리스코프 치환 원칙), DIP(의존 역전 원칙), ISP(인터페이스 분리 원칙)을 말하며, 앞자를 따서 SOILD 원칙이라고 부른다. (https://dev-momo.tistory.com/entry/SOLID-원칙 )

stream?

RowMapper?

 

jpquery - 테이블 대상으로 쿼리 날리는 대신 객체를 대상으로 쿼리 날림

 

마지막 실행 재실행: ctrl + R

인라인 리턴: ctrl + alt + n

refactor: ctrl + t

파일 찾기: ctrl + shift + n

 


H2 데이터베이스 설치

 

H2 데이터베이스 - 교육, 테스트용으로 좋은 가벼운 DB

 

jdbc:h2:tcp://localhost/~/test로 접속해야 충돌 없음

윈도우는 h2/bin/ 디렉토리에서 h2.bat로 실행

 


순수 JDBC

 

순수 JDBC - 20년 전쯤 사용하하던 방식이다.

 

build.gradle에 jdab, h2 라이브러리 추가

application.properties에 설정 추가

 

MemberRepository 인터페이스를 상속받는 JdbcMemberRepository 생성

DataSource를 생성자를 통해 받음

 

    @Override
    public Member save(Member member) {
        String sql = "insert into member(name) values(?)";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql,
                    Statement.RETURN_GENERATED_KEYS);
            pstmt.setString(1, member.getName());
            pstmt.executeUpdate();
            rs = pstmt.getGeneratedKeys();
            if (rs.next()) {
                member.setId(rs.getLong(1));
            } else {
                throw new SQLException("id 조회 실패");
            }
            return member;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
    }

예시로 save만 가져옴

커넥션을 직접 열고 닫으며 sql을 짜서 넣음

 

SpringConfig 파일에서 DatatSource를 생성자에 입력받아 JdbcMemberRepository에 넣어준다

 

기존에 사용하던 MemoryMemberRepository에서 JdbcMemberRepository로만 변경해주면 된다.

다른 코드는 수정할 필요 없이 정상 작동 된다.

 

개방-폐쇄 원칙(OCP, Open-Closed Principle)의 예시.

 


스프링 통합 테스트

 

기존 테스트는 순수 자바 코드만으로 테스트 한 것이다.

스프링 컨테이너와 함께 테스트 할 수 있다.

 

단위테스트: 순수하게 자바코드로 단위별로 시행하는 테스트 <-이게 더 좋은 테스트

통합테스트: 스프링, db 등 다같이 시행하는 테스트 <- 테스트 설계가 잘못되었을 확률 있음

 

@SpringBootTest: 스프링 컨테이너와 테스트 함께 실행

@Transactional: 테스트 완료 후 롤백, DB에 영향 X

 


스프링 JdbcTemplate

 

JdbcTemplate은 실무에서도 자주 사용됨

템플릿메소드 디자인패턴이 있음

 

순수 JDBC의 반복되는 코드를 대부분 제거해준다.

그러나 SQL은 직접 작성해야 한다.

 

    @Override
    public Member save(Member member) {
        SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
        jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");

        Map<String, Object> parameters = new HashMap<>();
        parameters.put("name", member.getName());

        Number key = jdbcInsert.executeAndReturnKey(new
                MapSqlParameterSource(parameters));
        member.setId(key.longValue());
        return member;
    }

예시로 save만 가져옴

생성자에서 DataSoruce를 받아 JdbcTemplate에 넣어준다.

 

순수 Jdbc와 마찬가지로 SpringConfig에서 교체해준다.

 


JPA

 

기존 반복 코드 제거 + 기본적인 SQL도 만들어 준다.

데이터 중심 설계에서 객체 중심의 설계로 패러다임을 전환할 수 있다.

 

build.gradle과 application.properties 설정

 

Member객체에 @Entity어노테이션을 붙여준다.

PK인 id에는 @Id와 @GeneratedValue (db에서 자동으로 생성해준다는.. ) 을 붙인다.

 

@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

 

JpaMemberRepository 생성

public class JpaMemberRepository implements MemberRepository {

    private final EntityManager em;

    public JpaMemberRepository(EntityManager em) {
        this.em = em;
    }

    @Override
    public Member save(Member member) {
        em.persist(member);
        return member;
    }

Jpa에서는 EntityManager를 사용한다.

 

Jpa를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 한다.

MemberService에 @Transactional을 붙여준다.

 

마찬가지로 SpringConfig에서 EntityManager를 받고 JpaManagerRepository로 변경해준다.

 


스프링 데이터 JPA

 

스프링 데이터 JPA - JPA를 편리하게 사용하도록 도와주는 기술, CRUD 기능도 제공함

 

CRUD는 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말이다. 사용자 인터페이스가 갖추어야 할 기능(정보의 참조/검색/갱신)을 가리키는 용어로서도 사용된다.

 

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
    Optional<Member> findByName(String name);
}

MemberRepository와 JpaReopsitory를 상속받는 새 인터페이스를 만든다.

이 인터페이스만 만들면 findById, findAll 등의 기본적인 기능은 모두 알아서 구현해준다.

 

SpringConfig 수정

@Configuration
public class SpringConfig {

    private final MemberRepository memberRepository;

    public SpringConfig(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Bean
    public MemberService memberService(){
        return new MemberService(memberRepository);
    }

 

실무에서는 JPA와 스프링 데이터 JPA를 기본으로 사용하고 복잡한 동적 쿼리는 Querydsl 라이브러리를 사용한다.

를이것으로 해결하기 어려운 쿼리는 JPA가 제공하는 네이티브 쿼리를 사용하거나 JdbcTemplate를 사용한다.