@Transactional
테스트 케이스에 이 어노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고, 테스트 완료 후에 항상 롤백한다. 이렇게 하면 DB에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않는다.
@SpringBootTest
스프링 컨테이너와 테스트를 함께 실행한다.
@Autowired 키워드 생략가능 조건
생성자가 하나일때는 생략 가능
JdbcTemplate 클래스
JdbcTemplate은 JDBC 코어 패키지의 중앙 클래스로 JDBC의 사용을 단순화하고 일반적인 오류를 방지하는데 도움이 된다. 개발자가 JDBC를 직접 사용할 때 발생하는 다음과 같은 반복 작업을 대신 처리해준다.
- 커넥션 획득
- statement를 준비하고 실행
- 결과를 반복하도록 루프를 실행
- 커넥션 종료, statement 및 resultset 종료
- 트랜잭션을 다루기 위한 커넥션 동기화
- 예외 발생 시 스프링 예외 변환기 실행
DataSource 인터페이스
DB와 관계된 커넥션 정보를 담고 있으며 빈으로 등록하여 인자로 넘겨준다. 이 과정을 통해 Spring은 DataSource로 DB와의 연결을 획득한다.
SimpleJdbcInsert
간단하게 데이터를 DB에 저장하기 위해 만들어진 구현체
객체 생성 시 매개값으로 ‘DB와 관계된 커넥션 정보를 담은 DataSource 객체를 매개 값으로 하는’ JdbcTemplate 객체를 넣는다.
withTableName() 메소드
insert 하고자 하는 테이블명을 매개값으로 넣는다
usingGeneratedKeyColumns() 메소드
데이터베이스에 레코드를 추가할 때 자동으로 생성 된 프라이머리 키 값을 가져오기 위해 사용된다.
MapSqlParameterSource 클래스
데이터베이스와 상호 작용할 때 Mapping되어있 정보를 SQL 쿼리의 바인딩 변수에 할당하는 데 사용된다.
jdbcTemplate.query() 메소드
첫 번째 인자 : 실행할 쿼리문을 인자로 넣어줌
두 번째 인자 : 조회 결과를 매핑할 RowMapper 가 리턴타입인 메소드를 넣어줌
세 번째 인자 : 바인딩 변수가 한개라면 그에 해당하는 한개의 값을 인자로 넣어줌, 바인딩 변수가 여러개라면 바인딩 변수의 순서에 맞춰 그 값들을 배열에 넣어서 인자로 넣어줌
RowMapper<T> 인터페이스
인터페이스 이므로 사용하려면 메소드 오버라이딩을 해줘야한다.
public interface RowMapper<T> {
@Nullable
T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
아래의 코드는 RowMapper 인터페이스를 익명구현하기위해 람다식을 사용하여 메소드를 정의하였다.
⭐인터페이스의 익명 구현 객체를 람다식으로 표현하려면 인터페이스가 단 하나의 추상 메소드만 가져야 한다. (RowMapper 인터페이스는 mapRow 추상메소드 하나만 가지고 있음)
⭐인터페이스가 단 하나의 추상 메소드를 가질 때, 이를 함수형 인터페이스(functional interface)라고 한다.
private RowMapper<Member> memberRowMapper() {
return (rs, rowNum) -> {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return member;
};
}
[코드 뜯기]
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
//JdbcTemplate 클래스를 이용하기
public class JdbcTemplateMemberRepository implements MemberRepository {
// JdbcTemplate를 멤버 변수로 선언 해 놓음
private final JdbcTemplate jdbcTemplate;
// JdbcTemplate 사용 시작 (기본 생성자에서 의존성 주입)
// DB와 관계된 커넥션 정보를 담은 DataSource의 객체를 주입시킨다.
// 이때 DataSource는 스프링 빈으로 등록되어 있어야 한다.
public JdbcTemplateMemberRepository(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
// 회원 정보 저장 메소드
@Override
public Member save(Member member) {
// 자동 insert를 가능하게하는 jdbcInsert 객체 생성
SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
// jdbcInsert 객체에 DB insert에 필요한 정보들을 담는 과정 (쿼리문 따로 작성 하지 않아도 됨)
jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");
Map<String, Object> parameter = new HashMap<>(); // member 객체의 정보를 담을 HashMap 객체
parameter.put("name", member.getName()); // member 객체의 정보를 컬럼명과 값으로 HashMap 객체에 mapping & 저장
// insert에 필요한 정보를 담은 jdbcInsert 객체를 parameter를 매개로 받은 executeAndReturnKey 메소드를 통해
// DB에 insert를 실행시킴과 동시에 Primary key를 반환하게 한다.
// 반환된 key의 값이 어떤 타입인지 알 수 없기 때문에 Number 타입으로 받는다.
Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameter));
// 반환받은 Number 타입의 key값을 long 타입으로 바꾼 후 member객체의 id에 set 해준다.
member.setId(key.longValue());
// id와 name이 저장된 member 객체 반환
return member;
}
// 아이디 찾기 메소드
@Override
public Optional<Member> findById(Long id) {
// jdbcTemplate.query() 메소드를 이용
// 첫번째 인자 : 쿼리문
// 두번째 인자 : 실행한 쿼리문의 결과를 담는 객체
// 세번째 인자 : 바인딩변수에 해당하는 값
List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
return result.stream().findAny();
}
// 회원 정보 전체 조회 메소드
@Override
public List<Member> findAll() {
// findById() 메소드와 동일한 구조
return jdbcTemplate.query("select * from member", memberRowMapper());
}
// 이름 찾기 메소드
@Override
public Optional<Member> findByName(String name) {
// findById() 메소드와 동일한 구조
List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
return result.stream().findAny();
}
// 실행한 쿼리문의 결과를 member 객체에 담는 과정의 메소드
private RowMapper<Member> memberRowMapper() {
return (rs, rowNum) -> { //인터페이스 추상메소드 사용을 위해 익명객체 생성
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return member;
};
}
}
'Back-End > Spring Boot' 카테고리의 다른 글
예습)스프링 입문 (0) | 2023.05.11 |
---|---|
예습) 스프링 기초 (0) | 2023.04.27 |
예습) 스프링 기초 (0) | 2023.04.25 |
댓글