🙂강의🙂
- 고대의 방식이라고 한다 😑
▨ 목차 ▨
- 환경 설정
- build.gradle 파일에 jdbc, h2 데이터베이스 관련 라이브러리 추가
- 스프링 부트 데이터베이스 연결 설정 추가 (resources/application.properties)
- Jdbc 리포지토리 구현
- Jdbc 회원 리포지토리
- 스프링 설정 변경
[ 환경 설정 ]
✅ build.gradle 파일에 jdbc, h2 데이터베이스 관련 라이브러리 추가하기
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
- 추가 화면
✅ 스프링 부트 데이터베이스 연결 설정 추가하기 (resources/application.properties)
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
- 추가 화면
주의 : 스프링 부트 2.4 부터는 spring.datasource.username=sa 를 꼭 추가해야 한다. 추가하지 않을 시 Wrong user name or password 오류가 발생한다. 마지막에 공백이 들어가도 같은 오류가 발생한다.
참고 : IntelliJ 커뮤니티 (무료) 버전의 경우 application.properties 파일의 왼쪽이 다음 그림과 같이 회색으로 나오지만 실제 동작하는 데는 아무런 문제가 없다. 엔터프라이즈 (유료) 버전에서 제공하는 스프링의 소스 코드를 연결하는 편의 기능이 빠진 것이다.
[ Jdbc 리포지토리 구현 ]
주의 : 이렇게 JDBC API 로 직접 코딩하는 것은 20년 전 이야기로, 참고만 하고 넘어가기
✅ Jdbc 회원 리포지토리 생성하기
- src/main/java/hello.hellospring/repository 에 JdbcMemberRepository class 생성
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.springframework.jdbc.datasource.DataSourceUtils;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class JdbcMemberRepository implements MemberRepository {
private final DataSource dataSource;
public JdbcMemberRepository(DataSource dataSource) {
this.dataSource = 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);
}
}
@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();
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);
}
}
@Override
public List<Member> findAll() {
String sql = "select * from member";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
List<Member> members = new ArrayList<>();
while(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
members.add(member);
}
return members;
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
@Override
public Optional<Member> findByName(String name) {
String sql = "select * from member where name = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name);
rs = pstmt.executeQuery();
if(rs.next()) {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return Optional.of(member);
}
return Optional.empty();
} catch (Exception e) {
throw new IllegalStateException(e);
} finally {
close(conn, pstmt, rs);
}
}
private Connection getConnection() {
return DataSourceUtils.getConnection(dataSource);
}
private void close(Connection conn, PreparedStatement pstmt, ResultSet rs)
{
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (pstmt != null) {
pstmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null) {
close(conn);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void close(Connection conn) throws SQLException {
DataSourceUtils.releaseConnection(conn, dataSource);
}
}
✅ 스프링 설정 변경하기
- src/main/java/hello.hellospring/service/SpringConfig
package hello.hellospring;
import hello.hellospring.repository.JdbcMemberRepository;
import hello.hellospring.service.MemberService;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class SpringConfig {
private DataSource dataSource;
@Autowired
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);
}
}
➡️ MemoryMemberRepository 대신 JdbcMemberRepository
- 스프링 설정 이미지
→ 개방 - 폐쇄 원칙 ( OCP, Open - Closed Principle ) : 확장에는 열려 있고, 수정/변경에는 닫혀 있다
→ 스프링의 DI ( Dependencies Injection ) 을 사용하면 기존 코드를 손대지 않고, 설정만으로 구현 클래스를 변경할 수 있다
→ 데이터를 DB 에 저장하므로 스프링 서버를 다시 실행해도 데이터가 안전하게 저장된다
- 실행 화면
'Spring > 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술' 카테고리의 다른 글
[ 스프링 DB 접근 기술 ] 스프링 JdbcTemplate (0) | 2023.09.14 |
---|---|
[ 스프링 DB 접근 기술 ] 스프링 통합 테스트 (0) | 2023.09.13 |
[ 스프링 DB 접근 기술 ] H2 데이터베이스 설치 (0) | 2023.09.11 |
[ 회원 관리 예제 - 웹 MVC 개발 ] 회원 조회 (0) | 2023.09.08 |
[ 회원 관리 예제 - 웹 MVC 개발 ] 회원 등록 (0) | 2023.09.08 |