티스토리 뷰
목차
1. 환경 세팅
2. JDBC
3. JDBC 핵심 5단계
4. 실습
5. DAO & DTO
6. SOLID 원칙
1. 환경 세팅
맥으로는 처음 해봐서 기록해보고 싶었다! 처음 세팅하는 과정부터 기록해보겠다
- IDE : IntelliJ IDEA 사용
- DB : MySQL + MySQL Workbench 사용
- 빌드 도구 : Maven을 써보았다
- JDBC 드라이버 : mysql-connector-j 사용
1-1. mysql + mysql workbench 설치
- mysql community server - 실제 db 서버
- mysql workbench - db를 gui로 관리하는 툴
두 개를 mysql 사이트에서 다운받으면 된다.
설치 중에 조심할 것! : root 비밀번호 설정 화면이 나오는데, 이건 나중에 db 연결 시 쓸 비번이므로 꼭 기억하기!!!!!
설치 완료 후 mysql workbench 실행하면 mysql connections 아래에 + 버튼 누르고 db를 만들면 된다.
참고 : 3306은 mysql의 포트 번호. java에서 코드 쓸 때 jdbc:mysql://127.0.0.1(내 로컬 ip주소):3306(db 포트번호)/db이름 형식으로 쓰게 된다.

1-2. db랑 테이블 만들기

sql 코드 입력하고 번개 모양 누르면 schemas 탭에 student1 테이블이 만들어진 걸 확인할 수 있다.


1-3. IntelliJ에서 maven 프로젝트 생성

이렇게 생성되면 pom.xml이 뜨게 된다.
이게 뭔가 했었는데 POM : Project Object Model 로, MAVEN프로젝트의 설정 파일이라고 한다. 이 파일 하나에 프로젝트에 필요한 정보들을 담으면 된다고 한다.
- 어떤 라이브러리 필요로 하는지 dependencies 로 정의
1-4. pom.xml에 mysql-connector 의존성 추가
JDBC로 mysql에 연결하려면 mysql jdbc 드라이버가 필요하다. 자바 코드랑 mysql 사이를 연결해주는 역할을 한다.
처음 프로젝트를 만들면 바로 pom.xml 파일이 뜨는데,

여기서 dependencies 를 직접 추가해줘야 한다. 아래 코드는 지피티에게 물어봤다.
<dependencies>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.6.0</version>
</dependency>
</dependencies>
여기서 mysql 버전을 확인하고 싶으면 mysql로 가서 쿼리창에 SELECT VERSION(); 을 치면 된다.

혹시 그래도 아래와 같은 에러가 뜬다면,
종속성 'com.mysql:mysql-connector-j:9.6.0'을(를) 찾을 수 없습니다

여기서 maven 아래 🔄 이 버튼을 눌러주면 해결된다.
mysql-connector 가 잘 다운됐나 확인하려면 위 사진 속 종속성 부분 펼쳐보고, mysql-connector-j가 보여야 한다.

이제 세팅은 된거고, Main.java에서 코드를 짜면 된다!
2. JDBC란
- JAVA DataBase Connectivity : 자바에서 db에 접근할 수 있도록 해주는 표준 api이다.
원래는 db 종류별로 연결 방법이 달라서 mysql용, oracle용 코드를 따로 짜야 했으나, 자바가 jdbc라는 통일된 인터페이스를 만들었다.
따라서 드라이버만 바꾸면 기존 코드 변경 없이 다양한 종류 db와 통신 가능해진다!
java 코드(유지 가능) -> jdbc api -> jdbc 드라이버(얘만 바꾸면) -> db(바뀌어도)
3. jdbc 핵심 5단계
1단계 : 드라이버 로드 : Class.forName()
2단계 : db 연결 : DriverManager.getConnection();
3단계 : sql 실행 : PreparedStatement
4단계 : 결과 처리 : ResultSet
5단계 : 자원 해제 : close() / try-with-resources
1단계 : 드라이버 로드
db의 jdbc 드라이버 클래스를 jvm에 로드한다. 디비랑 자바를 연결시키려 하는 사전준비 느낌이다. mysql 드라이버 쓸거야! 라고 jvm에 등록하는 것.
내 환경에서는 pom.xml에 mysql-connector-j를 추가함으로써 드라이버가 설치+자동 로드까지 해결된거라고 한다.
2단계 : 데이터베이스 연결 : connection
drivermanager가 써놓은 정보를 가지고 db와 연결 맺고, 연결 성공 시 connection 객체가 반환되고 이 객체를 통해 이후의 sql문을 실행하게 된다.
package org.example;
import java.sql.*;
public class Main{
public static void main(String[] args){
//db 연결 설정
//jdbc:mysql:// -> mysql용
//127.0.0.1 -> 내 컴퓨터 로컬 호스트
//3306 -> 포트 번호
//TEST -> 접속할 디비 이름
String url = "jdbc:mysql://127.0.0.1:3306/TEST";
String user = "root";
String password = "초기저장비번";
//connection 객체 선언
Connection conn = null;
try{
//실제 디비 연결 시도
//drivermanager가 url, user, pw 보고 db에 접속
conn = DriverManager.getConnection(url, user, password);
System.out.println("db 연결 성공!");
} catch(SQLException e) {
System.out.println("DB 연결 실패ㅠ");
e.printStackTrace();
}
}
}

3단계 : sql 실행
sql문 실행 시 Statement, PreparedStatement 두 가지가 있는데, 후자를 쓰자!
//? 는 나중에 넣을 자리 표시하는 것
String sql = "INSERT INTO student (dept, stdID, name, talk) VALUES (?, ?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
//?자리에 값 바인딩 - 인덱스 1부터 시작
//no는 auto increment로 설정해놔서 그건 제외하고 놓는다.
pstmt.setString(1, "컴퓨터공학과");// 첫 번째 ? 에 학과
pstmt.setString(2, "2176136");// 두 번째 ? 에 학번
pstmt.setString(3, "박남규");// 세 번째 ? 에 이름
pstmt.setString(4, "셤기간 힘드네오,,,");// 네 번째 ? 에 review
//INSERT 실행
int result = pstmt.executeUpdate();
이런 식으로 쓰는건데, 성능과 보안 면에서 월등히 좋다.
- executeQuery() : SELECT 데이터 조회 시 사용한다. 결과로 ResultSet이 반환되고, rs.next()로 한 행씩 읽어온다.
- executeUpdate() : INSERT, UPDATE, DELETE 데이터 변경 시 사용. 영향받은 행의 수가 숫자로 반환된다.
4단계 : 결과 처리
SELECT 실행 후 ResultSet이 반환되는데, rs.next() 호출 때마다 한 행씩 불러온다.
//select, WHERE로 학번이 일치하는 행만 조회
String sql = "SELECT no, name, talk FROM student WHERE stdID = ?";
//connection으로부터 preparedstatement 객체 생성
//db 서버가 sql문을 미리 컴파일하고, preparedstatement 객체가 컴파일된 sql을 들고 있다.
PreparedStatement pstmt = conn.prepareStatement(sql);
//셀렉트문이므로 executeQuery() 실행
//결과 resultset 객체로 반환
ResultSet rs = pstmt.executeQuery();
if(rs.next()){
int no = rs.getInt("no");
String name = rs.getString("name");
String talk = rs.getString("talk");
System.out.printf("no: %d , 이름: %s , talk: %s \n",
no, name, talk);
}
5단계 : 자원해제(Close)
db연결은 꼭 닫아줘야 한다. 안 닫으면 서버가 터질수도 있다고 한다.
닫는 순서는 열었던 순서 역순으로, ResultSet(결과집합) -> PreparedStatement(컴파일된 sql 들고 있는 객체) -> Connection(java<->db 연결해주는 객체) 순이다.
try-with-resources를 쓰면 블록 벗어날 때 자원이 자동해제되므로 꼭 쓰자!
//try() 괄호 안에 선언된 자원은 자동으로 close() 호출한다
//예외 발생 시에도 자원 안전하게 정리된다.
try(Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while(rs.next()) {
int no = rs.getInt("no");
String name = rs.getString("name");
String talk = rs.getString("talk");
System.out.printf("no: %d , 이름: %s , talk: %s \n",
no, dept, stdID, name, talk);
}
}catch(SQLException e){
e.printStackTrace();
}//try 블록 벗어나면 rs->pstmt->conn 순으로 자동 close()!
4. 실습
전체 코드
package org.example;
import java.sql.*;
public class Main {
public static void main(String[] args) {
//db 연결 설정
//jdbc:mysql:// -> mysql용
//127.0.0.1 -> 내 컴퓨터 로컬 호스트
//3306 -> 포트 번호
//TEST -> 접속할 디비 이름
String url = "jdbc:mysql://127.0.0.1:3306/TEST";
String user = "root";
String password = "mustbedoc1*";
String sql = "INSERT INTO student1 (dept, stdID, name, talk) VALUES (?, ?, ?, ?)";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "컴퓨터공학과");//첫 ?에 학과
pstmt.setString(2, "2176136");//두번째 ?에 학번
pstmt.setString(3, "박남규");//세번째 ? 이름
pstmt.setString(4, "셤기간 힘드네오,,,");//네번째 ? talk
//insert 실행
//executeUpdate() : insert, update, delete 변경 시 사용
//반환값: 영향받은 행 수
int result = pstmt.executeUpdate();
System.out.println(result + "개 행 삽입 성공!");
} catch (SQLException e) {
e.printStackTrace();
}
String selectSql = "SELECT no, name, talk FROM student1 WHERE stdID = ?";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(selectSql)) {
//? 부분에 내가 찾고 싶은 행의 stdID 명시해줘야 한다!
pstmt.setString(1, "2176136"); //첫번째 ?에 해당 학번 바인딩
//위에서 끊어지므로 아래에 try문 한번 . 써서 resultset 객체도 감싸주기
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
int no = rs.getInt("no");
String name = rs.getString("name");
String talk = rs.getString("talk");
System.out.printf("no: %d, 이름: %s, talk: %s \n", no, name, talk);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
자바 코드 실행 결과


5. DAO & DTO 왜 나눌까????
핵심
DTO : 데이터 보관함 : 데이터 담아놓는 곳
DAO : DB 명령어 모음집 : 디비랑 소통할 목적으로 db 관련 명령어들 담아놓는 곳
위의 코드처럼 main()에 데이터 관련, 명령어 관련을 다 넣으면 유지보수에 매우 안좋아진다.
예를 들어 db를 mysql이 아니고 다른 걸로 바꿔야 한다면 main() 전체를 다 뒤져봐야하기 때문이다.
반 드 시 역할을 분리하자. 이는 나중에 소개할 SOLID 원칙의 S- SINGLE RESPONSIBILITY - 단일 책임의 원칙에도 부합하는 얘기이다.
위의 코드를 어떻게 분리할 것인가
- DB 연결만 하기! : DatabaseConnector.java
- DB 명령어만 실행시키기! : StudentDao.java
- 데이터만 담아놓기! : Student(DTO).java
- 위의 것들을 조립만 하기! : StudentTest.java
각자 역할을 딱 하나만 같도록 분리할 것이다.
DTO(Data Transfer Object)
데이터를 담아놓는 곳. getter/setter만 존재한다!
Student.java : 데이터 담음
package org.example;
//데이터를 담아놓고 set하고 외부에서 get할 때만 씀!
public class Student {
private int no;
private String dept;
private String stdID;
private String name;
private String talk;
//기본 생성자
public Student() {}
//넘버는 auto_increment라서 제외하고 생성자 만들자
public Student(String dept, String stdID, String name, String talk) {
this.dept = dept;
this.stdID = stdID;
this.name = name;
this.talk = talk;
}
//getter/setter 만들기
public int getNo() { return no; }
public void setNo(int no) { this.no = no; }
public String getDept() { return dept; }
public void setDept(String dept) { this.dept = dept; }
public String getStdID() { return stdID; }
public void setStdID(String stdID){ this.stdID = stdID; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getTalk() { return talk; }
public void setTalk(String talk) { this.talk = talk; }
}
DAO (Data Access Object)
DB 접근할 때 쓰는 CRUD(Create, Read, Update, Delete) 코드만 모아놓은 클래스.
dto 접근해서 sql 명령문 날리고 결과 받아오는 역할만 한다!
StudentDao.java : db 명령어 모음
package org.example;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
//DB 명령어들 모음. CRUD만 담당!
public class StudentDao {
private final DatabaseConnector connector;
public StudentDao(DatabaseConnector connector) {
this.connector = connector;
}
// INSERT
public void insertStudent(Student student) {
String sql = "INSERT INTO student1 (dept, stdID, name, talk) VALUES (?, ?, ?, ?)";
try (Connection conn = connector.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, student.getDept());
pstmt.setString(2, student.getStdID());
pstmt.setString(3, student.getName());
pstmt.setString(4, student.getTalk());
pstmt.executeUpdate();
System.out.println("삽입 성공!");
} catch (SQLException e) {
e.printStackTrace();
}
}
// SELECT 전체 조회
public List<Student> getAllStudents() {
List<Student> list = new ArrayList<>();
String sql = "SELECT * FROM student1 ORDER BY no ASC";
try (Connection conn = connector.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
Student s = new Student();
s.setNo(rs.getInt("no"));
s.setDept(rs.getString("dept"));
s.setStdID(rs.getString("stdID"));
s.setName(rs.getString("name"));
s.setTalk(rs.getString("talk"));
list.add(s);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}
DatabaseConnector.java : db-java 연결만 관리
package org.example;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
//DB 연결 정보만 담당!
public class DatabaseConnector {
private static final String URL = "jdbc:mysql://127.0.0.1:3306/TEST";
private static final String USER = "root";
private static final String PASS = "내비번";
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASS);
}
}
StudentTest.java : 위의 것들 다 조립해서 실행만 함
package org.example;
import java.util.List;
public class StudentTest {
public static void main(String[] args) {
//DatabaseConnector, StudentDao 조립
//connector 안에는
//URL = "jdbc:mysql://127.0.0.1:3306/TEST"
//USER = "root"
//PASS = "내비번"
//getConnection() 메서드
//이게 다 들어있음
DatabaseConnector connector = new DatabaseConnector();
//dao 객체를 만들 때 connector를 넣어줌. - 의존성 주입!
//일케 하면 dao가 DB에 접근할 때마다 connector한테 연결 받아서 사용한다.
StudentDao dao = new StudentDao(connector);
//INSERT — DTO에 데이터 담아서 DAO에 넘김
//student 객체 안에 데이터 담기
Student student = new Student("컴퓨터공학과", "21761361", "박남규2", "홧탱!!!!");
//dao한테 담은 데이터 student 떠넘기기
dao.insertStudent(student);
// SELECT — 전체 조회 후 출력
//dao야 전체 다 가져와~~
//dao가 db에서 전체 조회 후
//각 행을 student(dto)에 담아서 list로 반환해준다.
List<Student> students = dao.getAllStudents();
//리스트 돌면서 한 명씩 출력 student 객체들이 반환된다.
for (Student s : students) {
System.out.printf("no: %d | 학과: %s | 학번: %s | 이름: %s | talk: %s %n",
s.getNo(), s.getDept(), s.getStdID(), s.getName(), s.getTalk());
}
}
}
중요! : dao 객체 만들 때 connector를 인자로 넣어주게 되고, 이는 의존성을 주입하는 것이다! 이렇게 분리해놓으면 결합도가 낮으니 수정하기 매우 편하다!!! 예) 혹여나 mysql에서 oracle로 바뀔 때에도 dao 건드릴 필요 없이 connector쪽만 수정하면 된다!


6. SOLID 원칙
결국 dao/dto로 나누게 됐던 건, 객체지향의 SOLID원칙을 지키기 위함일 것이다.
| 원칙 | 설명 |
| SRP : Single Responsibility : 단일 책임의 원칙 | 한 클래스는 한 책임만 가져야 함 |
| OCP : Open-Closed : 개방-폐쇄 원칙 |
확장엔 열려있고(open), 수정 때는 기존 코드 건드리지 않도록(closed) |
| LSP : 리스코프 치환 원칙 | 부모 자리에 자식을 넣어도 문제가 없어야 한다 |
| ISP : 인터페이스 분리 원칙 | 인터페이스 작게 쪼개야 한다 |
| DIP : Dependency Injection : 의존성 역전 원칙 |
구현체가 아닌 인터페이스에 의존해야 한다. |
이 중 가장 와닿았던 건 역시 SRP 단일 책임의 원칙이다.
main()에 다 넣었을 땐 db 연결 바꾸려고 해도 main()을 다 읽어봐야 하고, insert문, update문 추가하려고 해도 main()을 다 읽어봐야 한다.
그러나 dao(명령어 모음), dto(데이터 모음), connector(db 연결) 이렇게 나눴을 때는 db 연결 바꿀 땐 connector만 보고, insert 명령문 변경할 땐 dao만 보고, 데이터를 바꿀 땐 dto만 보면 된다!
'학교 강의 > 데이터베이스' 카테고리의 다른 글
| [db] 데이터 모델링 (0) | 2026.04.21 |
|---|---|
| [데이터베이스] 뷰, 인덱스, dbms 저장프로그램(프로시저, 트리거, 사용자 정의 함수) (0) | 2026.04.11 |
| [데이터베이스] 2. 관계 데이터 모델 (0) | 2026.03.18 |
| [데이터베이스] 1. 데이터베이스 시스템 (0) | 2026.03.07 |
| [데이터베이스] OT. 데이터베이스 기초 정리 (ERD, 관계형 모델, SQL, JDBC) (0) | 2026.03.07 |
