프로세스와 스레드

>>

더보기

프로세스 Process

- 운영체제로부터 자원을 할당받은 작업의 단위로, 실행중인 하나의 프로그램을 의미한다.

- 리소스(resource)와 스레드(thread)로 구성된다.

- Code, Data, Heap, Stack영역으로 이루어지며, 각각의 메모리 공간을 차지한다.

- 동시에 두 개 이상의 프로그램을 특정 기법으로 동시에 실행시키는 기능을 멀티 태스킹(multitasking) 이라 한다. 특정 기법에는 대표적으로 시분할(Time-Shared)기법이 있다.

 

스레드 Thread

- 프로세스 내에서 실행되는 흐름의 단위이다. 즉, 프로세스가 할당 받은 자원을 이용하는 실행 단위(흐름)이다. 

- 스레드는 프로세스 내에 존재하며, 모든 프로세스는 적어도 하나이상의 스레드를 가지고 있다.

- 프로세스는 자신만의 메모리 공간과 자원을 할당받아 사용하지만, 스레드는 다른 스레드와 메모리와 자원을 공유한다.

Code, Data, Heap 영역은 공유하고 별도의 Stack영역만 가지고 있다.

- 둘 이상의 스레드를 가진 프로세스를 멀티 스레드 프로세스(multi-thread process)라 한다.

 

멀티 스레드 

장점

- 시스템의 자원소모가 줄어든다.

- CPU의 사용률을 향상시킨다.

- 프로그램의 응답 시간이 단축된다.

 

단점

- 자원 공유를 위해 전역변수를 이용하므로 동기화 관련된 문제가 발생할 수 있다.

- 잘못된 변수를 사용하거나 미묘한 시간차로 인해 프로그램에 오류가 발생할 수도 있다.

- 디버깅이 어렵다.

스레드 구현 및 실행

>>

더보기

자바 메인 스레드

- 자바는 프로그램(process)이 시작되면 기본적으로 main() 메소드를 진입점(Entry Point)으로 하는 메인 스레드(Main Thread)가 생성되며, 사용자가 정의한 스레드를 생성함으로써 멀티 스레드를 구현할 수 있다.

- main()메소드는 프로그램의 진입점이지 종료점이 아니므로, 멀티 스레드 환경에서는 모든 스레드가 종료되야 프로세스가 종료된다.

 

java.lang.Thread 클래스

- 스레드 생성 및 시작, 관리를 위한 클래스이다.

- Thread 클래스를 상속 받은 하위 클래스에서 run() 메소드를 재정의하여 스레드를 구현한다.

 

java.lang.Runnable 인터페이스

- 스레드에서 실행할 코드를 가지는 run() 메소드가 선언되어 있다.

- 자바는 단일 상속만 구현 가능하므로 스레드를 구현할 클래스가 다른 클래스를 상속 받은 경우 Runnable 인터페이스를 구현한다.

- Runnable 인터페이스를 implements 한 클래스는 run() 메소드를 재정의하여 스레드를 구현한다.

 

스레드 시작

- 스레드를 실행하기 위해서는 Thread 클래스의 start() 메소드를 호출하면 스레드를 시작한다. start() 메소드에 의해 스레드가 시작되면, 자바 가상 머신은 이 스레드의 run() 메소드를 호출한다.

- 스레드 시작 방법

 1) Thread 클래스를 상속받는 하위 클래스 만든 경우 : 해당 클래스의 객체를 생성한 후 Thread 클래스의 start() 메소드를 호출한다.

 2) Runnable 인터페이스를 구현하여 클래스를 만든 경우 : Thread(Runnable target) 생성자에 Runnable 인터페이스 구현 클래스 객체를 인수로 넘겨 Thread 클래스의 객체를 생성하여 Thread 클래스의 start() 메소드를 호출한다.

 

스레드 종료

- 스레드의 종료는 run() 메소드가 종료되는 시점이다.

- Thread 클래스의 stop() 메소드를 이용하여 강제로 스레드를 종료할 수 있지만 사용을 권장하지 않는다.

스레드 예제

Ex001_Thread : Thread 클래스를 이용한 스레드 구현 >>

더보기

 

package threadEx;

public class Ex001_Thread {

	public static void main(String[] args) {
		MyThread1 t = new MyThread1();

		t.start(); // 스레드 시작
		// t.run(); // 유저가 부르면 Tread가 아님.
		
		try {
			for (int i = 1; i <= 10; i++) {
				System.out.println("main -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("main 종료 !!!");
		// main은 프로그램의 시작점이지만 종료점은 아니다.
		// main이 종료되어도 프로그램은 종료되지 않을 수 있다.
		// 프로그램의 종료 시점은 모든 독립스레드가 종료되는 시점이다.
	}
}

// 스레드 구현방법 - 1
//	1) Thread 클래스를 상속 받아 run() 메소드를 override한다.
//	2) Thread 클래스를 상속 받은 클래스의 객체를 생성하여 start() 메소드를 호출한다.
class MyThread1 extends Thread {

	@Override
	public void run() {
		int n = 0;

		try {
			while (n < 20) {
				n++;
				System.out.println(getName() + " -> " + n);

				sleep(500); // 지정 시간(단위:ms)동안 스레드 실행이 일시 중지됨.
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
}

스레드클래스를 상속받아 run() 메소드를 override 해서 클래스의 객체를 생성해서 start()메소드로 멀티 스레드를 구현했다. main 에서도 이미 Thread가 (main() 메소드를 진입점으로 하는 메인 스레드가 존재) 있기 때문에 둘을 비교해보았다.

main()이 종료되어도 프로그램 종료는 모든 독립 스레드가 종료된 후에 일어난다.

Ex002_Runnable : Runnable 인터페이스를 이용한 스레드 구현 >>

더보기
package threadEx;

public class Ex002_Runnable {
	public static void main(String[] args) {
		MyThread2 th = new MyThread2();
		Thread t = new Thread(th);
		t.start();
		
		try {
			for (int i = 1; i <= 10; i++) {
				System.out.println("main -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("main 종료 !!!");
	}
}

// 스레드 구현방법 - 2
//	1) Runnable 인터페이스를 구현하는 클래스를 만들어 run() 메소드를 override 한다.
//	2) Runnable 인터페이스 구현 클래스 객체를 생성한다.
//	3) Thread 클래스를 객체를 생성하며, Thread 객체를 생성할 때 생성자의 인자에 2)번에서 생성한 객체를 넘긴다.
//	4) 
class MyThread2 implements Runnable {

	@Override
	public void run() {
		int n = 0;

		try {
			while (n < 20) {
				n++;
				System.out.println(Thread.currentThread().getName() + " -> " + n);
				Thread.sleep(500);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

Runnable 인터페이스를 구현하는 클래스를 만들어 run() 메소드를 override한 후 Runnable 인터페이스 구현 클래스 객체를 생성한다. Thread 클래스 객체를 생성하여 생성자의 인자에 Runnable 구현 클래스 객체를 넘겨준다.

Ex003_Runnable : 익명 클래스를 이용한 스레드 구현 >> 

더보기
package threadEx;

public class Ex003_Runnable {

	public static void main(String[] args) {
		// 스레드 구현방법 - 3 : 익명 클래스를 이용한 스레드 구현
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					for (int n = 1; n <= 20; n++) {
						System.out.println("스레드 -> " + n);
						Thread.sleep(500);
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

			}
		});

		t.start();

		try {
			for (int i = 1; i <= 10; i++) {
				System.out.println("메인 -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println("메인 종료 !!!");
		
	}

}

익명클래스는 전에 수업시간에 한 번 보고 나서 너무 오랫만에 보는 클래스라 너무 낯설었다.

Ex004_Runnable : 람다를 이용한 스레드 구현 >>

더보기
package threadEx;

public class Ex004_Runnable {

	public static void main(String[] args) {
		// 스레드 구현 방법 - 4 : 람다를 이용한 스레드 구현
		Thread t = new Thread( () -> {
			try {
				for (int n = 1; n <= 20; n++) {
					System.out.println("스레드 -> " + n);
					Thread.sleep(500);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});

		t.start();

		try {
			for (int i = 1; i <= 10; i++) {
				System.out.println("메인 -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("메인 종료 !!!");

	}

}

람다는 아직 배우지 않았으므로 그냥 이렇게 구현할 수 있구나~ 정도만 알면 된다고 하셨다.

 

모델링의 정의

- 현실 세계의 정보들을 컴퓨터에 표현하기 위해서 단순화, 추상화 하여 체계적으로 표현한 개념적 모형

- 모델이라고 하는 것은 모형, 축소형의 의미로서 살아가면서 나타날 수 있는 다양한 현상에 대해서 일정한 표기법에 의해 표현해 놓은 모형

- 사람이 살아가면서 나타날 수 있는 다양한 현상은 사람, 사물, 개념 등에 의해 발생된다고 할 수 있으며, 모델링은 이것을 표기법에 의해 규칙을 가지고 표기하는 것 자체

- 정보시스템 구축에서는 모델링을 계획, 분석, 설계 할 때 업무를 분석하고 설계하는데 이용하고 이후 구축, 운영단계에서는 변경과 관리의 목적으로 이용

 

모델링의 특징

- 추상화

  1) 추상화(모형화, 가설적)는 현실세계를 일정한 형식에 맞추어 표현을 한다는 의미

  2) 다양한 현상을 일정한 양식인 표기법에 의해 표현한다는 것

- 단순화 : 복잡한 현실세계를 약속된 규약에 의해 제한된 표기법이나 언어로 표현하여 쉽게 이해할 수 있도록 하는 개념

- 명확화 : 누구나 이해하기 쉽게 하기 위해 대상에 대한 애매모호함을 제거하여 정확하게 현상을 기술하는 것


데이터 모델의 개념

- 현실 세계를 데이터베이스에 표현하는 중간 과정, 즉 데이터베이스 설계과정에서 데이터 구조를 표현하기 위해 사용되는 도구

- 현실 세계의 데이터 구조를 컴퓨터 세계의 데이터 구조로 기술하는 개념적인 도구

- 단순화, 추상화를 제공하기 위해 사용

- 데이터베이스의 구조를 묘사하기 위해 사용되는 개념들의 집합

- 데이터베이스의 구조는 데이터의 타입, 데이터간의 관계, 데이터를 유지하기 위해 필요한 제약들을 의미

 

개념적 데이터의 모델링

- 처음 현실세계에서 추상화 수준이 높은 상위 수준을 형상화하기 위해 개념적 데이터 모델링을 전개

- 추상화 수준이 높고 업무중심적이고 포괄적인 수준의 모델링을 진행한다.

- 속성들로 기술된 개체 타입과 이 개체 타입들 간의 관계를 이용하여 현실 세계를 표현하는 방법

- 요구사항을 수집하고 분석한 결과를 토대로 업무의 핵심적인 개념을 구분하고 전체적인 뼈대를 만드는 과정

- 개체(entity)를 추출하고 각 개체들 간의 관계를 정의하여 E-R 다이어그램을 만드는 과정까지를 말함

 

논리적 모델링 과정

- 개념적 모델링에서 추출하지 않았던 상세 속성들을 모두 추출함

- 정규화 수행

- 데이터 표준화 수행

 

물리적 모델의 개념

- 데이터베이스 저장구조에 따른 테이블스페이스 등을 고려한 방식을 물리적인 데이터 모델링이라고 함

- 레코드의 형식, 순서, 접근 경로와 같은 정보를 사용하여 데이터가 컴퓨터에 저장되는 방법을 묘사

- 작성된 논리적 모델을 실제 컴퓨터의 저장 장치에 저장하기 위한 물리적 구조를 정의하고 구현하는 과정

- DBMS의 특성에 맞게 저장 구조를 정의해야 데이터베이스가 최적의 성능을 낼 수 있음.

- 물리적 모델링 시 트랜잭션, 저장 공간 설계 측면에서 고려할 사항

 1) 응답시간을 최소화

 2) 얼마나 많은 트랜잭션을 동시에 발생시킬 수 있는 지 검토

 3) 데이터가 저장될 공간을 효율적으로 배치


데이터베이스 설계

데이터베이스 생명주기

- 요구조건 분석 : 데이터베이스에 저장할 내용을 정하기 위해 사용자 요구사항 분석

- 설계 : 개념적 설계, 논리적 설계, 물리적 설계

- 구현 : 스키마 정의, 데이터베이스 구축

- 운영 : 사용자의 요구에 맞는 서비스 제공

- 감시 및 개선 : 새로운 요구조건 감시 및 성능 향상

 

package metaEx;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;

import db_util.DBConn;

public class MySqlplus {
	public static void main(String[] args) {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String sql, s;
		int n;

		gogo: 
		while (true) {
			try {
				System.out.print("SQL> ");
				sql = "";
				n = 1;
				do {
					s = br.readLine();
					if (s == null || s.equalsIgnoreCase("exit")) {
						DBConn.close();
						System.exit(0);
					}

					s = s.trim();
					sql += s + " ";

					if (sql.trim().length() == 0) {
						continue gogo;
					}
					if (s.lastIndexOf(";") == -1) {
						System.out.print((++n) + " ");
					}
				} while (s.lastIndexOf(";") == -1);

				sql = sql.trim();
				sql = sql.substring(0, sql.lastIndexOf(";"));
				if (sql.length() == 0) {
					continue;
				}
				execute(sql);

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void execute(String sql) {
		Connection conn = DBConn.getConnection();
		Statement stmt = null;
		ResultSet rs = null;
		ResultSetMetaData rsmd = null;

		try {
			stmt = conn.createStatement();
			if (sql.toUpperCase().startsWith("SELECT")) {
				rs = stmt.executeQuery(sql);
				rsmd = rs.getMetaData();

				int cols = rsmd.getColumnCount();
				for (int i = 1; i <= cols; i++) {
					System.out.print(rsmd.getColumnName(i) + "\t");
				}
				System.out.println();

				for (int i = 1; i <= cols; i++) {
					System.out.print("----------");
				}
				System.out.println();

				while (rs.next()) {
					for (int i = 1; i <= cols; i++) {
						System.out.print(rs.getString(i) + "\t");
					}
					System.out.println();
				}
			} else {
				// INSERT, UPDATE, DELETE, CREATE, ALTER, DROP 등
				int result = stmt.executeUpdate(sql);
				if (sql.toUpperCase().startsWith("INSERT")) {
					System.out.println(result + " 행이 추가 되었습니다.");
				} else if (sql.toUpperCase().startsWith("UPDATE")) {
					System.out.println(result + " 행이 수정 되었습니다.");
				} else if (sql.toUpperCase().startsWith("DELETE")) {
					System.out.println(result + " 행이 삭제 되었슨비다.");
				} else {
					System.out.println("쿼리가 실행 되었습니다.");
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}

			if (stmt != null) {
				try {
					stmt.close();
				} catch (Exception e2) {
				}
			}
		}

	}
}

 

메타데이터 ?

- 부가적인 정보로, 컬럼명, 컬럼 타입, 컬럼폭, 등을 의미하여 ResultSet에서 얻어온다.

package metaEx;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

import db_util.DBConn;

public class Ex001_MetaData {

	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		ResultSetMetaData rsmd = null;

		try {
			conn = DBConn.getConnection();

			String sql = "SELECT * FROM score";

			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			rsmd = rs.getMetaData();

			// 컬럼수
			int cols = rsmd.getColumnCount();
			System.out.println("전체 컬럼 수 : " + cols);

			for (int i = 1; i <= cols; i++) {
				System.out.print("컬럼명 : " + rsmd.getColumnName(i) + "\t");
				System.out.print("컬럼타입명 : " + rsmd.getColumnTypeName(i) + "\t");
				System.out.println("컬럼폭 : " + rsmd.getPrecision(i));
			}
			System.out.println();

			// 데이터
			// 테이블의 숫자, 날짜 형등은 문자열로 가져올 수 있다.
			while (rs.next()) {
				for (int i = 1; i <= cols; i++) {
					System.out.print(rs.getString(i) + "\t");
				}
				System.out.println();
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}
			if (pstmt != null) {
				try {
					pstmt.close();
				} catch (Exception e2) {
				}
			}
		}

	}

}


package metaEx;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;

import db_util.DBConn;

public class Ex002_Matadata {

	public static void main(String[] args) {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		Connection conn = DBConn.getConnection();
		Statement stmt = null;
		ResultSet rs = null;
		ResultSetMetaData rsmd = null;

		String sql;

		try {
			System.out.print("쿼리 ? ");
			sql = br.readLine();
			sql = sql.trim();

			if (!sql.toUpperCase().startsWith("SELECT")) {
				System.out.println("SELECT 문만 가능합니다.");
				return;
			}

			stmt = conn.createStatement();
			rs = stmt.executeQuery(sql);
			rsmd = rs.getMetaData();

			int cols = rsmd.getColumnCount();
			for (int i = 1; i <= cols; i++) {
				System.out.print(rsmd.getColumnName(i) + "\t");
			}
			
			System.out.println();
			
			while (rs.next()) {
				for (int i = 1; i <= cols; i++) {
					System.out.print(rs.getString(i) + "\t");
				}
				System.out.println();
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}
			if (stmt != null) {
				try {
					stmt.close();
				} catch (Exception e2) {
				}
			}
		}

	}

}

 

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import db_util.DBConn;

/*
 - 결과 집합 유형
 	TYPE_FORWORD_ONLY : 기본. 순방향(next)만 가능
 	TYPE_SCROLL_SENSITIVE : 순방향, 역방향 가능, 수정 결과 바로 반영
 	TYPE_SCROLL_INSENSITIVE : 순방향, 역방향 가능, 수정 결과 바로 반영 안됨
 	
 - 동시성 유형
 	CONCUR_READ_ONLY : 기본. 읽기만 가능
 	CONCUR_UPDATABLE : 수정도 가능
 	
 */
public class Ex_Scroll {

	public static void main(String[] args) {
		Connection conn = DBConn.getConnection();
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			String sql = " SELECT hak, name, birth, kor, eng, mat FROM score ";
			
			// pstmt = conn.prepareStatement(sql); // 기본으로 순방향(next)만 가능
			
			// 순방향 및 역방향 가능
			pstmt = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, 
					ResultSet.CONCUR_READ_ONLY); 
			
			rs = pstmt.executeQuery();
			
			char ch;
			while(true) {
				do {
					System.out.print("1.처음 2.이전 3.다음 4.마지막 5.종료 => ");
					ch = (char)System.in.read();
					System.in.skip(2); // 엔터 버림
				} while (ch<'1'||ch>'5');
				
				if(ch=='5') {
					break;
				}
				
				switch(ch) {
				case '1':
					if(rs.first())
						System.out.println("처음->"+rs.getString(1)+":"+rs.getString(2));
					break;
				case '2':
					if(rs.previous())
						System.out.println("이전->"+rs.getString(1)+":"+rs.getString(2));
					break;
				case '3':
					if(rs.next())
						System.out.println("다음->"+rs.getString(1)+":"+rs.getString(2));
					break;
				case '4':
					if(rs.last())
						System.out.println("마지막->"+rs.getString(1)+":"+rs.getString(2));
					break;
				}
				
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}
			
			if(pstmt != null) {
				try {
					pstmt.close();
				} catch (Exception e2) {
				}
			}
		}

	}

}

부하를 많이 준다.

 

 

트랜잭션 ? 

- 하나의 논리적인 작업 단위

- 자바에서 INSERT, UPDATE, DELETE 등의 작업을 실행하면 기본적으로 자동 COMMIT

 

실습용 테이블

더보기
CREATE TABLE test1 (
    id VARCHAR2(30) PRIMARY KEY,
    name VARCHAR2(30) NOT NULL
);

CREATE TABLE test2 (
    id VARCHAR2(30) PRIMARY KEY,
    birth VARCHAR2(30) NOT NULL,
    FOREIGN KEY(id) REFERENCES test1(id)
);

CREATE TABLE test3 (
    id VARCHAR2(30) PRIMARY KEY,
    tel VARCHAR2(30) NOT NULL,
    FOREIGN KEY(id) REFERENCES test1(id)
);

SELECT * FROM test1;
SELECT * FROM test2;
SELECT * FROM test3;
package transEx;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import db_util.DBConn;

public class Ex_Transaction {

	public static void main(String[] args) {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		Connection conn = DBConn.getConnection();
		PreparedStatement pstmt = null;
		
		String sql;
		String id, name, birth, tel;
		
		try {
			System.out.print("아이디 ? ");
			id = br.readLine();
			
			System.out.print("이름 ? ");
			name = br.readLine();
			
			System.out.print("생년월일 ? ");
			birth = br.readLine();
			
			// 전화번호를 입력하지 않고 그냥 엔터를 누를경우와 전화번호를 입력했을 때와 비교
			System.out.print("전화번호 ? ");
			tel = br.readLine();
			
			// 트랜잭션이 필요한 부분은 반드시 하나의 try 블록에서 모두 코드를 작성해야 한다.
			
			// 자동으로 COMMIT 되지 않도록 설정
			conn.setAutoCommit(false);
			
			sql = "INSERT INTO test1(id, name) VALUES (?, ?)";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, id);
			pstmt.setString(2, name);
			pstmt.executeUpdate();
			pstmt.close();
			
			sql = "INSERT INTO test2(id, birth) VALUES (?, ?)";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, id);
			pstmt.setString(2, birth);
			pstmt.executeUpdate();
			pstmt.close();
			
			sql = "INSERT INTO test3(id, tel) VALUES (?, ?)";
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, id);
			pstmt.setString(2, tel);
			pstmt.executeUpdate();
			
			// 커밋
			conn.commit();
			
			System.out.println("데이터 추가 성공...");
		} catch (SQLException e) {
			try {
				// 세 개의 테이블 중 하나의 테이블이라도 추가하는 도중에 에러가 발생하면 모두 롤백
				conn.rollback();
			} catch (Exception e2) {
			}
			System.out.println(e.toString());
			System.out.println("데이터 추가 실패...");
		
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (pstmt != null) {
				try {
					pstmt.close();
				} catch (Exception e2) {
				}
			}
			
			try {
				conn.setAutoCommit(true);
			} catch (Exception e2) {
			}
			
			DBConn.close(); // 프로그램 종료 시
			
		}

	}

}

 

conn.setAutoCommit(false)를 통해 트랜잭션이 다 이뤄지고 나서 3개의 테이블에 모두 COMMIT되지 않는 경우에는 데이터가 들어가지 않도록 한다. 또 트랜잭션이 필요한 부분은 반드시 하나의 try 블록에서 모두 코드를 작성해야한다. 예외가 발생했을때는 ROLLBACK을 통해 데이터가 들어가지 않도록 해야한다.

쿼리 실행

- Statement

: 보안에 취약. 실무에서는 거의 사용하지 않는다.

: 필요시 트랜잭션 처리를 자바에서 해야한다.

 

- Prepared Statement 인터페이스

: 전처리된 Statement

: 주어진 SQL문을 미리 전처리해서 저장한다.

: 보안에 유리하다.

: 필요시 트랜잭션 처리를 자바에서 해야한다.

 

- Callable Statement

: 프로시저 실행

: 프로시저에서 트랜잭션을 처리한다.

 

App

더보기
package score3;

public class App {
	public static void main(String[] args) {
		ScoreUI ui = new ScoreUI();
		ui.menu();
	}
}

 

ScoreDAO

더보기
package score3;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public interface ScoreDAO {
	public int insertScore(ScoreDTO dto) throws SQLException;
	public int updateScore(ScoreDTO dto) throws SQLException;
	public int deleteScore(String hak) throws SQLException;
	
	public ScoreDTO readScore(String hak);
	public List<ScoreDTO> listScore();
	public List<ScoreDTO> listScore(String name);
	
	public Map<String, Integer> averageScore();
}

 

ScoreDAOImpl

더보기
package score3;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import db_util.DBConn;
import oracle.jdbc.OracleTypes;

public class ScoreDAOImpl implements ScoreDAO {
	private Connection conn = DBConn.getConnection();
	
	@Override
	public int insertScore(ScoreDTO dto) throws SQLException {
		int result = 0;
		CallableStatement cstmt = null;
		String sql;
		
		// INSERT INTO 테이블명(컬럼, 컬럼) VALUES (값, 값)
		try {
			// 자바에서 프로시저를 호출할 때는 CALL로 실행한다.
			sql = "{ CALL insertScore(?, ?, ?, ?, ?, ?) }";
			
			cstmt = conn.prepareCall(sql);
			
			// ?에 setter를 이용하여 컬럼에 대입할 값을 할당한다.
			cstmt.setString(1, dto.getHak());
			cstmt.setString(2, dto.getName());
			cstmt.setString(3, dto.getBirth());
			cstmt.setInt(4, dto.getKor());
			cstmt.setInt(5, dto.getEng());
			cstmt.setInt(6, dto.getMat());
			
			// 쿼리를 실행한다. 반환 값은 프로시저 실행 여부이다.
			result = cstmt.executeUpdate(); // DML, DDL 실행
			
		} catch (SQLIntegrityConstraintViolationException e) {
			// 기본키 중복, NOT NULL등의 제약 조건 위반에 의한 예외 - 무결성 제약 조건 위반
			// 에러 코드는 오라클 기준이며 마리아디비등은 다를 수 있음
			if(e.getErrorCode()==1) {
				System.out.println("학번 중복 입니다.");
			} else if(e.getErrorCode()==1400) { // NOT NULL 위반
				System.out.println("필수 사항을 입력 하지 않았습니다.");
			} else {
				System.out.println(e.toString());
			}
			throw e; // 예외를 던짐
		} catch (SQLDataException e) {
			// 날짜등의 형식 잘못으로 인한 예외
			if(e.getErrorCode()==1861 || e.getErrorCode()==1840) { 
				System.out.println("날짜 형식이 잘못 되었습니다.");
			} else {
				System.out.println(e.toString());
			}
			throw e;
		} catch (SQLException e) {
			e.printStackTrace();
			throw e;
		} finally {
			if(cstmt != null) {
				try {
					cstmt.close();
				} catch (Exception e2) {
				}
			}
		}
		
		return result;
	}

	@Override
	public int updateScore(ScoreDTO dto) throws SQLException {
		int result = 0;
		CallableStatement cstmt = null;
		String sql;
		
		try {
			sql = "{ CALL updateScore(?,?,?,?,?,?) }";
			
			cstmt = conn.prepareCall(sql);
			
			cstmt.setString(1, dto.getName());
			cstmt.setString(2, dto.getBirth());
			cstmt.setInt(3, dto.getKor());
			cstmt.setInt(4, dto.getEng());
			cstmt.setInt(5, dto.getMat());
			cstmt.setString(6, dto.getHak());
			
			result =cstmt.executeUpdate();
			
		} catch (SQLIntegrityConstraintViolationException e) {
			if(e.getErrorCode()==1400) {
				System.out.println("필수 입력 사항을 입력하지 않았습니다.");
			} else {
				System.out.println(e.toString());
			}
			throw e;
		} catch (SQLDataException e) {
			if(e.getErrorCode()==1840||e.getErrorCode()==1861) {
				System.out.println("날짜 형식이 올바르지 않습니다.");
			} else {
				System.out.println(e.toString());
			}
			throw e;
		} catch (SQLException e) {
			if(e.getErrorCode()==20100) {
				System.out.println("등록된 자료가 아닙니다.");
			} else {
				e.printStackTrace();
			}
			throw e;
		} finally {
			if ( cstmt != null) {
				try {
					cstmt.close();
				} catch (Exception e2) {
				}
			}
		}
		
		return result;
	}

	@Override
	public int deleteScore(String hak) throws SQLException {
		int result = 0;
		CallableStatement cstmt = null;
		String sql;
		
		// DELETE FROM 테이블 WHERE 조건
		try {
			sql = "{ CALL deleteScore(?) }";
			
			cstmt = conn.prepareCall(sql);
			
			cstmt.setString(1, hak);
			
			result = cstmt.executeUpdate();
			
		} catch (SQLException e) {
			if(e.getErrorCode()==20100) {
				System.out.println("등록된 자료가 아닙니다.");
			} else {
				e.printStackTrace();				
			}
			throw e;
		} finally {
			if(cstmt !=null) {
				try {
					cstmt.close();
				} catch (Exception e2) {
				}
			}	
		}
		
		return result;
	}

	@Override
	public ScoreDTO readScore(String hak) {
		ScoreDTO dto = null;
		CallableStatement cstmt = null;
		ResultSet rs = null;
		String sql;
		
		try {
			sql = "{ CALL readScore(?, ?) }";
			cstmt = conn.prepareCall(sql);
			// OUT 파라미터는 파라미터의 타입을 설정한다.
			cstmt.registerOutParameter(1, OracleTypes.CURSOR); 
			// 오라클의 SYS_REFCURSOR
			
			// IN 파라미터 
			cstmt.setString(2, hak);
			
			// 프로시저 실행. 모든 프로시저는 executeUpdate()로 실행
			cstmt.executeUpdate();
			
			// OUT 파라미터 값 넘겨 받기
			rs = (ResultSet) cstmt.getObject(1); 
			// SYS_REFCURSOR는 ResultSet로 반환 받는다.
			
			// 기본키 조건에 만족하는 레코드는 1개 또는 0개
			if(rs.next()) {
				dto = new ScoreDTO();
				
				dto.setHak(rs.getString("hak"));
				dto.setName(rs.getString("name"));
				dto.setBirth(rs.getString("birth"));
				dto.setKor(rs.getInt("kor"));
				dto.setEng(rs.getInt("eng"));
				dto.setMat(rs.getInt("mat"));
				dto.setTot(rs.getInt("tot"));
				dto.setAve(rs.getInt("ave"));
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}
			if(cstmt != null) {
				try {
					cstmt.close();
				} catch (Exception e2) {
				}
			}
		}
		
		return dto;
	}

	@Override
	public List<ScoreDTO> listScore() {
		List<ScoreDTO> list = new ArrayList<ScoreDTO>();
		CallableStatement cstmt = null;
		ResultSet rs = null;
		String sql;
		
		try {
			sql = "{ CALL listScore(?) }";
			cstmt = conn.prepareCall(sql);
			
			cstmt.registerOutParameter(1, OracleTypes.CURSOR);
			
			cstmt.executeUpdate();
			
			rs = (ResultSet) cstmt.getObject(1);
			
			// 테이블의 모든 레코드를 읽어 List에 저장
			while(rs.next()) {
				ScoreDTO dto = new ScoreDTO();
				
				dto.setHak(rs.getString("hak")); // dto.setHak(rs.getString(1));
				dto.setName(rs.getString("name")); // dto.setName(rs.getString(2));
				dto.setBirth(rs.getDate("birth").toString());
				// dto.setBirth(rs.getDate("birth")); // yyyy-mm-dd hh:mi:ss
				dto.setKor(rs.getInt("kor"));
				dto.setEng(rs.getInt("eng"));
				dto.setMat(rs.getInt("mat"));
				dto.setTot(rs.getInt("tot"));
				dto.setAve(rs.getInt("ave"));
				dto.setRank(rs.getInt("rank"));
				
				list.add(dto); // List에 저장
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}
			
			if (cstmt != null) {
				try {
					cstmt.close();
				} catch (Exception e2) {
				}
			}
		}
		
		return list;
	}

	@Override
	public List<ScoreDTO> listScore(String name) {
		List<ScoreDTO> list = new ArrayList<ScoreDTO>();
		CallableStatement cstmt = null;
		ResultSet rs = null;
		String sql;
		
		try {
			sql = " { CALL searchNameScore(?, ?) } ";
			cstmt = conn.prepareCall(sql);
			
			cstmt.registerOutParameter(1, OracleTypes.CURSOR);
			cstmt.setString(2, name);
			
			cstmt.executeUpdate();
			
			rs = (ResultSet) cstmt.getObject(1);
			
			while(rs.next()) {
				ScoreDTO dto = new ScoreDTO();
				dto.setHak(rs.getString("hak"));
				dto.setName(rs.getString("name"));
				dto.setBirth(rs.getDate("birth").toString());
				dto.setKor(rs.getInt("kor"));
				dto.setEng(rs.getInt("eng"));
				dto.setMat(rs.getInt("mat"));
				
				list.add(dto);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}
			
			if (cstmt != null) {
				try {
					cstmt.close();
				} catch (Exception e2) {
				}
			}
		}
		
		return list;
	}

	@Override
	public Map<String, Integer> averageScore() {
		Map<String, Integer> map = new HashMap<String, Integer>();
		CallableStatement cstmt = null;
		String sql;
		
		try {
			sql = " { CALL averageScore(?, ?, ?) } ";
			cstmt = conn.prepareCall(sql);
			
			cstmt.registerOutParameter(1, OracleTypes.INTEGER);
			cstmt.registerOutParameter(2, OracleTypes.INTEGER);
			cstmt.registerOutParameter(3, OracleTypes.INTEGER);
			
			cstmt.executeUpdate();
			
			int kor = cstmt.getInt(1);
			int eng = cstmt.getInt(2);
			int mat = cstmt.getInt(3);
			
			map.put("kor", kor);
			map.put("eng", eng);
			map.put("mat", mat);
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(cstmt != null) {
				try {
					cstmt.close();
				} catch (Exception e2) {
				}
			}
		}
		
		return map;
	}

}

 

ScoreDTO

더보기
package score3;

public class ScoreDTO {
	private String hak;
	private String name;
	private String birth;
	private int kor;
	private int eng;
	private int mat;
	
	private int tot;
	private int ave;
	private int rank;
	
	public String getHak() {
		return hak;
	}
	public void setHak(String hak) {
		this.hak = hak;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getBirth() {
		return birth;
	}
	public void setBirth(String birth) {
		this.birth = birth;
	}
	public int getKor() {
		return kor;
	}
	public void setKor(int kor) {
		this.kor = kor;
	}
	public int getEng() {
		return eng;
	}
	public void setEng(int eng) {
		this.eng = eng;
	}
	public int getMat() {
		return mat;
	}
	public void setMat(int mat) {
		this.mat = mat;
	}
	public int getTot() {
		return tot;
	}
	public void setTot(int tot) {
		this.tot = tot;
	}
	public int getAve() {
		return ave;
	}
	public void setAve(int ave) {
		this.ave = ave;
	}
	public int getRank() {
		return rank;
	}
	public void setRank(int rank) {
		this.rank = rank;
	}
}

 

ScoreUI

더보기
package score3;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;

import db_util.DBConn;

public class ScoreUI {
	private BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	private ScoreDAO dao = new ScoreDAOImpl();
	
	public void menu() {
		int ch;
		
		System.out.println("Callable Statement 예제...");
		
		while(true) {
			try {
				do {
					System.out.print("1.등록 2.수정 3.삭제 4.학번검색 5.이름검색 6.리스트 7.과목별평균 8.종료 => ");
					ch = Integer.parseInt(br.readLine());
				} while(ch < 1 || ch > 8);
				
				if(ch == 8) {
					DBConn.close();
					return;
				}
				
				switch(ch) {
				case 1: insert(); break;
				case 2: update(); break;
				case 3: delete(); break;
				case 4: findByHak(); break;
				case 5: findByName(); break;
				case 6: listAll(); break;
				case 7: average(); break;
				}
				
			} catch (Exception e) {
			}
		}
		
	}
	
	public void insert() {
		System.out.println("\n데이터 등록...");
		
		ScoreDTO dto = new ScoreDTO();
		try {
			System.out.print("학번 ? ");
			dto.setHak(br.readLine());
			
			System.out.print("이름 ? ");
			dto.setName(br.readLine());
			
			System.out.print("생년월일 ? ");
			dto.setBirth(br.readLine());
			
			System.out.print("국어 ? ");
			dto.setKor(Integer.parseInt(br.readLine()));
			
			System.out.print("영어 ? ");
			dto.setEng(Integer.parseInt(br.readLine()));
			
			System.out.print("수학 ? ");
			dto.setMat(Integer.parseInt(br.readLine()));
			
			dao.insertScore(dto);
			System.out.println("데이터 추가 완료...");
		} catch (NumberFormatException e) {
			System.out.println("점수는 숫자만 가능합니다.");
		} catch (Exception e) {
			System.out.println("데이터 등록에 실패 했습니다.");
			// e.printStackTrace();
		}
		System.out.println();
	}
	
	public void update() {
		System.out.println("\n데이터 수정...");
		
		String hak;
		try {
			System.out.print("수정할 학번 ? ");
			hak = br.readLine();
			
			ScoreDTO dto = dao.readScore(hak);
			if(dto == null) {
				System.out.println("등록된 자료가 없습니다.\n");
				return;
			}
			
			System.out.print("수정할 이름 ? ");
			dto.setName(br.readLine());
			
			System.out.print("생년월일 ? ");
			dto.setBirth(br.readLine());
			
			System.out.print("국어 ? ");
			dto.setKor(Integer.parseInt(br.readLine()));
			
			System.out.print("영어 ? ");
			dto.setEng(Integer.parseInt(br.readLine()));
			
			System.out.print("수학 ? ");
			dto.setMat(Integer.parseInt(br.readLine()));
			
			dao.updateScore(dto);
			
			System.out.println("데이터 수정이 완료 되었습니다.");
			
		} catch (NumberFormatException e) {
			System.out.println("점수는 숫자만 가능합니다.");
		} catch (Exception e) {
			System.out.println("데이터 수정에 실패 했습니다.");
			// e.printStackTrace();
		}
		System.out.println();
		
	}
	
	public void delete() {
		System.out.println("\n데이터 삭제...");
		
		String hak;
		try {
			System.out.print("삭제할 학번 ? ");
			hak = br.readLine();
			
			dao.deleteScore(hak);
			
			System.out.println("삭제 완료...\n");
			
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("삭제 실패...\n");
		}
	}
	
	public void findByHak() {
		System.out.println("\n학번 검색...");
		String hak;
		
		try {
			System.out.print("검색할 학번 ? ");
			hak = br.readLine();
			
			ScoreDTO dto = dao.readScore(hak);
			if ( dto == null) {
				System.out.println("등록된 자료가 없습니다.\n");
				return;
			}
			
			System.out.print(dto.getHak()+"\t");
			System.out.print(dto.getName()+"\t");
			System.out.print(dto.getBirth()+"\t");
			System.out.print(dto.getKor()+"\t");
			System.out.print(dto.getEng()+"\t");
			System.out.print(dto.getMat()+"\t");
			System.out.print(dto.getTot()+"\t");
			System.out.println(dto.getAve());
			System.out.println();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void findByName() {
		System.out.println("\n이름 검색...");
		
		String name;
		
		try {
			System.out.print("검색할 이름 ? ");
			name = br.readLine();
			
			List<ScoreDTO> list = dao.listScore(name);
			if(list.size() == 0) {
				System.out.println("등록된 자료가 없습니다.\n");
				return;
			}
			
			for(ScoreDTO dto : list) {
				System.out.print(dto.getHak()+"\t");
				System.out.print(dto.getName()+"\t");
				System.out.print(dto.getBirth()+"\t");
				System.out.print(dto.getKor()+"\t");
				System.out.print(dto.getEng()+"\t");
				System.out.println(dto.getMat());
			}
			System.out.println();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void listAll() {
		System.out.println("\n전체 리스트...");
		
		List<ScoreDTO> list = dao.listScore();
		System.out.println("학번\t이름\t생년월일\t\t국어\t영어\t수학\t총점\t평균\t석차");
		System.out.println("----------------------------------------------------------------------------");
		for(ScoreDTO dto : list) {
			System.out.print(dto.getHak()+"\t");
			System.out.print(dto.getName()+"\t");
			System.out.print(dto.getBirth()+"\t");
			System.out.print(dto.getKor()+"\t");
			System.out.print(dto.getEng()+"\t");
			System.out.print(dto.getMat()+"\t");
			System.out.print(dto.getTot()+"\t");
			System.out.print(dto.getAve()+"\t");
			System.out.println(dto.getRank());
		}
		System.out.println();
	}
	
	public void average() {
		System.out.println("\n과목별 평균 점수");
		
		Map<String, Integer> map = dao.averageScore();
		
		try {
			int kor = map.get("kor");
			int eng = map.get("eng");
			int mat = map.get("mat");
			
			System.out.println("국어:"+kor);
			System.out.println("영어:"+eng);
			System.out.println("수학:"+mat);
			
		} catch (Exception e) {
			
		}
		System.out.println();
		
	}
}

 

프로시저

더보기
-- 프로시저에서 DML(INSERT, UPDATE, DELETE)작업 후 반드시 COMMIT
CREATE OR REPLACE PROCEDURE insertScore
(
    pHak IN score.hak%TYPE,
    pName IN score.name%TYPE,
    pBirth IN score.birth%TYPE,
    pKor IN score.kor%TYPE,
    pEng IN score.eng%TYPE,
    pMat IN score.mat%TYPE
)
IS
BEGIN
    INSERT INTO score(hak,name,birth,kor,eng,mat) VALUES
    (pHak, pName, pBirth, pKor, pEng, pMat);
    COMMIT;
END;
/

SELECT * FROM user_procedures;

EXEC insertScore('5555', '마마마', '2003-03-03', 80, 90, 70);

SELECT * FROM score;

-- 수정 프로시저
CREATE OR REPLACE PROCEDURE updateScore
(
    pName IN score.name%TYPE,
    pBirth IN score.birth%TYPE,
    pKor IN score.kor%TYPE,
    pEng IN score.eng%TYPE,
    pMat IN score.mat%TYPE,
    pHak IN score.hak%TYPE
)
IS
BEGIN
    UPDATE score SET name=pName, birth=pBirth, kor=pKor, eng=pEng,
        mat=pMat WHERE hak=pHak;
        IF SQL%NOTFOUND THEN
            RAISE_APPLICATION_ERROR(-20100, '존재하지 않는 자료입니다.');
        END IF;
        COMMIT;
END;
/

EXEC updateScore('마마마', '2000-10-10', 100, 100, 100, '5555');

SELECT * FROM score;

-- 삭제 프로시저
CREATE OR REPLACE PROCEDURE deleteScore
(
    pHak IN score.hak%TYPE
)
IS
BEGIN
    DELETE FROM score WHERE hak = pHak;
    IF SQL%NOTFOUND THEN
        RAISE_APPLICATION_ERROR(-20100, '존재하지 않는 자료 입니다.');
    END IF;
    COMMIT;
END;
/

EXEC deleteScore('5555');
SELECT * FROM score;

-- 학번 검색 프로시저
CREATE OR REPLACE PROCEDURE readScore
(
    pResult OUT SYS_REFCURSOR,
    pHak IN VARCHAR2
)
IS
BEGIN
    OPEN pResult  FOR
        SELECT hak, name, TO_CHAR(birth, 'YYYY-MM-DD') birth, kor, eng, mat,
            (kor+eng+mat) tot, (kor+eng+mat)/3 ave
        FROM score where hak = pHak;
END;
/

-- 전체 리스트 프로시저
CREATE OR REPLACE PROCEDURE listScore
(
    pResult OUT SYS_REFCURSOR
)
IS
BEGIN
    OPEN pResult FOR
        SELECT hak, name, birth, kor, eng, mat, 
            (kor+eng+mat) tot, (kor+eng+mat)/3 ave,
            RANK() OVER( ORDER BY (kor+eng+mat) DESC ) rank
        FROM score;

END;
/

-- 이름 검색 프로시저
CREATE OR REPLACE PROCEDURE searchNameScore
(
    pResult OUT SYS_REFCURSOR,
    pName IN VARCHAR2
)
IS
BEGIN
    OPEN pResult  FOR
        SELECT hak, name, birth, kor, eng, mat,
            (kor+eng+mat) tot, (kor+eng+mat)/3 ave
        FROM score where INSTR(name, pName) >= 1;
END;
/

-- 각 과목 평균프로시저
CREATE OR REPLACE PROCEDURE averageScore
(
    pKor OUT NUMBER,
    pEng OUT NUMBER,
    pMat OUT NUMBER
)
IS
BEGIN
    SELECT NVL(AVG(kor), 0), NVL(AVG(eng), 0), NVL(AVG(mat), 0)
        INTO pKor, pEng, pMat 
    FROM score;
END;
/

java.sql.Statement 인터페이스

- 정적인 SQL 문을 실행하여 작성된 결과를 돌려주는 객체

- Statement 객체는 Connection의 createStatement() 메소드를 호출하여 얻는다.

 

Statement를 이용한 JDBC프로그램 작성 순서

1) JDBC 드라이버를 로딩한다.

- ORACLE 을 사용하는 경우

Class.forName("oracle.jdbc.driver.OracleDriver");

- MySQL을 사용하는 경우

Class.forName("com.mysql.jdbc.Driver");

 

- 자바 6부터는 JDBC드라이버를 자동으로 로딩하므로 생략 가능하다.

 

2) Connection 객체를 생성한다.

- 오라클의 Connection 객체 생성

String url = "jdbc:oracle:thin:@127.0.0.1:1521:ORCL"; // 11g, ORCL : SID
// String url = "jdbc:oracle:thin:@//127.0.0.1:1521/ORCL"; // 12C 이상
String user = "계정이름";
String pwd = "비밀번호";
Connection conn=DriverManager.getConnection(url, user, pwd);

 

- MySQL의 Connection 객체 생성

String url="jdbc:mysql://127.0.0.1:3306/mydb"; // mydb : 데이터베이스명
String user="계정이름";
String pwd="비밀번호";
Connection conn=DriverManager.getConnection(url, user, pwd);

3) Connection의 createStatement() 메소드를 호출하여 쿼리를 실행할 Statement 객체를 얻는다.

Statement stmt = conn.createStatement();

 

4) 실행할 쿼리를 작성한다.

- INSERT 문의 예

String sql = "INSERT INTO 테이블명(컬럼명, 컬럼명) VALUES (값, 값)";

 

- SELECT 문의 예

String sql = "SELECT 컬럼명, 컬럼명 FROM 테이블명 WHERE 조건";

 

5) 쿼리를 실행한다.

- DML(INSERT, UPDATE, DELETE), DDL 실행

int result = stmt.executeUpdate(sql);

 

- SELECT 문 실행

ResultSet rs = stmt.executeQuery(sql);

 

6) SELECT 문의 경우 next() 메소드를 이용하여 실행된 결과를 읽어 온다.

if(rs.next()) {
	String hak = rs.getString("hak");
    // ...
}

 

7) 리소스를 close 한다.

rs.close(); // SELECT 문을 실행한 경우
stmt.close();
conn.close();

 

예 >>

더보기
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import db_util.DBConn;

public class Ex001_Statement {

	public static void main(String[] args) {
		Connection conn = DBConn.getConnection();
		
		// Statement 인터페이스 쿼리를 실행하는 인터페이스
		Statement stmt = null;
		String sql;
		
		try {
			// 쿼리를 작성할때 쿼리 마지막에 ;를 붙이지 않는다. 
			// 만약에 쿼리에 ;를 붙이면 ORA-00933 에러 발생
			sql = "INSERT INTO score(hak, name, birth, kor, eng, mat) VALUES ( " 
					+ " '1001', '김자바', '2000-10-10', 80, 90, 70) ";
			
			stmt = conn.createStatement();
			
			// executeUpdate() : DDL(CREATE, ALTER, DROP), DML(INSERT, UPDATE, DELETE) 실행
			int result = stmt.executeUpdate(sql);
				// DML을 실행한 경우 쿼리를 실행 후 변경 개수를 반환하고
			    // DDL은 실행 여부를 반환 한다.
			System.out.println(result +" 행이 추가 되었습니다.");
			
			// 이 프로그램은 한번만 실행 할 수 있다.
			// 두번 실행하면 학번이 기본키 이므로 동일한 학번을 추가 할수 없어서
			// ORA-00001(SQLIntegrityConstraintViolationException) 에러 발생
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if(stmt != null) {
				try {
					stmt.close();
				} catch (Exception e2) {
				}
			}
			DBConn.close();
		}
		

	}

}

java.sql.ResultSet 인터페이스

- 데이터베이스 결과 집합을 나타내는 데이터 테이블로, 일반적으로 데이터베이스에 조회하는 문을 실행하여 생성된다.

- ResultSet 객체는 현재 데이터 행을 가리키는 커서를 유지하며, 초기에 커서는 첫 번째 행 앞에 위치한다.

- next() 메소드는 커서를 다음 행으로 이동시키고, ResultSet 객체에 더 이상 행이 없을 때 false를 리턴하므로 while 루프에서 결과 세트를 반복할 수 있다.

- 디폴트의 ResultSet 객체는 갱신이 불가능하며, next() 메소드로 다음 행(순방향)으로만 이동 가능하다.

- 옵션을 이용해 갱신이 가능하며, 스크롤이 가능한 ResultSet객체를 생성할 수 있다.

- ResultSet 객체를 생성한 Statement 객체가 close()되거나 다시 실행되는 경우에는 ResultSet 객체는 자동으로 close() 된다.

- ResultSet 객체는 Statement의 executeQuery(String sql) 메소드, PreparedStatement의 executeQuery() 메소드 등을 이용하여 객체를 얻는다. 

 

예 >>

더보기
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import db_util.DBConn;

public class Ex002_ResultSet {
	public static void main(String[] args) {
		Connection conn = DBConn.getConnection();
		Statement stmt = null;
		ResultSet rs = null;
		String sql;
		
		try {
			stmt = conn.createStatement();
			sql = "SELECT hak hno, name, birth, kor, eng, mat, kor+eng+mat FROM score"
					+ "  WHERE hak = '1001' ";
			
			// executeQuery() : SELECT 문 실행
			// ResultSet : SELECT 문 실행 결과를 가지고 있는 객체. 전부 다 가져옴
			rs = stmt.executeQuery(sql);
			
			// 초기에 커서는 첫번재 행 앞에 위치
			// next() : 커서를 다음 행으로 이동
			if(rs.next()) {
				// String hak = rs.getString("hak"); // 에러
					// 컬럼명에 별명을 주면 반드시 별명으로 가져와야 한다.
				String hak = rs.getString("hno");
				String name = rs.getString("name");
				// String name = rs.getString(2);
				// String birth = rs.getString(3); // 컬럼의 위치로 가져오기(1부터 시작)
					// 날짜는 yyyy-mm-dd hh:mi:ss 로 출력
					// 날짜, 숫자는 String으로 가져 올수 있음
					// 날짜를 원하는 형식으로 가져오기 위해서는 쿼리에서
					// TO_CHAR(birth, 'YYYY-MM-DD') birth
					// 같이 해줘어야 함
					// 날짜는 getDate()로 가져오며, java.sql.Date 형임
				String birth = rs.getDate(3).toString(); // yyyy-mm-dd 로 반환
				int kor = rs.getInt("kor");
				int eng = rs.getInt("eng");
				int mat = rs.getInt(6);
				int tot = rs.getInt(7);
				
				System.out.print(hak + "\t" + name +"\t" + birth +"\t");
				System.out.println(kor + "\t" + eng +"\t" + mat +"\t" + tot);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
				}
			}
			
			if(stmt != null) {
				try {
					stmt.close();
				} catch (Exception e2) {
				}
			}
		}
		
		
	}
}

위 Statement 예시를 실행 후 ResultSet에서 불러온 결과

+ Recent posts