자바/JDBC
JDBC 2편
parkhesse7
2025. 5. 23. 03:23
반응형
저번 JDBC 1편에 이어서 설명을 진행하겠다.
설정 정보들을
properties 정보들로 연결 & CRUD Test
resources 하위에 application.properties 파일을 만들어 담는다.
application.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/jdbc_ex
id=scoula
password=1234

그리고 위 경로에 JDBCUtil.java를 만들어서
JDBCUtil.java
package org.scoula.jdbc_ex.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class JDBCUtil {
static Connection conn = null;
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();
}
}
public static Connection getConnection() {
return conn;
}
public static void close() {
try {
if (conn != null){
conn.close();;
conn=null;
}
} catch(SQLException e){
e.printStackTrace();
}
}
}
ConnectionTest.java
@Test
@DisplayName("jdbc_ex에 접속한다.(자동 닫기)")
public void testConnection2() throws SQLException {
try(Connection conn = JDBCUtil.getConnection()){
System.out.println("DB 연결 성공");
}
}
CrudTest.java
package org.scoula.jdbc_ex.test;
import org.junit.jupiter.api.*;
import org.scoula.jdbc_ex.common.JDBCUtil;
import java.sql.*;
@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)) {
pstmt.setString(1,"scoula");
pstmt.setString(2,"scoula3");
pstmt.setString(3,"스콜라");
pstmt.setString(4,"USER");
int count = pstmt.executeUpdate();
Assertions.assertEquals(1,count);
}
}
@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 stmt = conn.prepareStatement(sql)){
stmt.setString(1,userid);
try(ResultSet rs = stmt.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 stmt = conn.prepareStatement(sql)){
stmt.setString(1,"스콜라 수정");
stmt.setString(2,userid);
int count = stmt.executeUpdate();
Assertions.assertEquals(1,count);
}
}
@Test
@DisplayName("지정한 사용자를 삭제한다")
@Order(5)
public void deleteUser() throws SQLException {
String userid = "scoula";
String sql = "delete from users where id = ?";
try(PreparedStatement stmt = conn.prepareStatement(sql)){
stmt.setString(1,userid);
int count = stmt.executeUpdate();
Assertions.assertEquals(1,count);
}
}
}
VO 패턴
Value Object
특정 테이블의 한 행을 매핑하는 클래스
클래스 정의 -> 테이블
필드들 -> 컬럼들
인스턴스 -> 한 행
package org.scoula.jdbc_ex.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserVO {
private String id;
private String password;
private String name;
private String role;
}
DAO 패턴 적용
Data Access Object
데이터베이스에 접근하여 실질적인 데이터베이스 연동 작업을 담당하는 클래스
인터페이스 정의 후 구현 클래스 작성
package org.scoula.jdbc_ex.dao;
import org.scoula.jdbc_ex.domain.UserVO;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
public interface UserDao {
// 회원 등록
int create(UserVO user) throws SQLException;
//회원 목록 조회
List<UserVO> getList() throws SQLException;
//회원 정보 조회
Optional<UserVO> get(String id) throws SQLException;
//회원 수정
int update(UserVO user)throws SQLException;
// 회원 삭제
int delete(String id) throws SQLException;
}
UserDaoImpl
package org.scoula.jdbc_ex.dao;
import org.scoula.jdbc_ex.common.JDBCUtil;
import org.scoula.jdbc_ex.domain.UserVO;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class UserDaoImpl implements UserDao{
Connection conn = JDBCUtil.getConnection();
//USERS 테이블 관련 SQL 명령어
private String USER_LIST = "select * from users";
private String USER_GET = "select * from users where id = ?";
private String USER_INSERT = "insert into users values(?, ?, ?, ?)";
private String USER_UPDATE = "update users set name = ?, role = ? where id = ?";
private String USER_DELETE = "delete from users where id = ?";
//회원 등록
@Override
public int create(UserVO user) throws SQLException {
try (PreparedStatement stmt = conn.prepareStatement(USER_INSERT)) {
stmt.setString(1, user.getId());
stmt.setString(2,user.getPassword());
stmt.setString(3,user.getName());
stmt.setString(4,user.getRole());
return stmt.executeUpdate();
}
}
private UserVO map(ResultSet rs) throws SQLException {
UserVO user = new UserVO();
user.setId(rs.getString("ID"));
user.setPassword(rs.getString("PASSWORD"));
user.setName(rs.getString("NAME"));
user.setRole(rs.getString("ROLE"));
return user;
}
//회원 목록 조회
@Override
public List<UserVO> getList() throws SQLException {
List<UserVO> userList = new ArrayList<UserVO>();
Connection conn = JDBCUtil.getConnection();
try (PreparedStatement stmt = conn.prepareStatement(USER_LIST);
ResultSet rs = stmt.executeQuery()){
while(rs.next()) {
UserVO user = map(rs);
userList.add(user);
}
}
return userList;
}
//회원 정보 조회
@Override
public Optional<UserVO> get(String id) throws SQLException {
try(PreparedStatement stmt = conn.prepareStatement(USER_GET)) {
stmt.setString(1,id);
try(ResultSet rs = stmt.executeQuery()){
if(rs.next()){
return Optional.of(map(rs));
}
}
}
return Optional.empty();
}
//회원 수정
@Override
public int update(UserVO user) throws SQLException {
Connection conn = JDBCUtil.getConnection();
try (PreparedStatement stmt = conn.prepareStatement(USER_UPDATE)) {
stmt.setString(1,user.getName());
stmt.setString(2,user.getRole());
stmt.setString(3,user.getId());
return stmt.executeUpdate();
}
}
//회원 삭제
@Override
public int delete(String id) throws SQLException {
try(PreparedStatement stmt = conn.prepareStatement(USER_DELETE)){
stmt.setString(1,id);
return stmt.executeUpdate();
}
}
}
UserDaoTest
package org.scoula.jdbc_ex.dao;
import org.junit.jupiter.api.*;
import org.scoula.jdbc_ex.common.JDBCUtil;
import org.scoula.jdbc_ex.domain.UserVO;
import java.sql.SQLException;
import java.util.List;
import java.util.NoSuchElementException;
import static org.junit.jupiter.api.Assertions.*;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class UserDaoTest {
UserDao dao = new UserDaoImpl();
@AfterAll
static void tearDown() {
JDBCUtil.close();
}
@Test
@DisplayName("user를 등록합니다.")
@Order(1)
void create() throws SQLException {
UserVO user = new UserVO("ssamz3","ssamz123","쌤즈","ADMIN");
int count =dao.create(user);
Assertions.assertEquals(1,count);
}
@Test
@DisplayName("UserDao User 목록 추출")
@Order(2)
void getList() throws SQLException {
List<UserVO> list = dao.getList();
for(UserVO vo:list){
System.out.println(vo);
}
}
@Test
@DisplayName("특정 user 1건을 추출합니다.")
@Order(3)
void get() throws SQLException {
UserVO user = dao.get("ssamz3").orElseThrow(NoSuchElementException::new);
Assertions.assertNotNull(user);
}
@Test
@DisplayName("user 정보 수정")
@Order(4)
void update() throws SQLException {
UserVO user = dao.get("ssamz3").orElseThrow();
user.setName("쌤즈3");
int count = dao.update(user);
Assertions.assertEquals(1,count);
}
@Test
@DisplayName("user 정보 삭제")
@Order(5)
void delete() throws SQLException {
int count = dao.delete("ssamz3");
Assertions.assertEquals(1,count);
}
}
PreparedStatement pstmt = conn.prepareStatement(sql);
Statemen stmt = conn.createStatement();
비교
1. pstmt는 stmt에 비해 SQL Injection 방어 잘 됨.

2. pstmt는 DBMS 쪽에서 SQL 구조를 미리 컴파일 해놓고 데이터만 바인딩 하는 형식이라 시간 효율적
UserDAO에서
int를 반환하는 것이 아니고, void로 반환하게 인터페이스를 구현했다면 어떤 Test 메서드로 확인을 했어야 했었을까?
반응형