Java Database Connectivity
- 데이터베이스와 연결해서 입출력 지원
- DBMS의 종류와 상관없이 동일하게 사용할 수 있는 클래스와 인터페이스로 구성
➔ 없으면 ClassNotFoundException 발생
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("연결 문자열(접속url)", "사용자", "비밀번호")
ConnectionTest.java
// DB 커넥션은 모듈화해서 쓸거다~!
public class ConnectionTest {
@Test
@DisplayName("jdbc_ex 데이터베이스 접속 (Connection Test)")
public void testConnection() throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.cj.jdbc.Driver"); // 드라이버 연결
// 설정정보 - 하드코딩(비권장) -> 설정 파일로 분리
String url = "jdbc:mysql://127.0.0.1:3306/jdbc_ex"; // 연결문자열(접속url)
String id = "jdbc_ex";
String password = "jdbc_ex";
Connection conn = DriverManager.getConnection(url, id, password);
System.out.println("DB 연결 성공");
conn.close(); // DB 연결 종료
}
}
# 키=값 (공백X)
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/jdbc_ex
id=jdbc_ex
password=jdbc_exJDBCUtil.java
// DB 모듈
public class JDBCUtil {
static Connection conn = null; // static으로 Connection 객체 준비
static { // conn을 초기화할 코드가 길기 때문에 static 초기화 블럭으로 초기화 진행
try {
Properties properties = new Properties();
properties.load(JDBCUtil.class.getResourceAsStream("/application.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String id = properties.getProperty("id");
String password = properties.getProperty("password");
Class.forName(driver);
conn = DriverManager.getConnection(url, id, password);
} catch (Exception e) {
e.printStackTrace();
}
}
// DB 연결
public static Connection getConnection() {
return conn;
}
// DB 연결 끊기
public static void close() {
try {
if (conn != null) {
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

JDBCUtilTest.java
package org.scoula.jdbc_ex.common; // JDBCUtil과 동일 패키지
class JDBCUtilTest {
@Test
@DisplayName("jdbc_ex에 접속")
void getConnection() throws SQLException {
try (Connection conn = JDBCUtil.getConnection()){
System.out.println("DB 연결 성공쓰~");
} // catch 없음 -> 예외 처리 안하겠다는 뜻 , 자동 닫기를 하기 위해 try문을 쓴 것
}
}
-SQL문 실행 클래스
-Connection 객체를 통해 생성: Statement stmt = conn.createStatement();
SQL 실행 메서드
ResultSet executeQuery(SQL문) : SELECTint executeUpdate(SQL문) : INSERT, UPDATE, DELETEResultSet

getString(), getInt(), getLong(), getDouble(), getDate()-Statement는 단순한 문장은 쉬운데 변수 처리를 해야하는 복잡한 문장에는 부적합 ⇨ PreparedStatement
String sql = "INSERT INTO USERS (ID, PASSWORD, NAME, ROLE)" + "VALUES(?, ?, ?, ?)";PreparedStatment pstmt = conn.prepareStatement(sql);setString(), setInt(), setLong(), setDouble()int count = pstmt.executeUpdate()'String sql = "INSERT INTO USERS (ID, PASSWORD, NAME, ROLE)" + "VALUES('member2', 'member123', '일반회원', 'USER');
int count = stmt.executeUpdate(sql);
// 값을 변수로 대체할 경우
String userid = "member2";
String password = "member123";
String name = "일반회원";
String role = "USER";
String sql = "INSERT INTO USERS (ID, PASSWORD, NAME, ROLE)" + "VALUES('" + userid + "','" + password + "','" + name + "','" + role + "')";
// -> PreparementStatement로 처리
CrudTest.java
// 테스트 케이스는 실행되는 순서가 정해져있지 X
// 순서 지정을 위해 TestMethodOrder 사용
// OrderAnnotion : 넘버링 한 순서대로 실행
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class CrudTest {
Connection conn = JDBCUtil.getConnection();
@AfterAll
static void tearDown() {
JDBCUtil.close();
}
// 테스트 케이스
@Test
@DisplayName("새로운 User 등록")
@Order(1)
public void insertUser() throws SQLException {
String sql = "INSERT INTO USERS (ID, PASSWORD, NAME, ROLE) VALUES (?, ?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) { // DB컴파일
pstmt.setString(1, "scoula"); // 1부터 시작
pstmt.setString(2, "scoula123");
pstmt.setString(3, "스콜라");
pstmt.setString(4, "USER");
int count = pstmt.executeUpdate();
Assertions.assertEquals(1, count); // 1이면 통과, 아니면 예외 발생
}
}
@Test
@DisplayName("User 목록 추출")
@Order(2)
public void selectUser() throws SQLException {
String sql = "SELECT * FROM USERS";
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
) {
while (rs.next()) {
System.out.println(rs.getString("name"));
}
}
}
@Test
@DisplayName("특정 User 검색")
@Order(3)
public void selectUserById() throws SQLException {
String userid = "scoula";
String sql = "SELECT * FROM USERS WHERE ID = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, userid);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
System.out.println(rs.getString("name"));
} else {
throw new SQLException("scoula not found");
}
}
}
}
@Test
@DisplayName("특정 User 수정")
@Order(4)
public void updateUser() throws SQLException {
String userid = "scoula";
String sql = "UPDATE USERS SET NAME = ? WHERE ID = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "스콜라 수정");
pstmt.setString(2, userid);
int count = pstmt.executeUpdate();
Assertions.assertEquals(1, count);
}
}
@Test
@DisplayName("특정 User 삭제")
@Order(5)
public void deleteUser() throws SQLException {
String userid = "scoula";
String sql = "DELETE FROM USERS WHERE ID = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, userid);
int count = pstmt.executeUpdate();
Assertions.assertEquals(1, count);
}
}
}
⇨ 검증 코드는 따로 관리 되어야 함, 테스트 하는 메커니즘도 필요
: 테스트 용이라는 어노테이션 붙음
@DisplayName("테스트이름") : 테스트 구분 제목@Test : 테스트 메서드: 실패하면 예외를 발생시킬지 판정 내림
assertEquals(기대값, 실제값)src/test/java
JUnitTest.java
public class JUnitTest {
@DisplayName("1 + 2 는 3이다") // 메서드별로 이름을 붙여줌
@Test
public void junitTest() {
int a = 1;
int b = 2;
int sum = 3;
Assertions.assertEquals(a + b, sum); // 기대값, 실제값
}
}

- JUnit은 메서드마다 새로운 인스턴스를 만듦
- 공통적인 작업(ex.DB연결) 有 - 시작할 때 한번~ (BeforeAll)
@BeforeAll@BeforeEach@AfterEach@AfterAllJUnitCycleTest.java
public class JUnitCycleTest {
@BeforeAll // 전체 테스트 시작 전 1회 실행, static
static void beforeAll() {
System.out.println("@BeforeAll");
}
@BeforeEach // 테스트케이스 시작 전 마다 실행
public void beforeEach() {
System.out.println("@BeforeEach");
}
@Test // 1번 테스트 케이스
public void test1() {
System.out.println("test 1");
}
@Test // 2번 테스트 케이스
public void test2() {
System.out.println("test 2");
}
@AfterEach // 테스트 케이스 종료 전 마다 실행
public void afterEach() {
System.out.println("@AfterEach");
}
@AfterAll // 전체 테스트를 마치고 종료하기 전 1회, static
static void afterAll() {
System.out.println("@AfterAll");
}
}
CREATE DATABASE jdbc_ex;
CREATE USER 'jdbc_ex'@'%' IDENTIFIED BY 'jdbc_ex';
GRAND ALL PRIVILEGES ON jdbc_ex.* TO 'jdbc_ex'@'%';
FLUSH PRIVILEGES;
build.gradle
dependencies {
implementation 'com.mysql:mysql-connector-j:8.3.0'
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
testCompileOnly 'org.projectlombok:lombok:1.18.30'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.30'
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
test~ : 단위테스트(JUnit)를 위한 설정
흔하게 쓰는 라이브러리이기 때문에 따로 저장~!
: 매번 워크벤치에서 SQL X, Intellij에서 SQL 처리 O
⇨ 프로젝트 단위로 관리되는 정보 sql파일 생성 - DB 연결
데이터 준비
jdbc_ex.sql
USE jdbc_ex;
DROP TABLE IF EXISTS USERS;
CREATE TABLE USERS (
ID VARCHAR(12) NOT NULL PRIMARY KEY,
PASSWORD VARCHAR(12) NOT NULL,
NAME VARCHAR(30) NOT NULL,
ROLE VARCHAR(6) NOT NULL
);
INSERT INTO USERS (ID, PASSWORD, NAME, ROLE)
VALUES('guest', 'guest123', '방문자', 'USER'),
('admin', 'admin123', '관리자', 'ADMIN'),
('member', 'member123', '일반회원', 'USER');
SELECT * FROM USERS;
