- H2 데이터베이스 설치
- 순수 Jdbc
- 스프링 JdbcTemplate
- JPA
- 스프링 데이터 JPA
H2 데이터베이스 설치
> https://www.h2database.com/html/download-archive.html
Archive Downloads
www.h2database.com
- h2 접속 시 경로 : ip대신 localhost라고 입력
- JDBC URL은 jdbc:h2:tcp://localhost/~/test : 파일에 직접 접근하는 것이 아닌 소켓을 통한 접근
순수 JDBC
고대의 선배님들이 쓰던 방법(편하게 들으면 됨)
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-jdbc' : 자바는 기본적으로 db와 붙으려면 jdbc 드라이버가 꼭 있어야 함
runtimeOnly 'com.h2database:h2' : db와 붙을 때 데이터베이스가 제공하는 client가 필요함
resources/application.properties
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=orgh2.Driver
spring.datasource.username=sa
데이터 베이스에 접근하기 위한 준비
JdbcMemberRepository.java
private final DataSource dataSource;
public JdbcMemberRepository(DataSource dataSource) { //generate 단축키 : Alt+Insert
this.dataSource = dataSource;
}
DB에 붙으려면 dataSource가 필요
dataSource를 스프링에게 주입받아야 함. -> getConnection으로 커넥션도 받아야 함
@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); //DB 아이디 인덱스 Z
pstmt.setString(1, member.getName()); // 1 : 쿼리의 ?와 매칭이됨
pstmt.executeUpdate(); // DB에 실제 쿼리가 이때 날아감
rs = pstmt.getGeneratedKeys(); //ID 1,2 .. 자동으로 들어가는거
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);
}
}
어차피 사용하지 않을 것이기 때문에 알아만 두면 됨.
@Override
public Optional<Member> findById(Long id) { //조회
String sql = "select * from member where id = ?"; //쿼리 날리기
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setLong(1, id);
rs = pstmt.executeQuery(); //조회는 execute쿼리임
if(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return Optional.of(member);
} else {
return Optional.empty();
}
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
springConfig.java
@Configuration
public class SpringConfig {
private final DataSource dataSource;
public SpringConfig(DataSource dataSource) {
this.dataSource = dataSource;
}
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
// return new MemoryMemberRepository();
return new JdbcMemberRepository(dataSource);
}
}
memberRepository만 변경


개방-폐쇄 원칙(OCP, Open-Closed Principle)
- 확장에는 열려이고 수정, 변경에는 닫혀있다.
스프링의 DI(Dependencies Injection)을 사용하면 기존 코드를 전혀 손대지 않고, 설정만으로 구현 클래스를 변경할 수 있다.
회원을 등록하고 DB에 결과가 잘 입력되는지 확인하자
데이터를 DB에 저장하므로 스프링 서버를 다시 실행해도 데이터가 안전하게 저장된다.
스프링 통합 테스트
스프링 컨테이너와 DB까지 연결한 통합 테스트를 진행해보자
@SpringBootTest
스프링 컨테이너와 테스트를 함께 실행한다.
@Transactional
테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고, 테스트 완료 후에 항상 롤백한다. 이렇게 하면 DB에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않는다.
스프링 JdbcTemplate
- 스프링 JdbcTemplate과 MyBatis 같은 라이브러리는 JDBC API에서 본 코드를 대부분 제거해준다. 하지만 SQL은 직접 작성해야 한다.
- 실무에서도 많이 사용
JdbcTemplateMemberRepository.java
private final JdbcTemplate jdbcTemplate;
@Autowired // 생성자가 하나일때 Autowired 생략 가능
public JdbcTemplateMemberRepository(DataSource dataSource) { //datasource 인젝션
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
private RowMapper<Member> memberRowMapper(){
return (rs, rowNum) -> { //객체 생성
Member member=new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return member;
};
}
Jdbc 매뉴얼 참고하면 사용 방법 잘 나와있음
JPA
- JPA는 기존의 반복 코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해준다.
- JPA를 사용하면, SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환할 수 있다.
- JPA를 사용하면 개발 생산성을 크게 높일 수 있다.
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
//implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
spring-boot-starter-data-jpa는 내부에 jdbc 관련 라이브러리를 포함한다. 따라서 jdbc는 제거해도 된다.
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
show-sql : JPA가 생성하는 SQL을 출력한다.
ddl-auto : JPA는 테이블을 자동으로 생성하는 기능을 제공하는데 none을 사용하면 해당 기능을 끈다.
- create를 사용하면 엔티티 정보를 바탕으로 테이블도 직접 생성해줌
domain의 Member.java에 @Entity 매핑
@Entity
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
// Id는 pk임 id는 자동으로 번호가 생성되니 IDEMTITY라고 함
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
JPA 리포지토리
public class JpaMemberRepository implements MemberRepository {
private final EntityManager em; //Jpa는 EntityManager 주입 받아야 사용 ㄱㄴ
public JpaMemberRepository(EntityManager em) {
this.em = em;//em이라고 많이 씀
}
@Override
public Member save(Member member) {
em.persist(member); //영구 저장하다 ( 이렇게 하면 jpa가 inser 쿼리 다 만들어줌)
return member;
}
@Override
public Optional<Member> findById(Long id) {
Member member = em.find(Member.class,id);
return Optional.ofNullable(member);
}
@Override
public Optional<Member> findByName(String name) {
List<Member> result = em.createQuery("select m from Member m where m.name = :name",Member.class)
.setParameter("name",name)
.getResultList();
return result.stream().findAny();
}
@Override
public List<Member> findAll() {
return em.createQuery("select m from Member m",Member.class)
.getResultList();
}
}
Service에 @Transactional 추가하기
import org.springframework.transaction.annotation.Transactional
@Transactional
public class MemberService {}
JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 함
- Test로 할 때 DB로 반영하고 싶으면 @Commit 쓰면 됨
스프링 데이터 JPA
public interface SpringDataJpaMemberRepository extends JpaRepository<Member,Long>, MemberRepository {
Optional<Member> findByName(String name);
}
interface가 interface를 받을 때는 extends를 씀

- 인터페이스를 통한 기본적은 CRUD
- findByName(), findByEmail()처럼 메서드 이름만으로 조회 기능 제공
- 페이징 기능 자동 제공
[무료] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 - 인프런 | 강의
스프링 입문자가 예제를 만들어가면서 스프링 웹 애플리케이션 개발 전반을 빠르게 학습할 수 있습니다., - 강의 소개 | 인프런...
www.inflearn.com
'Back-End > Inflearn 강의' 카테고리의 다른 글
[스프링 핵심 원리 - 기본편] 스프링 핵심 원리 이해1 - 예제 만들기 (0) | 2022.05.18 |
---|---|
[스프링 입문] AOP (0) | 2022.05.16 |
[스프링 입문] 회원 관리 예제 - 웹 MVC 개발 (0) | 2022.05.15 |
[스프링 입문] 스프링 빈과 의존관계 (0) | 2022.05.12 |
[스프링 입문] 회원 관리 예제 - 백엔드 개발 (0) | 2022.05.12 |