2021. 12. 11. 02:24ㆍProgramming Languages/Java
JPA를 배우기 전에 간략하게 이런 게 있고 동작 방식, 여러 문제 때문에 JPA가 나오게 되었다는 것 정도만 알고 넘어가서 오랜만에 다시 복습할 겸 글을 작성한다. 주제에 앞서서 JDBC에 대해 간략히 소개하고 가도록 하자.
JDBC
JDBC(Java Database Connectivity)는 위키백과의 설명을 빌리자면 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API이다. JDBC를 사용하면 코드 상에서 DB에 접속한 다음 각종 쿼리를 사용할 수 있게 된다.
JDBC의 실행 사이클
- JDBC 드라이버를 메모리에 로딩한다.
- DB와 연결한다.
- DB에 쿼리를 수행한다.
- DB와의 연결을 종료한다.
JDBC 드라이버 로딩
드라이버는 DB 벤더마다 다르다. 따라서 각 벤더의 홈페이지에서 다운로드해야 한다. 또는 Maven이나 Gradle과 같은 빌드 툴을 사용하면 의존성을 추가하여 사용할 수 있다.
MySQL 드라이버
구버전 - com.mysql.jdbc.Driver
최신 버전 - com.mysql.cj.jdbc.Driver
드라이버 로딩 코드
Class.forName("com.mysql.cj.jdbc.Driver");
Class.forName은 파라미터로 받은 클래스를 바탕으로 JVM에 클래스 객체를 생성하는 메서드이다. 클래스 객체는 JVM에 딱 하나만 생성되고 이후에는 생성되지 않는다. 이에 대해서는 이번 글에서 다루지 않는다. 궁금하신 분들은 Java의 클래스 로딩 과정에 관련하여 검색하시면 되겠다. JDBC는 이정도로 소개하고 본론을 시작하자. 기본적으로 Extension Pack for Java를 설치했다고 가정한다.
메이븐 프로젝트 생성
위 확장을 설치했다면 왼쪽 탐색기 아래에 Maven 탭이 보인다. 여기서 + 아이콘을 클릭한다.
그리고 maven-archetype-quickstart로 설치한다. 이는 junit 외에 아무것도 없는 기초적인 메이븐 프로젝트를 생성한다.
이건 자바 버전을 의미하는데 나중에 수정할 것이므로 아무거나 해도 상관없다.
groupId와 artifactId를 정하고 프로젝트를 생성한다.
프로젝트를 생성하고 나면 pom.xml을 열고 자바 버전을 11로 설정한다.
이제 MySQL 드라이버의 의존성을 추가하자. MavenRepository에 접속한 뒤 mysql jdbc로 검색한다. 그리고 맨 위에 있는 MySQL Connector/J를 선택한다.
그러면 여러 버전들이 나오는데 우리는 최신 버전을 사용한다. 8.0.27을 클릭하자.
그리고 Maven 탭을 클릭하고 아래 코드를 클릭하면 자동으로 copy된다. 이제 pom.xml에 paste하자.
아마 오른쪽 아래에 동기화하느냐는 메시지가 뜰텐데 항상 자동으로 동기화하는 Always로 하거나 아니면 현재 수정사항만 반영하는 Now를 선택하자. 필자는 계속 Now가 뜨는 게 귀찮아서 Always로 설정했다. 동기화가 끝나면 아래와 같이 끌어온 라이브러리를 볼 수 있다.
우리가 등록할 MySQL 드라이버는 다음에 위치해있다. 한 번 쯤 확인해보자.
이제 코드를 작성해서 DB와 연결하고 쿼리를 해보자. 참고로 필자는 미리 MySQL에서 jdbcexam이라는 DB를 생성하고 department 라는 테이블을 생성해놓았다. 테이블 생성 쿼리는 다음과 같다.
CREATE TABLE department (
id bigint PRIMARY KEY NOT NULL AUTO_INCRMENT,
name varchar(255)
);
package com.example;
import java.sql.*;
public class App {
private final static String[] names = { "frontend", "backend", "devops", "designer", "marketer" };
public static void main(String[] args) {
Connection conn = null;
ResultSet rs = null;
PreparedStatement insertPstm = null;
Statement selectPstm = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// jdbc:mysql://IP:PORT/DBNAME
String url = "jdbc:mysql://localhost:3306/jdbcexam";
// getConnection(url, username, password)
conn = DriverManager.getConnection(url, DatabaseInfo.USER.getInfo(), DatabaseInfo.PASSWORD.getInfo());
System.out.println("DB 연결 성공");
} catch (SQLException e) {
System.out.println("DB 연결 실패");
System.err.println(e);
} catch (ClassNotFoundException e) {
System.out.println("드라이버 로딩 실패");
System.err.println(e);
}
try {
String sql = "insert into department(name) values (?)";
insertPstm = conn.prepareStatement(sql);
for (String name : names) {
insertPstm.setString(1, name);
insertPstm.executeUpdate();
}
sql = "select * from department";
selectPstm = conn.createStatement();
rs = selectPstm.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getString("id") + ": " + rs.getString("name"));
}
// String sql = "delete from department";
// Statement stm = conn.createStatement();
// stm.executeUpdate(sql);
System.out.println("쿼리 성공");
} catch (SQLException e) {
System.out.println("쿼리 실패");
System.err.println(e);
} finally {
try {
if (rs != null) {
rs.close();
}
if (insertPstm != null) {
insertPstm.close();
}
if (selectPstm != null) {
selectPstm.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
위와 같이 작성한 후 Run 하면 정상적으로 수행되며 다음과 같이 메시지가 출력될 것이다.
Statement vs PreparedStatement
둘의 차이의 핵심은 캐시 여부이다. Statement는 해당 SQL을 수행할 때마다 컴파일하여 해석한 뒤 쿼리를 수행한다. 만약 해당 SQL을 반복적으로 사용한다면 매번 컴파일하는 것은 성능에 악영향을 끼친다. PreparedStatement는 SQL을 처음에 컴파일 해놓은 뒤 캐시해놓고 해당 쿼리를 재사용한다. 또한 Statement는 파라미터를 지정할 수 없지만 PreparedStatement는 파라미터를 지정할 수 있어 동적 쿼리에도 유용하다. 따라서 대부분의 경우에는 PreparedStatement를 사용하는 편이 낫다. 딱 한 번만 수행하는 경우에는 Statement를 사용해도 무방하다.
executeQuery() vs executeUpdate()
- executeQuery() - 반환값이 있는 경우 사용한다. ResultSet을 반환한다. select 쿼리에서 주로 사용한다.
- executeUpdate() - 반환값이 없는 경우 사용한다. update, insert, delete와 같은 경우 주로 사용한다.
'Programming Languages > Java' 카테고리의 다른 글
[Java] 인증번호 생성 방법 (0) | 2023.03.28 |
---|---|
[Java] ArrayList의 capacity, size, 그리고 add(int index, E element) (0) | 2023.03.16 |
[Java] 메서드 시그니처 (0) | 2021.12.04 |
[Java] Equals and HashCode (0) | 2021.10.19 |
[Java] Thread (0) | 2021.10.19 |