DBMS

[DBMS] DB 연동

shb 2022. 2. 25. 11:53
package com.lec.java.db;

public interface Query {

	//  1. DB 연동을 위한 정보들(상수들)을 정의(세팅)
	// JDBC 드라이버 클래스 정보
	public static final String DRIVER = "com.mysql.cj.jdbc.Driver";  // MySQL 8.x <=
	
	// 연결할 DB url 정보
	public static final String URL = "jdbc:mysql://localhost:3306/mydb111?useSSL=false&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true";
		
	// DB 사용자 정보
	public static final String USER = "myuser111";
	public static final String PASSWORD = "1234";
	
	
	// PreparedStatement 에서 사용될 SQL 문장
	
	public static final String SQL_SELECT_ALL = 
			"SELECT * FROM test_member";

	public static final String SQL_SELECT_BY_NO = 
			"SELECT * FROM test_member WHERE mb_no < ?";
	
	public static final String SQL_INSERT =
			"INSERT INTO test_member VALUES(?, ?, ?)";
	
	public static final String SQL_UPDATE_BIRTHDATE = 
			"UPDATE test_member "
			+ " SET mb_birthdate = ? "
			+ " WHERE mb_no = ?";
	
	public static final String SQL_DELETE_BY_NO = 
			"DELETE FROM test_member "
			+ " WHERE mb_no = ?";
	
	
	
	

} // end Query(I)

JDBC (Java DataBase Connectivity) 사용
 0. 라이브러리(jar) 추가:
  1) 이클립스 프로젝트 폴더에 libs 폴더를 생성
  2) mysql-connector-java-8.0.*.jar 파일을 libs 폴더로 복사
  3) 복사한 라이브러리를 빌드패스에 추가   
     BulidPath - Configure Build Path..
     Libraries 탭에서  [Add JARs..]   ->  위 libs 폴더의 mysql-connector-java-8.0.*.jar 파일 추가
     Order and Export 탭에서  우선순위 Up (권장)

 1. DB 연동을 위한 정보들(상수들)을 정의(세팅)
 2. JDBC 드라이버 클래스를 메모리에 로드
 3. DB와 connection(연결)을 맺음
 4. Statement 인스턴스를 생성 (SQL을 사용하기 위한 인스턴스)
 5. SQL 문장 작성(SELECT, INSERT, UPDATE, DELETE)
 6. SQL 문장을 DB 서버로 전송
 7. SELECT 결과 확인
 8. 리소스 해제

 

er-diagram 만들기
http://ermaster.sourceforge.net/update-site

package com.lec.java.db01;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DB01Main {

	//  1. DB 연동을 위한 정보들(상수들)을 정의(세팅)
	// JDBC 드라이버 클래스 정보
	public static final String DRIVER = "com.mysql.cj.jdbc.Driver";  // MySQL 8.x <=
	
	// 연결할 DB url 정보
	public static final String URL = "jdbc:mysql://localhost:3306/mydb111?useSSL=false&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true";
		
	// DB 사용자 정보
	public static final String USER = "myuser111";
	public static final String PASSWORD = "1234";
	
	public static void main(String[] args) {
		System.out.println("DB 1 : JDBC 프로그래밍");
		
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		try {
			// 2. JDBC 드라이버 클래스를 메모리에 로드
			Class.forName(DRIVER);  // 동적 클래스 로딩
			System.out.println("드라이버 클래스 로딩 성공");
			
			// 3. DB와 connection(연결)을 맺음
			conn = DriverManager.getConnection(URL, USER, PASSWORD);
			System.out.println("DB Connect 성공");
			
			// 4. Statement 인스턴스를 생성 (SQL을 사용하기 위한 인스턴스)
			stmt = conn.createStatement();
			System.out.println("Statement 생성 성공");
						
			//  5. SQL 문장 작성(SELECT, INSERT, UPDATE, DELETE)
			System.out.println();
			String sql_insert = "INSERT INTO test_member VALUES(120, '코만도', now())";
			System.out.println(sql_insert);
			
			//6. SQL 문장 실행 (DML)
			int cnt = stmt.executeUpdate(sql_insert);  // 'DML' 의 경우 executeUpdate() 로 실행
											// 리턴값은 정수(int)
			
			System.out.println(cnt + "개 row(행) 이 INSERT 됨");
			
			
			// 6. SQL 문장 실행 (SELECT)
			System.out.println();
			String sql_select = "SELECT * FROM test_member";
			System.out.println(sql_select);
			
			rs = stmt.executeQuery(sql_select);   // 'SELECT 및 기타 쿼리' 의 경우 executeQuery() 로 실행
											// 리턴값은 ResultSet 객체
			
			// 7. SELECT 결과 확인
			
			// 7-1 컬럼이름으로 받아오기
			/*
			while(rs.next()) {  // next().  레코드 하나 추출하고 true 리턴.  추출할 레코드 없으면 false 리턴
				String no = rs.getString("mb_no");   // getXXX() 에 '컬럼명 혹은 별명' 명시
				String name = rs.getString("mb_name");
				String birthDate = rs.getString("mb_birthdate");
				
				String result = no + "\t | " + name + "\t | " + birthDate;
				System.out.println(result);
			}
			*/
			
			// 컬럼이름 오류시 java.sql.SQLException: Column 'mb_nama' not found.
			
			// 7-2 컬럼 인덱싱으로 받기
			/*
			System.out.println();
			while(rs.next()) {
				String no = rs.getString(1);   // getXXXX() 컬럼인덱스 명시 (1부터 시작)
				String name = rs.getString(2);
				String birthDate = rs.getString(3);
				
				String result = no + "\t | " + name + "\t | " + birthDate;
				System.out.println(result);
			}
			*/
			
			// 7-3 null 처리해주기
			// 가져오는 데이터가 null 값일때 getString 으로 가져오면 null 로 넘어온다.
			/*
			System.out.println();
			while(rs.next()) {
				String no = rs.getString(1);
				String name = rs.getString(2);
				if(name == null) name = "";
				String birthDate = rs.getString(3);
				
				String result = no + "\t | " + name + "\t | " + birthDate;
				System.out.println(result);
			}
			*/
			
			// 7-4 개별적인 타입으로 get 하기
			System.out.println();
			while(rs.next()) {
				int no = rs.getInt("mb_no");
				String name = rs.getString("mb_name");
				if(name == null) name = "";
				
				
				LocalDateTime localDateTime = null;
				localDateTime = rs.getObject("mb_birthdate", LocalDateTime.class);
				
				String birthDate = "";
				if(localDateTime != null) {
					birthDate = localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));
				}
				
				String result = no + "\t | " + name + "\t | " + birthDate;
				System.out.println(result);
			}
			
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			// 8. 리소스 해제
			//  나중에 만들어진 인스턴스들 부터 close 한다
			try {
				if(rs != null) rs.close();
				if(stmt != null) stmt.close();
				if(conn != null) conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			
		}
		
		
		
		System.out.println("프로그램 종료");
		
		
	} // end main()

} // end class DB01Main
package com.lec.java.db02;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

public class DB02Main {

	// 1. Oracle 연동을 위한 정보들(상수들)을 정의(세팅)
	// JDBC 드라이버 클래스 정보
	public static final String DRIVER =
			"oracle.jdbc.driver.OracleDriver";
	// DB 서버 정보
	public static final String URL =
			"jdbc:oracle:thin:@localhost:1521:XE";
	// DB 사용자 계정 정보
	public static final String USER = "scott";
	public static final String PASSWD = "tiger";

	public static final String TBL_NAME = "test_member";
	public static final String COL_LABEL_NO = "mb_no";
	public static final String COL_LABEL_NAME = "mb_name";
	public static final String COL_LABEL_BIRTHDATE = "mb_birthdate";

	public static void main(String[] args) {
		System.out.println("DB 2 - Statement");
		
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;

		// TODO
		
	} // end main()

} // end class DB02Main
package com.lec.java.db03;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.lec.java.db.Query;

// 공통적으로 사용하는 상수들 인터페이스에 담아서 처리.
public class DB03Main implements Query{

	public static void main(String[] args) {
		System.out.println("DB 3 - PreparedStatement");
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		System.out.println(SQL_SELECT_ALL);
		System.out.println(SQL_INSERT);
		System.out.println(SQL_UPDATE_BIRTHDATE);
		System.out.println(SQL_DELETE_BY_NO);
		
		try {
			Class.forName(DRIVER);
			System.out.println("드라이버 클래스 로딩 성공");
			
			conn = DriverManager.getConnection(URL, USER, PASSWORD);
			System.out.println("DB Connection 생성");
			
			// PreparedStatement 생성
			System.out.println();
			System.out.println("INSERT");
			pstmt = conn.prepareStatement(SQL_INSERT);  // <- ?, ?, ?  3개가 있다.
			pstmt.setInt(1, 101);  // 첫번째 ?
			pstmt.setString(2, "헐크");  // 두번째 ?
			pstmt.setString(3, "2000-10-10");  // 세번째 ?
			
			int cnt = 0;
					
			cnt += pstmt.executeUpdate();
			
			pstmt.setInt(1, 103);  // 첫번째 ?
			pstmt.setString(2, "호크아이");  // 두번째 ?
			pstmt.setString(3, "2011-09-30 18:21:50");  // 세번째 ?
			
			cnt += pstmt.executeUpdate();
			
			System.out.println(cnt + "개 행(row) INSERT 성공");
			
			pstmt.close();
			
			// UPDATE
			System.out.println();
			System.out.println("UPDATE");
			pstmt = conn.prepareStatement(SQL_UPDATE_BIRTHDATE);
			pstmt.setString(1, "2021-08-16");
			pstmt.setInt(2, 3);
			
			cnt = pstmt.executeUpdate();
			System.out.println(cnt + "개 행(row) UPDATE 성공");
			
			pstmt.close();
			
			// DELETE
			System.out.println();
			System.out.println("DELETE");
			pstmt = conn.prepareStatement(SQL_DELETE_BY_NO);
			pstmt.setInt(1, 101); 
			cnt = pstmt.executeUpdate();
			System.out.println(cnt + "개 행(row) DEELTE 성공");
			
			// SELECT
			System.out.println();
			System.out.println("SELECT");
			pstmt = conn.prepareStatement(SQL_SELECT_BY_NO);
			pstmt.setInt(1, 7);
			
			rs = pstmt.executeQuery();
			while(rs.next()) {  
				String no = rs.getString("mb_no");
				String name = rs.getString("mb_name");
				String birthDate = rs.getString("mb_birthdate");
				
				String result = no + "\t | " + name + "\t | " + birthDate;
				System.out.println(result);
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if(rs != null) rs.close();
				if(pstmt != null) pstmt.close();
				if(conn != null) conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		

	} // end main()

} // end class DB03Main

 

auto-generated keys 값
    SEQUENCE (ORACLE),  AUTO_INCREMENET (mysql),  IDENTITY (mssql) 등으로
    새로운 레코드 INSERT 시 자동 생성된 key 값 알아내기
 
ex) 새로운 게시글 작성시 첨부파일(들) 도 같이 저장되어야 할때.
    먼저 게시글 이 먼저 INSERT 된뒤 auto-generated key 값을 얻어와서 첨부파일을 저장해야 한다.   

package com.lec.java.db04;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

import com.lec.java.db.Query;

/* auto-generated keys 값
 * 	SEQUENCE (ORACLE),  AUTO_INCREMENET (mysql),  IDENTITY (mssql) 등으로
 *  새로운 레코드 INSERT 시 자동 생성된 key 값 알아내기
 *  
 *  ex) 새로운 게시글 작성시 첨부파일(들) 도 같이 저장되어야 할때.
 *      먼저 게시글 이 먼저 INSERT 된뒤 auto-generated key 값을 얻어와서 첨부파일을 저장해야 한다.    
 */
public class DB04Main implements Query {

	public static void main(String[] args) {
		System.out.println("DB 4 - generated id값");
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		// 자동생성되는 컬럼의 이름(들) 이 담긴 배열 준비 (auto-generated keys 배열)
		String [] generatedCols = {"mb_no"};  
		
		try {
			// Driver 클래스를 메모리에 로딩
			Class.forName(DRIVER);
			System.out.println("드라이버 클래스 로딩 성공");
			
			// DB Connection
			conn = DriverManager.getConnection(URL, USER, PASSWORD);
			System.out.println("DB Connection 성공");
			
			System.out.println("INSERT");
			// Statement 나 PreparedStatement 생성시 두번째 매개변수로 auto-generated keys 배열 넘겨줌
			
			String sql_insert_name = "INSERT INTO test_member(mb_name) VALUES (?)";
			pstmt = conn.prepareStatement(sql_insert_name, generatedCols);
			pstmt.setString(1, "토르");
			int cnt = pstmt.executeUpdate();
			System.out.println(cnt + "개 행(row) INSERt 성공");
			
			// auto-generated key  값 뽑아오기
			rs = pstmt.getGeneratedKeys();
			if(rs.next()) {
				long no = rs.getLong(1);
				System.out.println("Inserted mb_no = " + no);
			}
			
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			// SQL 에러 메세지는 SQLException 에서 확인가능
			System.out.println("SQL 에러: " + e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				if (rs != null) {
					rs.close();
				}
				if (pstmt != null) {
					pstmt.close();
				}
				if (conn != null) {
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		} // end try-catch

	} // end main()

} // end class DB03Main

 

* 트랜잭션 (Transaction)
- 데이터베이스의 '작업'의 단위,  
- '하나의 트랜잭션'은  '일련의 쿼리연산(들)' 로 구성

 - 가령 : A계좌 → B계좌  로의 '송금' 이라는 트랜잭션은 아래 쿼리연산(들)로 구성 된 경우
  ① A계좌에서 인출 쿼리실행
  ② B계좌로 입금 쿼리실행
 - 두 쿼리 연산은 '모두 반영' 되든지  아니면 '전혀 반영되지 않아야 한다'

  트랜잭션 중간에 실패하면 직전까지 성공한 쿼리 결과도 다시 원상 복귀 해야 한다 ( rollback 이라 한다)

* 트랜잭션의 4 특징 (줄여서 ACID 라고 한다) 
  1. 원자성 (Atomicity) : 트랜잭션 연산은 '모두 반영' 되든지 아니면 '전혀 반영되지 않든지' 해야 한다.
  2. 일관성 (Consistency) : 트랜잭션이 성공적으로 완료되면 언제나 일관성 있는 데이터베이스 상태로 변환되어야 한다
  3. 독립성 (Isolation) : 한 트랜잭션이 완료되기 전까지 트랜잭션이 다루는 데이터를 다른 트랜잭션이 데이터를 접근하지 못하도록 해야 한다  
 4. 영속성 (Durability) : 트랜잭션 완료 후에 변경된 내용은 계속 영구적으로 보존되어야 한다.
 
 트랜잭션의 상태
 
             시작
              ↓
            (활동)
        ↙        ↘
   (부분완료) → (실패)
         ↓           ↓
(완료:commit)  (철회:rollback)
 
 
- 기본적으로 JDBC 의 모든 쿼리실행은 auto commit 이다. 
 
* JDBC 에서 트랜잭션 구현하기
  1. Connection 의 auto commit 을 해제  setAutoCommit(false);
  2. 쿼리연산(들) 수행
  3. 정상적으로 완료되면 commit() 실행
  4. 예외 발생등으로 실패 하면 rollback() 실행

 

package com.lec.java.db05;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import com.lec.java.db.Query;
public class DB05Main implements Query {

	public static void main(String[] args) {
		System.out.println("DB 5 - Transaction");
		
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		
		try {
			// OracleDriver 클래스를 메모리에 로딩
			Class.forName(DRIVER);
			System.out.println("드라이버 클래스 로딩 성공");
			
			// DB Connection
			conn = DriverManager.getConnection(URL, USER, PASSWD);
			System.out.println("DB Connection 성공");
			
			// Statement 작성
			stmt = conn.createStatement();
			
			// 1. Connection 의 auto commit 을 해제
			// TODO
			
			// 2. 쿼리연산(들) 수행
			// TODO
			
			// 3. 정상적으로 완료되면 commit() 실행
			// TODO  
			
			
			// 결과는 직접 콘솔에서 확인해보자
						
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			System.out.println("SQL 에러: " + e.getMessage());
			e.printStackTrace();
			
			// 4. 예외 발생등으로 실패 rollback() 실행
			// TODO

		} finally {
			try {
				if (rs != null) {
					rs.close();
				}
				if (stmt != null) {
					stmt.close();
				}
				if (conn != null) {
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		} // end try-catch

	} // end main()

} // end class

'DBMS' 카테고리의 다른 글

[DBMS] Constraint 제약조건  (0) 2022.02.24
[DBMS] View  (0) 2022.02.24
[DBMS] Join, Sub Query  (0) 2022.02.23
[DBMS] AggregateFunction  (0) 2022.02.23
[DBMS] Single-Row Function  (0) 2022.02.23