2023. 2. 5. 14:22ㆍSpring 강의/section6
순수 JDBC
build.gradle에 jdbc, h2 데이터베이스 라이브러리를 추가한다.(옆에 코끼리 모양 뜬 거 눌러서 import 시켜줌)
자바는 db랑 붙으려면 jdbc 드라이버가 꼭 있어야 한다.
또 db에 붙으려면 접속정보를 넣어줘야 한다.
application.properties
이렇게 해두면 스프링부트가 DataSource를 만들어두고 우리는 주입 받아서 쓸 수 있다.
repository - JdbcMemberRepository 클래스를 만들어준다.
JdbcMemberRepository.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
package hello.hellospring2.repository;
import hello.hellospring2.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 {
//db에 붙으려면 DataSource가 필요하다.
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);
//id값 세팅 없이 저장할 때 자동으로 id값 생성시켜주는 옵션
pstmt.setString(1, member.getName());
pstmt.executeUpdate(); //db에 쿼리가 날아간다.
rs = pstmt.getGeneratedKeys(); //RETURN_GENERATED_KEYS와 매칭해서 사용할 수 있다.
// db가 생성해준 키를 반환받을 수 있다.
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);
}
}
|
cs |
이 상태로 실행하면 안 된다.
configuration 해줘야 한다.
SpringConfig.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package hello.hellospring2;
import hello.hellospring2.repository.JdbcMemberRepository;
import hello.hellospring2.repository.MemberRepository;
import hello.hellospring2.repository.MemoryMemberRepository;
import hello.hellospring2.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
//스프링이 뜰 때 @Configuration 읽고 @Bean을 보고 인식해서 memberService()와 memberRepository()를 스프링 빈에 등록하고 // 스프링 빈으로 등록되어 있는 memberRepository를 MemberService에 넣어준다.
public class SpringConfig {
private DataSource dataSource;
//스프링이 application.properties를 보고 db와 연결할 수 있는 정보가 있는 dataSource를 만들어준다.
@Autowired
public SpringConfig(DataSource dataSource){ //스프링이 만들어준 dataSource를 주입해준다
this.dataSource = dataSource;
}
@Bean
public MemberService memberService(){
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository(){
//return new MemoryMemberRepository();
return new JdbcMemberRepository(dataSource);
}
}
|
cs |
여기까지 하고 실행해보자.
여기서 회원 목록으로 들어가면 db에서 저장했던 rm이 나와야 한다.
그런데 오류 발생 : org.h2.jdbc.JdbcSQLInvalidAuthorizationSpecException: Wrong user name or password [28000-214]
스프링부트 2.4부터는 `spring.datasource.username=sa`를 꼭 추가해주어야 한다.
그렇지 않으면 `Wrong user name or password` 오류가 발생한다.
application.properties에 3번줄을 추가하면 된다.
다시 회원목록에 들어가면 rm을 확인할 수 있다.
회원가입을 해서 db에 있는지도 확인해보자.
이 정보가 h2 데이터베이스에도 있으면 성공
성공!
스프링을 왜 쓸까?
객체 지향적인 설계가 좋은 이유는 다형성을 활용하기 때문이다.
인터페이스를 두고 구현체를 바꿔쓸 수 있는데 스프링은 이를 굉장히 편리하게 할 수 있도록
스프링 컨테이너가 지원해준다.
구현체를 바꾸면서도 기존 코드를 변경하지 않아도 된다.