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에서 불러온 결과

java.sql.DriverManager 클래스

- DriverManager JDBC드라이버를 관리하기 위한 기본적인 클래스

- 데이터베이스 드라이버를 선택하고 새로운 데이터베이스 연결을 생성하는 기능을 한다.

- JDBC 4.0 (자바 6) 이상은 classpath 내의 JDBC드라이버가 자동으로 로드 되므로 Class.forName() 메소드를 사용하여 명시적으로 로드 하지 않아도 되지만, JDBC 4.0 미만은 수동으로 JDBC 드라이버를 로딩해야 한다.

 

java.sql.Connection 인터페이스

- 특정 데이터베이스 (DBMS) 와의 연결(session)을 나타내는 객체이다.

- Connection 객체는 쿼리를 실행하는 Statement, PreparedStatement 등의 객체를 생성하거나 COMMIT, ROLLBACK 등의 트랜잭션 처리를 위한 메소드를 제공한다.

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

import java.sql.Connection;
import java.sql.DriverManager;

// Singleton Pattern
public class DBConn {
	private static Connection conn;
	
	private DBConn() {		
	}

	public static Connection getConnection() {
		String url = "jdbc:oracle:thin:@//127.0.0.1:1521/xe"; // 12C 이상
		String user = "유저";
		String pwd = "비밀번호";
		
		if(conn == null) {
			try {
				Class.forName("oracle.jdbc.driver.OracleDriver"); // JDK 7부터 생략 가능
				conn = DriverManager.getConnection(url, user, pwd);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		return conn;
	}

	public static void close() {
		if(conn != null) {
			try {
				if(! conn.isClosed()) {
					conn.close();
				}
			} catch (Exception e) {
			}
		}
		
		conn = null;
		
	}
	
}

오라클과 연동하는 것을 클래스로 짜두면 나중에 클래스만 불러와서 하면되므로 편하다.

직렬화(Serialization)

- 직렬화란 자바 시스템 내부에서 사용되는 객체 또는 데이터를 자바 외부에서도 사용할 수 있도록 바이트(byte)단위로 변환하는 것을 말한다.

- 직렬화가 가능한 자료형 및 객체

  기본형 타입 (boolean, char, byte, short, int, long, float, double)

  Serializable 인터페이스를 구현한 클래스의 객체

  transient가 사용된 멤버변수(null 전송), static 멤버변수, 메소드는 직렬화 대상에서 제외된다.

 

역 직렬화(Deserialization)

- 직렬화된 바이트(byte)단위의 데이터를 다시 원래 데이터로 복원하는 것을 말한다.

 

java.io.Serializable 인터페이스

- 객체를 직렬화하기 위해서는 먼저, 객체를 직렬화가 가능하도록 Serializable 인터페이스를 구현해야 한다.

- 이 인터페이스는 객체 직렬화가 제공되어야 함을 자바 가상 머신에 알려주는 역할을 한다.

- Serializable 인터페이스는 다른 인터페이스와는 달리 구현해야 할 메소드가 없으므로 단지 Serializable 인터페이스만 implements 하면 된다.

- 객체의 직렬화 대상에서 제외되는 것은 멤버 변수가 static으로 선언된 경우, 멤버 변수가 transient로 선언된 경우와 메소드이다.

 

형식

public class 클래스명 implements Serializable {

 // 클래스 정의 부분

}

 

transient

- 직렬화 대상에서 제외할 멤버 변수는 transient 키워드를 사용하여 제외한다.

- transient 키워드가 붙은 멤버 변수가 복원되면, 숫자변수는 0, 객체는 null로 설정된다.

public class 클래스명 implements Serializable {

 접근제어자 자료형 변수1;

 접근제어자 transient 자료형 변수2;

 // 클래스 구현

}

 

SerialVersionUID 필드

- serialVersionUID 는 직렬화에 사용되는 고유 아이디로, 선언하지 않으면 JVM에서 디폴트로 자동생성된다.

  serialVersionUID는 역 직렬화 해서 읽어 들일 때 캐스팅한 클래스의 serialVersionUID와 역직렬화 한 serialVersionUID가 맞는지 확인하기 위해 사용된다.

- 선언하지 않아도 동작하는데 문제는 없지만, JVM에 의한 디폴트 serialVersionUID 계산은 클래스의 세부 사항을 매우 민감하게 반영하기 때문에 컴파일러 구현체에 따라서 달라질 수 있어 역 직렬화(deserialization) 과정에서 예상하지 못한 InvalidClassException을 유발할 수 있다. 

- Java에서는 명시적으로 serialVersionUID를 선언할 것을 적극 권장하고 있다.

- 선언 예

private static final long serialVersionUID = 1L;

 

예시>>

더보기

Main

import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Ex004_transient {
	public static void main(String[] args) {
		UserService ov = new UserService();
		ov.saveFile();
		ov.loadFile();
	}
}

 

Class

// Serializable : 직렬화
// 직렬화에서 제외되는 것 : 메소드, static 변수, transient 변수

class UserDTO implements Serializable { // 바이트로 고쳐서 저장해줌
	private static final long serialVersionUID = 1L; // 같은 클래스인지아닌지 확인용도
	
	private String name;
	private transient String tel; // 직렬화에서 제외됨. 네트워트로 전송이 되지 않음.
	private int age;

	public UserDTO() {
		
	}
	
	public UserDTO(String name, String tel, int age) {
		this.name = name;
		this.tel = tel;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getTel() {
		return tel;
	}

	public void setTel(String tel) {
		this.tel = tel;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

class UserService {
	private String pathname = "object2.txt";
	
	public void loadFile() {
		try( ObjectInputStream ois = new ObjectInputStream(new FileInputStream(pathname))) {
			
			System.out.println("파일 내용...");
			while(true) {
				UserDTO vo = (UserDTO) ois.readObject(); // 역직렬화수행
				System.out.println(vo.getName()+"\t"+vo.getTel()+"\t"+vo.getAge());
			}
			
		} catch (EOFException e) {
			// ObjectInputStream 스트림은 파일의 내용을 더 이상 읽을 수 없으면
			// EOFException 예외가 발생한다. 따라서 EOFException 예외를 catch하고
			// 아무런 코드도 작성하지 않는다. // 안잡으면 터짐
		}catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void saveFile() {
		// ObjectOutputStream : Serializable 인터페이스가 구현되어 있어야 저장가능하다.
		try ( ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(pathname))){

			oos.writeObject(new UserDTO("다자바", "010-0000-0000", 20));
			oos.writeObject(new UserDTO("너자바", "010-1111-0000", 20));
			oos.writeObject(new UserDTO("구자바", "010-2222-0000", 20));
			
			System.out.println("파일 저장 완료...");
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

+ Recent posts