2024. 12. 11. 10:37ㆍ데이터 분석/데이터 베이스 프로그래밍
1. JDBC의 개념
JDBC(Java Database Connectivity)는 Java 프로그램과 데이터베이스 간의 연결을 제공하는 표준 API입니다.
- 데이터베이스와 독립적으로 설계되어, 다양한 DBMS(MySQL, Oracle, MS SQL 등)에서 동일한 코드로 데이터베이스 작업이 가능합니다.
- 데이터베이스와 상호 작용하기 위해 JDBC 드라이버와 JDBC API를 사용합니다(Lecture7-JDBC Programmi…).
2. JDBC의 구성요소
JDBC는 데이터베이스 연결과 작업을 지원하기 위해 다양한 인터페이스와 클래스를 제공합니다.
구성 요소설명
DriverManager | DBMS 연결을 관리하는 클래스. JDBC 드라이버를 로드하고 연결을 생성합니다. |
Connection | 데이터베이스와의 연결을 나타내는 객체. |
Statement | SQL 문을 실행하기 위한 객체. executeQuery()와 executeUpdate() 메서드를 제공합니다. |
PreparedStatement | 미리 컴파일된 SQL 문을 실행하기 위한 객체. 매개변수를 바인딩하고 보안성을 제공합니다. |
ResultSet | SQL SELECT 질의 결과를 저장하는 객체. |
DatabaseMetaData | 데이터베이스에 대한 메타데이터를 제공하는 인터페이스. |
ResultSetMetaData | ResultSet 객체에 포함된 컬럼 정보와 메타데이터를 제공. |
3. JDBC 사용방법(절차)
JDBC를 통해 데이터베이스와 상호 작용하기 위한 기본 절차는 다음과 같습니다(Lecture7-JDBC Programmi…):
준비 단계
- JDBC 관련 패키지 임포트
import java.sql.*;
2. JDBC 드라이버 로딩 및 등록
Class.forName("oracle.jdbc.driver.OracleDriver");
3. DBMS와의 연결(Connection 획득)
Connection conn = DriverManager.getConnection(url, user, password);
사용 단계
4. SQL 문 실행을 위한 객체 생성
- Statement
Statement stmt = conn.createStatement();
- PreparedStatement
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM EMP WHERE DEPTNO = ?");
pstmt.setInt(1, 10);
5. SQL 문 실행
- SELECT
ResultSet rs = stmt.executeQuery("SELECT * FROM EMP");
- INSERT, UPDATE, DELETE
int result = pstmt.executeUpdate();
6. DBMS 응답 처리
while (rs.next()) {
int empNo = rs.getInt("EMPNO");
String empName = rs.getString("ENAME");
System.out.println("EMPNO: " + empNo + ", ENAME: " + empName);
}
종료 단계
7. 자원 반납
- 반드시 ResultSet, Statement, Connection 순으로 닫아야 합니다..
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
4. Statement와 PreparedStatement의 차이
항목 | Statement | PreparedStatement |
SQL 실행 방식 | SQL 문을 실행할 때마다 컴파일. | SQL 문을 미리 컴파일하여 실행. |
매개변수 지원 | 지원하지 않음. SQL 문에 직접 값을 포함해야 함. | 매개변수(?) 사용 가능. |
보안성 | SQL 인젝션에 취약. | 매개변수 바인딩을 통해 SQL 인젝션 방지 가능. |
성능 | 반복 실행 시 성능이 저하됨. | 동일 SQL 문 반복 실행 시 더 효율적. |
적합한 사용 사례 | 간단한 SQL 문을 한 번만 실행할 때. | 매개변수가 많거나 반복 실행이 필요한 경우. |
예제 코드 | stmt.executeQuery("SELECT * FROM EMP WHERE JOB = 'CLERK'"); |
pstmt.setString(1, "CLERK"); ResultSet rs = pstmt.executeQuery(); |
5. SQL 질의와 DML 실행을 위한 프로그램 코드의 구조 및 내용
SQL 질의 (SELECT) 실행 구조
- JDBC 드라이버 로딩 및 DB 연결.
- Statement 또는 PreparedStatement 객체 생성.
- executeQuery()를 사용해 SELECT 문 실행.
- ResultSet을 통해 결과 데이터 순회.
- 자원 반납.
String query = "SELECT EMPNO, ENAME FROM EMP WHERE DEPTNO = ?";
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setInt(1, 10);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int empNo = rs.getInt("EMPNO");
String empName = rs.getString("ENAME");
System.out.println("EMPNO: " + empNo + ", ENAME: " + empName);
}
DML 실행 (INSERT, UPDATE, DELETE) 구조
- JDBC 드라이버 로딩 및 DB 연결.
- PreparedStatement 객체 생성 및 매개변수 바인딩.
- executeUpdate()를 사용해 DML 실행.
- 영향을 받은 행 수 확인.
- 자원 반납.
String dml = "INSERT INTO EMP (EMPNO, ENAME, JOB, DEPTNO) VALUES (?, ?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(dml);
pstmt.setInt(1, 7950);
pstmt.setString(2, "Tom");
pstmt.setString(3, "Analyst");
pstmt.setInt(4, 20);
int result = pstmt.executeUpdate();
System.out.println("Affected rows: " + result);
구조적 차이
항목 | SQL 질의 (SELECT) | DML 실행 (INSERT, UPDATE, DELETE) |
사용 메서드 | executeQuery() | executeUpdate() |
결과 반환 | ResultSet 객체 (조회된 데이터) | 정수 값 (영향받은 행의 수) |
적용 대상 | 데이터를 읽어오는 SELECT 문 | 데이터를 추가, 수정, 삭제하는 INSERT, UPDATE, DELETE 문 |
DAODTO
1. 계층 구조 (3-Tier Architecture)
애플리케이션을 3개의 계층으로 나누어 각 역할을 분리함:
- Presentation Layer (UI)
- 사용자와 상호작용 (예: JSP, HTML).
- 입력 데이터를 받아 Business Layer로 전달.
- Business Layer (서비스 계층)
- 비즈니스 로직 수행.
- 데이터를 처리하고 DAO를 호출하여 저장하거나 검색.
- Persistence Layer (데이터 계층)
- 데이터 저장소(Database)와 상호작용.
- DAO(Data Access Object)로 데이터 접근을 처리.
2. DAO (Data Access Object)
DAO는 Persistence Layer에서 데이터베이스 접근을 캡슐화하는 패턴.
- 비즈니스 로직과 데이터 접근 로직을 분리하여 유지보수를 쉽게 함.
3. DAO의 구성요소
- DAO Interface
- 데이터 삽입, 검색, 수정, 삭제 메서드를 정의.
- 예: StudentDAO
- DAO Implementation
- Interface를 구현해 데이터베이스 작업 처리.
- 예: StudentDAOImpl
- DTO (Data Transfer Object)
- 데이터를 계층 간 전송하기 위한 객체.
- 예: StudentDTO에 학번, 이름, 학년 등의 정보 저장.
- Data Source
- 데이터가 저장되는 장소 (Database, File System 등).
4. DAO의 장점
- 데이터 저장소 독립성: 데이터베이스 변경 시 영향 최소화.
- 비즈니스 로직 분리: 서비스와 데이터 접근 로직을 구분.
- 재사용성: 데이터 접근 코드를 재활용 가능.
- 유지보수 용이: 한 곳에서 데이터 접근 로직 관리.
간단 예제
StudentDAOImpl (데이터를 가져오는 DAO 클래스):
public class StudentDAOImpl implements StudentDAO {
public List<StudentDTO> getStudentList() {
String query = "SELECT STU_NO, STU_NAME FROM STUDENT";
// 데이터베이스 접근 코드 수행 (생략)
return new ArrayList<>(); // 학생 리스트 반환
}
}
StudentServiceImpl (비즈니스 로직):
public class StudentServiceImpl implements StudentService {
private StudentDAO dao = new StudentDAOImpl();
public List<StudentDTO> getStudents() {
return dao.getStudentList(); // DAO 호출
}
}
JSP (화면 출력):
<c:forEach var="student" items="${studentList}">
${student.stuNo} ${student.stuName} <br>
</c:forEach>
MyBatis
- 구조와 구성요소
- mybatis-config.xml: 설정 파일 (DB 연결, Mapper 설정).
- Mapper XML: SQL과 매핑 정의.
- SqlSession: SQL 실행, 트랜잭션 관리.
- 사용 방법
- mybatis-config.xml에 DB 연결 정보 작성.
- Mapper XML에 SQL 작성.
- SqlSession을 이용해 SQL 실행.
- Mapper XML vs Interface
- XML: 복잡한 동적 SQL 작성에 유리. / SQL ID를 문자열로 참조
- Interface: 코드 간결, 타입 안전. / N:1,1:N 작성 제약
- 병행 사용: XML에서 SQL 작성, Interface에서 메서드 호출.
- SqlSession API
- selectOne, insert, update, delete로 SQL 실행.
- commit, rollback으로 트랜잭션 관리.
- selectOne: 단일 결과 조회.
try (SqlSession session = sqlSessionFactory.openSession()) {
User user = session.selectOne("mapper.UserMapper.getUserById", 1); // ID 1인 사용자 조회
System.out.println("Username: " + user.getUsername());
}
- selectList: 여러 결과 조회.
try (SqlSession session = sqlSessionFactory.openSession()) {
List<User> users = session.selectList("mapper.UserMapper.getAllUsers"); // 모든 사용자 조회
for (User user : users) {
System.out.println("Username: " + user.getUsername());
}
}
- insert: 데이터 삽입.
try (SqlSession session = sqlSessionFactory.openSession()) {
User newUser = new User();
newUser.setUsername("new_user");
newUser.setEmail("new_user@example.com");
int rowsInserted = session.insert("mapper.UserMapper.insertUser", newUser);
System.out.println("Rows inserted: " + rowsInserted);
session.commit(); // 변경 사항 저장
}
- update: 데이터 수정.
try (SqlSession session = sqlSessionFactory.openSession()) {
User existingUser = new User();
existingUser.setId(1); // 수정할 사용자 ID
existingUser.setEmail("updated_email@example.com");
int rowsUpdated = session.update("mapper.UserMapper.updateUser", existingUser);
System.out.println("Rows updated: " + rowsUpdated);
session.commit(); // 변경 사항 저장
}
- delete: 데이터 삭제.
try (SqlSession session = sqlSessionFactory.openSession()) {
int rowsDeleted = session.delete("mapper.UserMapper.deleteUser", 1); // ID 1 삭제
System.out.println("Rows deleted: " + rowsDeleted);
session.commit(); // 변경 사항 저장
}
- commit/rollback: 트랜잭션 관리.
try (SqlSession session = sqlSessionFactory.openSession()) {
try {
// 데이터 삽입
User newUser = new User();
newUser.setUsername("temp_user");
newUser.setEmail("temp_user@example.com");
session.insert("mapper.UserMapper.insertUser", newUser);
// 데이터 수정
User existingUser = new User();
existingUser.setId(1);
existingUser.setEmail("rollback_email@example.com");
session.update("mapper.UserMapper.updateUser", existingUser);
// 트랜잭션 커밋
session.commit();
System.out.println("Transaction committed.");
} catch (Exception e) {
session.rollback(); // 에러 발생 시 롤백
System.err.println("Transaction rolled back due to error.");
e.printStackTrace();
}
}
- Mapper XML 매핑
- Parameter Mapping: SQL에 값 전달.
- Result Mapping: 결과를 객체에 매핑.
- Complex Type/Collection: N:1 (<association>), 1:N (<collection>).
Mapper XML
<mapper namespace="mapper.CommentMapper">
<resultMap id="commentResultMap" type="Comment">
<id column="comment_id" property="commentId" />
<result column="content" property="content" />
<association property="user" javaType="User">
<id column="user_id" property="userId" />
<result column="username" property="username" />
<result column="email" property="email" />
</association>
</resultMap>
<select id="getCommentWithUser" parameterType="int" resultMap="commentResultMap">
SELECT c.comment_id, c.content, u.user_id, u.username, u.email
FROM Comments c JOIN Users u ON c.user_id = u.user_id
WHERE c.comment_id = #{commentId};
</select>
</mapper>
try (SqlSession session = sqlSessionFactory.openSession()) {
CommentMapper mapper = session.getMapper(CommentMapper.class);
// N:1 매핑
Comment commentWithUser = mapper.getCommentWithUser(1);
System.out.println("User: " + commentWithUser.getUser().getUsername());
// 1:N 매핑
Comment commentWithReplies = mapper.getCommentWithReplies(1);
commentWithReplies.getReplies().forEach(reply -> System.out.println("Reply: " + reply.getContent()));
}
Transaction DBCP
1. 트랜잭션의 필요성
트랜잭션(Transaction)은 데이터베이스 작업에서 "All or Nothing" 방식으로 처리되는 논리적 작업 단위입니다. 여러 DML 문장을 묶어 작업 중 오류가 발생하면 모든 변경을 취소(rollback)하고, 성공하면 작업 결과를 확정(commit)합니다.
- 필요성: 데이터 무결성과 안정성을 보장하기 위해, 특히 계좌 이체나 상품 주문 같은 작업에서 중간 오류로 데이터가 불일치하지 않도록 합니다.
- ACID 속성: 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 영속성(Durability)을 만족해야 합니다.
주요 메서드:
- setAutoCommit(boolean autoCommit): Auto-commit 설정/해제.
- commit(): 트랜잭션 완료 및 결과 저장.
- rollback(): 트랜잭션 취소 및 이전 상태로 복구.
conn.setAutoCommit(false); // Auto-commit 해제
try {
// SQL 작업
conn.commit(); // 성공 시 트랜잭션 확정
} catch (SQLException e) {
conn.rollback(); // 실패 시 롤백
} finally {
conn.setAutoCommit(true); // Auto-commit 재설정
}
3. DBCP(Database Connection Pool) 개념
DBCP는 데이터베이스 연결(Connection)을 효율적으로 관리하는 커넥션 풀링(Connection Pooling) 기술입니다.
- 애플리케이션이 필요할 때 DB 연결을 미리 생성된 커넥션 풀(pool)에서 가져와 사용하고, 종료 시 다시 반환합니다.
- 새로운 커넥션을 매번 생성·종료하지 않으므로 시스템 성능이 향상됩니다.
4. DBCP의 필요성
- 성능 향상: DB 연결 생성·종료에 필요한 시간과 자원(CPU, 메모리)을 절약.
- 자원 관리: 커넥션 수를 제한하여 시스템 부하 방지.
- 재사용성: 유휴 상태의 커넥션을 유지해 재사용.
Apache Commons DBCP는 자주 사용하는 라이브러리로, 커넥션 풀을 쉽게 설정하고 관리할 수 있습니다.
DBCP 설정 예제:
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
ds.setUsername("scott");
ds.setPassword("tiger");
ds.setMaxTotal(10); // 최대 커넥션 수 설정
'데이터 분석 > 데이터 베이스 프로그래밍' 카테고리의 다른 글
[주요 문제] Transaction DBCP (0) | 2024.12.10 |
---|---|
JDBC Programming (0) | 2024.11.03 |
[주요 내용] 문제 형식 (0) | 2024.10.20 |