본문 바로가기

교육 및 세미나/신입사원 교육

9일차(2018.01.15)

Statement

DAO/DTO/VO

DAO (Data Access Object)

데이터에 접근을 목적으로 하는 객체.

리소스를 매우 크게 소모하는 커넥션 객체를 하나만 두고

여러 사용자가 DAO 인터페이스를 사용하여 필요한 데이터에 접근할 수 있도록 한다.

즉, Database 와 연계하여 처리할 프로그램을 규정화 해 둔 클래스를 말한다.

- DTO 객체를 만들어 편집 및 조작을 한다.

- DTO 를 데이터베이스 서버에 저장하기도 하고 DB 서버로부터 레코드를 select 해서

DTO 객체로 변경해 가져오기도 한다.

- insert, update, delete, select 등 데이터 처리를 주 목적으로 한다.

- 필요성

- 모든 데이터베이스를 공통적으로 접속할 수 있는 ODBC 가 나왔지만 완벽하진 못했다.

- 여전히 로우 레벨의 API를 포함하고 있었기 때문에 개발 장벽이 여전히 높았다.

- 이런 이유 때문에 개발자들은 정작 데이터베이스에 들어있는 데이터를 어떻게 이용할 지에 초점을 맞추기 보다

어떻게 데이터베이스에 접속해서 데이터베이스와 교류하는 지에 더 고민하고 집중할 수 밖에 없었다.

- 즉, 데이터를 활용하는 논리적인 고민보다 기술적 고민에 더 많은 신경을 쏟았던 것이다.

- 이러한 이유로 DAO 라는 대안이 나왔다.

- 사용자는 자신이 필요한 Interface를 DAO에 던지고,

DAO는 이 인터페이스를 구현한 객체를 사용자에게 편리하게 사용할 수 있도록 반환해준다.

- DB 에 대한 접근을 DAO 가 담당하도록 하여 데이터베이스 액세스를 DAO에서만 하게되면

다수의 원격 호출을 통한 오버헤드를 V0 나 DTO를 통해 줄일 수 있고 다수의 DB 호출문제를 해결할 수 있다.

- 또한 단순히 읽기만 하는 연산이기 때문에 트랜잭션 간의 오버헤드를 감소할 수 있다.

- 그러나 Persistent Storage 를 너무 밀접하게 결합해서 작성하게 되면

Persistent Storage 를 다시 작성해야 할 경우가 생기는 데 이 경우 유지보수의 문제가 발생할 수 있다.

DTO (Data Transfer Object)

데이터가 포함된 객체를 특정 시스템에서 다른 시스템으로 전달해야 하는 작업을 처리하는 객체.

메소드 호출 횟수를 줄이기 위해 데이터를 담고 있는 객체이다.

즉, 데이터를 하나의 객체로 관리할 목적으로 만들어 둔 클래스의 객체를 말한다.

setter와 getter 메소드를 가지고 직렬화(Serializable)를 구현한다.

- 폼에서 입력된 데이터들은 하나의 DTO 객체로 변환될 수 있다.

- 일반적으로 하나의 데이터베이스 레코드를 저장하며, 레코드와 같은 구조를 가지고 있다.

- 하나의 레코드는 빈즈 클래스 객체 하나로 매핑된다.

※ beans(빈즈) → 개별학습을 통한 정리 필요~!!

VO (Value Object)

Value Object는 관계형 데이터베이스의 레코드에 대응되는 자바 클래스로

형태는 DB 레코드를 구성하는 필드들을 Value Object의 Attribute로 하고

해당 변수에 접근할 수 있는 getter / setter 메소드의 조합으로 형성된 클래스.

특성은 대체로 불변성이고, equals() 메소드로 비교할 경우 객체의 모든 값을 비교해야 한다.

DTO와 유사한 개념이지만, 특정 비지니스 로직만 전달한다는 것으로 이해하는 것이 구분에 용이하다.

즉, 일반적으로 Value Object는 read only 속성을 갖는다.

- Network Traffic 을 줄여 처리 성능을 향상시킬 수 있다.

- 장점으로는 비 서버 측에 해당하는 클라이언트도 네트워크 오버헤드 없이

영속적 데이터에 액세스할 수 있다는 점이다.

- 데이터 전달을 위해 가장 효율적인 방법이지만, 클래스의 선언을 하기 위해서는 많은 코드가 필요하다.

즉, 파일 수가 많아지게 되고 관리도 힘들어지게 도니다는 단점이 있다.

DBConn.java :

싱글톤 패턴을 이용한 Database 연결 객체 생성 전용 클래스

→ DB 연결 과정이 부하가 가장 크기 때문에 한번 연결된 객체를 계속 사용하는 것이 좋다.

/*==========================================================
  2018.01.12
  DBConn.java
  - 싱글톤 패턴을 이용한 Database 연결 객체 생성 전용 클래스
   → DB 연결 과정이 부하가 가장 크기 때문에
      한번 연결된 객체를 계속 사용하는 것이 좋다.
 ===========================================================*/
package com.util;

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

public class DBConn {
	
	private static Connection dbConn;
	//-- 자동으로 null 초기화
	
	public static Connection getConnection() //throws SQLException, ClassNotFoundException
	{
		// try ~ catch 대신 getConnection() 메소드명 뒤에 『throws Exception』 (SQLException, ClassNotFoundException)
		// 을 사용하면 try ~ catch 문을 사용하지 않아도 된다.
		// 단, throws Exception 을 사용할 경우 예외가 발생하게 되면
		// 프로그램 자체가 종료되어 버린다.
		// 하지만, try ~ catch 문을 사용할 경우 프로그램이 종료되는 것은 아니며
		// 연결 실패에 대한 원인 분석을 할 수 있다.
		// 또한, 이 오류가 발생되었을 경우 클라이언트에게 별도의 안내를 할 수도 있게 된다.
		// ex) 공사중
		if(dbConn == null)
		{
			try
			{
				String url ="jdbc:oracle:thin:@172.27.166.18:1521:xe";
				//--IP 주소는 오라클 서버의 주소, 1521은 오라클 Port Number
				//  xe 는 Express Edition을 사용할 경우 명시하게 되는 SID 이지만
				//  Standard Edition 이나 Enterprise Edition 등을 사용할 경우
				//  별도로 부여된 SID 명을 사용해야 한다.
				
				String user = "scott"; //--오라클 사용자 계정 이름
				String pwd = "tiger";  //--오라클 사용자 계정 암호
				
				Class.forName("oracle.jdbc.driver.OracleDriver");
				//-- OracleDriver 클래스에 대한 객체 생성
				
				// DriverManager.getConnection 은 static 클래스 기반이라서 원래는 DriverManager dm = new DriverManager(); 
				// 라고 선언해서 사용해야되는데 DriverManager.getConnection으로 사용한다.
				dbConn = DriverManager.getConnection(url, user, pwd);
				//-- 오라클 서버 실제 연결
				//   갖고있는 인자값은 오라클 주소, 계정명, 패스워드
			}catch (Exception e) // Exception 대신 SQLException, ClassNotFoundException 사용 가능
			{
				System.out.println(e.toString());
				//--오라클 서버 연결 실패 시 오류 메세지 출력 부분
			}
		}
		return dbConn;
	}
	public static Connection getConnection(String url, String user, String pwd)
	{
		if (dbConn == null) 
		{
			try
			{
				Class.forName("oracle.jdbc.driver.OracleDriver");
				dbConn = DriverManager.getConnection(url, user, pwd);
			}catch (Exception e)
			{
				System.out.println(e.toString());
			}
		}
		return dbConn;
	
	}
	public static void close()
	{
		if(dbConn != null)
		{
			try
			{
				if(!dbConn.isClosed()) //--isClosed() 메소드를 통해 연결 상태 확인 // 열려있다면....
					dbConn.close();    //--close() 메소드를 통해 연결 종료
			}catch(Exception e)
			{
				System.out.println(e.toString());
			}
		}
		dbConn = null;
	}
}

MemberDTO.java

/*==========================================
  2018.01.15
  MemberDTO.java
  - 문제에서 요구한 Member 클래스
  - DTO/VO의 개념으로 활용하기 위한 클래스
============================================ */
package com.test;

public class MemberDTO
{
	// 주요 속성 구성
	private String sid, name, tel;

	// getter / setter 구성
	public String getSid() {
		return sid;
	}

	public void setSid(String sid) {
		this.sid = sid;
	}

	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;
	}
	
}

MemberDAO.java

/*========================================
	2018.01.15
	MemberDAO.java
	- 데이터베이스 액션 처리 전용 클래스
========================================== */

package com.test;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import com.util.DBConn;
import com.test.MemberDTO;

public class MemberDAO 
{
	private Connection conn;
	
	// 데이터베이스 연결 → 생성자 형태로 정의
	public MemberDAO() 
	{
		 conn = DBConn.getConnection();
	}
		
	// 회원 정보(데이터) 추가
	public int add(MemberDTO dto) throws SQLException
	{
		int result = 0;
		
		Statement stmt = conn.createStatement();
		String sql = String.format("INSERT INTO TBL_MEMBER(SID, NAME, TEL) VALUES(MEMBERSEQ.NEXTVAL, '%s', '%s')", dto.getName(), dto.getTel());
		result = stmt.executeUpdate(sql);
		
		return result;
	}
	
	// 인원(데이터) 수 확인
	public int count() throws SQLException
	{
		// 결과값 변수 선언
		int result = 0;
		
		// 작업 객체 생성
		Statement stmt = conn.createStatement();
		
		// 쿼리문 준비
		String sql = "SELECT COUNT(*) AS COUNT FROM TBL_MEMBER";
		
		// 쿼리문 실행 → 결과 집합 반환 (ResultSet)
		ResultSet rs = stmt.executeQuery(sql);
		
		if(rs.next())
		//while(rs.next())
		{
			// result = rs.getInt("COUNT"); // 별칭을 꼭 부여해야함
			 result = rs.getInt(1); // 1은 Index를 뜻함, 오라클의 Index임 인덱스는 1부터
		}
		rs.close(); // -- 리소스 반납
				
		// 최종 결과 반환
		return result;
	}
	
	// 회원 목록(데이터) 조회
	public ArrayList<MemberDTO> lists() throws SQLException
	{
		// 결과값 변수 선언
		ArrayList<MemberDTO> result = new ArrayList<MemberDTO>();
		
		// 작업 객체 생성
		Statement stmt = conn.createStatement();
		
		// 쿼리문 준비
		String sql = "SELECT SID, NAME, TEL FROM TBL_MEMBER";
		
		// 작업 객체를 활용하여 쿼리문 실행
		ResultSet rs = stmt.executeQuery(sql);
		
		/*
		 1	오승우	010-5555-5555
		 2	육승우	010-6666-6666
		 3	칠승우	010-7777-7777		 
		 */
		
		while (rs.next())
		{
			MemberDTO dto = new MemberDTO();
			
			dto.setSid(rs.getString("SID"));
			dto.setName(rs.getString("NAME"));
			dto.setTel(rs.getString("TEL"));
			
			result.add(dto);
		}
		rs.close();
		stmt.close();
		
		// 결과 값 반환
		return result;
	}	
	
	// 데이터베이스 연결 해제
	public void close()
	{
		DBConn.close();
	}
}

SqlExam01.java

/*=========================================================================
	2018.01.15
	SqlExam01.java
	- 이름과 전화번호를 여러개 입력받고 전체 출력하는 프로그램을 구성한다.
	- 데이터베이스를 이용한다.
	- Member 클래스르 만들어 활용할 수 있도록 한다.
=========================================================================== */

// 실행 예)
// 이름 전화번호 입력(1) : 오승우 010-1111-1111
// 회원 정보 입력 완료~!!!
// 이름 전화번호 입력(2) : 육승우 010-2222-2222
// 회원 정보 입력 완료~!!!
// 이름 전화번호 입력(3) : 칠승우 010-3333-3333
// 회원 정보 입력 완료~!!!
// 이름 전화번호 입력(4) : .

// --------------------------------
// 전체 회원 수 : 3명
// --------------------------------
// 번호		이름	전화번호
//  1	   오승우	010-1111-1111
//  2      육승우	010-2222-2222
//  3	   칠승우	010-3333-3333

package com.test;

import java.util.Scanner;

import com.util.DBConn;

public class SqlEaxm01_1 {

	public static void main(String[] args) 
	{
		Scanner sc = new Scanner(System.in);
		
		try 
		{
			MemberDAO dao =new MemberDAO();
			System.out.println("데이터베이스 연결됨~~~!!!");
			
			int count = dao.count();
			
			do
			{
				System.out.printf("이름 전화번호 입력(%d): ", (++count));
				
				String name = sc.next();
				if (name.equals("."))
					break; // 멈춘다.(그리고...빠져나간다) continue (뒷부분... 무시하고)계속한다.
				String tel = sc.next();
				
				// insert 쿼리문을 수행
				// 이 메소드가 dao 안에... add() 라는 이름으로 존재한다.
				// add(MemeberDTO) 메소드 호출하기 위해서는...
				// MemberDTO 가 사전에 준비되어(마련되어) 있어야... add() 메소드 호출 가능
				
				MemberDTO dto = new MemberDTO();
				dto.setName(name);
				dto.setTel(tel);
				
				int result = dao.add(dto);
				if(result > 0)
				{
					System.out.println("회원 정보 입력 완료~!!!");
				}
				
				
			}while(true);
			
			// . 찍어서... 그만하겠다는 의사 표현 했을 경우... 처리될 내용
			System.out.println("---------------------------------------");
			System.out.printf("	전체 회원 수 : %d명\n", dao.count());
			System.out.println("---------------------------------------");			
			System.out.println(" 번호	   이름		   전화번호");
			System.out.println("---------------------------------------");
			
			for (MemberDTO dto : dao.lists()) // for(lists에서 꺼낸 타입, list(데이터타입)) 
			{
				System.out.printf("%3s %10s %20s%n", dto.getSid(), dto.getName(), dto.getTel());
				System.out.println("---------------------------------------");
				
			}
			
			// System.out.println("---------------------------------------");

			
		} catch (Exception e) 
		{
			System.out.println(e.toString());
		}
		finally 
		{
			try 
			{
				DBConn.close();
				System.out.println("데이터베이스 연결 닫힘~!!!");
				System.out.println("프로그램 종료됨~!!!");
			} catch (Exception e) 
			{
				System.out.println(e.toString());
			}
		}
	}

}

PreparedStatement

PreparedStatement 객체

  1. Statement 의 execute() 메소드는 문자열로 구성된 SQL 문을 DBMS 로 전달하는 역할을 수행하며, 내부적으로는 SQL 문을 JDBC 드라이버가 읽어들일 수 있는 형식으로 전처리(Precompile) 한다. 이후 드라이버는 DBMS 에 전처리된 요구사항을 전송하게 되는데, SQL 문을 매번 전처리 해야 하기 때문에 반복적인 작업에서 속도가 늦어질 수 있다. 하지만 PreparedStatement는 전처리된 Statement 로 주어진 SQL 문을 미리 전처리 과정을 거치 상태로 보관하기 때문에 반복 작업에 유리하다. Statement의 서비클래스인 PreparedStatement 는 Statement 의 모든 기능을 상속받으며 IN 매개변수의 위치에 데이터베이스로 전송되어질 값을 지정하기 위해 필요한 전체 모든 메소드들의 집합을 포함시킨다. 또한, 세 개의 메소드 execute(), executeQuery(), executeUpdate() 는 아무런 매개변수도 갖지 않는다. 이러한 메소드들의 Statement 형태(SQL 문 매개변수를 가지는 형태) 는 PreparedStatement 객체에서 사용되지 않는다.
  2. IN 매개변수 넘겨주기: PreparedStatement 객체를 실행하기 전에 각 『?』, 매개변수의 값이 설정되어져야 한다. 이것은 setXXX() 메소드를 호출하여 이루어지며 XXX 는 매개변수에 대한 적당한 데이터타입(형)이다. 예를 들어, 매개변수가 long 형이라면, 사용할 메소드는 getLong() 이다. setXXX() 메소드의 첫 번째 인자는 설정될 매개변수의 순번이고, 두 번째 인자는 매개변수가 설정될 값이다.

SqlTest01.java

package com.test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;

import com.util.DBConn;

public class SqlTest01 
{
	public static void main(String[] args) 
	{
		try 
		{
			Connection conn = DBConn.getConnection();
			
			if(conn != null)
			{
				System.out.println("데이터베이스 연결 성공~!!!");
				try 
				{
					/*
					
					// 작업 객체 생성
					Statement stmt = conn.createStatement();
					
					// 쿼리문 준비
					String sql = "INSERT INTO TBL_MEMBER(SID, NAME, TEL) VALUES(4,'고길동', '010-4444-4444')";
					
					// 쿼리문 실행
					int result = stmt.executeUpdate(sql);
					
					if(result > 0)
						System.out.println("데이터 입력 성공~!!!");
						
					*/
					
					// 쿼리문 준비
					String sql = "INSERT INTO TBL_MEMBER(SID, NAME, TEL) VALUES(?, ?, ?)";
					
					// 작업 객체 생성
					PreparedStatement pstmt = conn.prepareStatement(sql);
					
					// In 매개변수 넘겨주기
					pstmt.setInt(1, 14);
					pstmt.setString(2, "고길동");
					pstmt.setString(3, "010-4444-4444");
					
					// 쿼리문 실행
					int result = pstmt.executeUpdate();
					
					if(result > 0)
						System.out.println("데이터 입력 성공~!!!");
					
				} catch (Exception e) 
				{
					System.out.println(e.toString());
				}
			}
			
			DBConn.close();
			
		} catch (Exception e) 
		{
			System.out.println(e.toString());
		}
	}

}

SqlTest02.java

package com.test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Scanner;

import com.util.DBConn;

public class SqlTest02 
{

	public static void main(String[] args) 
	{
		Scanner sc = new Scanner(System.in);
		
		Connection conn = DBConn.getConnection();
		
		do
		{
			System.out.println("번호를 입력하세요 : ");
			String sid = sc.next();
			
			if(sid.equals("-1"))
				break;
			System.out.println("이름을 입력하세요 : ");
			String name = sc.next();
			System.out.println("전화번호를 입력하세요 : ");
			String tel = sc.next();
			
			if(conn != null)
			{
				System.out.println("데이터베이스 연결 성공~!!!");
				try 
				{
					String sql = "INSERT INTO TBL_MEMBER(SID, NAME, TEL) VALUES(?,?,?)";
					
					PreparedStatement pstmt = conn.prepareStatement(sql);
					
					pstmt.setInt(1, Integer.parseInt(sid)); // sid는 String 값으로 받았기 때문에 integer로 파싱해줘야함
					pstmt.setString(2, name);
					pstmt.setString(3, tel);
					
					int result = pstmt.executeUpdate();
					
					if(result > 0) 
					{
						System.out.println("데이터 입력 성공~!!!");
					}
					
				} catch (Exception e) 
				{
					System.out.println(e.toString());
				}
			}
		}while(true);
		
		DBConn.close();
		
		System.out.println("데이터베이스 연결 닫힘~!!!");
		System.out.println("프로그램 종료됨~!!!");
	}

}

SqlTest03.java

package com.test;

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

import com.util.DBConn;

public class SqlTest03 {

	public static void main(String[] args) 
	{
		Connection conn = DBConn.getConnection();
		
		if(conn != null)
		{
			System.out.println("데이터베이스 연결 성공~!!!");
		}
			try
			{
				Statement stmt = conn.createStatement();
				String sql = "SELECT SID, NAME, TEL FROM TBL_MEMBER";
				ResultSet rs = stmt.executeQuery(sql);
				
				
				while (rs.next())
				{
					String sid = rs.getString("SID");
					String name = rs.getString("NAME");
					String tel = rs.getString("TEL");
					
					String str = String.format("%3s %10s %20s", sid, name, tel);
					System.out.println(str);
				}
				rs.close();
			} catch (Exception e)
			{
				System.out.println(e.toString());
				
			}
			DBConn.close();
			
			System.out.println("데이터베이스 연결 닫힘~!!!");
			System.out.println("프로그램 종료됨~!!!");
	}

}

JSP(Java Server Pages)

1. Java Server Pages : 웹 프로그램 작성 언어의 한 종류.

2. JSP( Java Server Pages ) 는 HTML 내에 자바 코드를 삽입하여

웹 서버에서 동적으로 웹 페이지를 생성하여 웹 브라우저에 돌려주는 언어이다.

Java EE 스펙 중 일부로 웹 애플리케이션 서버에서 동작한다.

3. JSP( Java Server Pages ) 는 동적(Dynamic)인 웹 페이지를

비교적 간단히 만들 수 있는 방법을 제공하는

자바를 기반으로 하고 있는 스크립트 언어(Server Side Script)로

자바 엔터프라이즈 애플리케이션에서 UI(User Interface) 영역을 담당하고 있다.

4. JSP( Java Server Pages ) 는 실행 시에는 자바 서블릿(Servlet)으로 변환 후 실행되므로

서블릿(Servlet) 과 거의 유사하다고 볼 수 있다.

하지만, 서블릿과는 달리 HTML 표준에 따라 작성되므로 웹 디자인(구조)하기에 편리하다.

이와 비슷한 구조인 것으로 PHP, ASP, ASP.NET 등도 있다.

5. JSP(Java Server Pages) 는 자바를 서버 환경에서 사용하는 스크립트 방식의 언어로

단일 스레드로 클라이언트의 요청에 서비스한다.

요청이 있을 때 마다... 즉, 객체가 생성될 때 마다... 프로세스를 생성하는 기존의 CGI 와는 달리

하나의 메모리를 공유하면서 서비스되는 원리를 가지고 있다.

이러한 원리는 서버측의 부하를 줄여주며, JSP 내부에는 보여주는 코드만 작성하고

직접 작업하는 부분은 자바 빈으로 구성하여 둘을 분리할 수 있다.

이는 서로 영향을 주지 않으면서 수정할 수 있는 장점을 취하며,

JAVA가 갖고 있는 장점에 해당하는 재사용성을 높일 수 있도록 한다.

클라이언트	          <-----------------> 서버

HTML, CSS, Javascript   <-----------------> JSP(JAVA)

브라우저(IE, FF, CR)	<-----------------> 웹서버(톰캣), 오라클

요청	                <-----------------> 응답

6. 아파치 스트럿츠나 자카르타 프로젝트의 JSTL 등의 JSP 태그 라이브러리를 사용하는 경우에는

자바 코딩 없이 태그만으로 간략히 기술하는 것이 가능하기 때문에 생산성을 높일 수 있다.

7. JSP 실행 구조

1단계. 웹 클라이언트에서 웹 서버에 웹 프로그램 요청.

2단계. 웹 서버에서 클라이언트가 요청한 JSP 프로그램 로드.

3단계. JSP 페이지에 대한 변환 실행

이 과정에서 일반 『.java』인 파일로 변환된다. → Servlet

4단계. 『.java』인 파일로 변환된 서블릿(Servlet)의 컴파일 및 실행

5단계. 실행 결과로 동적 생성된 HTML Document 를 클라이언트측에 응답(전달).

6단계. 웹 클라이언트는 응답받은 HTML Document 를

브라우저에서 웹 페이지 형태로 출력

==> 클라이언트에서 서비스가 요청되면 JSP 의 실행을 요구하고,

JSP 는 웹 애플리케이션 서버의 서블릿 컨테이너에서 서블릿 윈시 코드로 변환된다.

그 후에 서블릿 원시 코드는 바로 컴파일된 후 실행되어

결과를 HTML 형태로 클라이언트에게 돌려주게 된다.

'교육 및 세미나 > 신입사원 교육' 카테고리의 다른 글

11일차(2018.01.17)  (0) 2018.01.19
10일차(2018.01.16)  (0) 2018.01.19
8일차(2018.01.12)  (0) 2018.01.12
7일차(2018.01.11)  (0) 2018.01.12
6일차(2018.01.10)  (0) 2018.01.12