반응형

1. StringBuffer vs StringBuilder

StringBuilder

StringBuffer

  • 문자열 저장 및 변경을 위한 메모리 공간을 지닌 클래스

  • 문자열 데이터의 추가를 위해 append , insert 메소드를 지니고 있다

  • String 클래스는 문자열 상수를 지니는 메모리 공간 지님

    -> StringBuffer, StringBuilder 안의 메모리 공간 : 값이 변경 가능한 변수의 성격 지님

동시에 처리하는 것(Synchroziation) 허용 X

동시에 처리하는 것 (Synchroziation) 허용 O

단일 스레드 환경

멀티 쓰레드 프로그래밍

2. 객체란?

-데이터 행위, 아이덴티티를 가지고 있는 것

 

3.클래스 

-객체를 생성하는 템플릿

-동일한 속성과 메소드를 가진 객체를 생성하기 위한 템플릿

-객체를 메모리상(Heap)에 올려놓고 데이터를 처리하기 위해서 미리 작성된 객체의 정의(데이터 구조 + 처리과정)

-메모리 상 올라가기전(class) / 올라와서 사용( 객체)

-클래스에서 데이터 구조를 정의하는 것 : 속성(Attribute) or 멤버변수

-클래스에서 처리 과정을 위한 함수 : 메서드

 

4.캡슐화

-행위, 상태 포장 -> 외부에 노출할 것(interface), 감출 것 결정

 

5.상속

-계층구조를 표현하는 것

 

6.다형성

-캡슐화, 상속과 함께 동작하며 , 객체-지향 프로그램의 흐름 제어를 단순화

 

7.JSP & Servlet

-웹 어플리케이션

-JSP (HTML 문서 안에 JAVA 코드 포함)

-서블릿(자바 코드 안에 HTML 포함)

 

-사용자 요청이 Servlet 일 경우 

  • 클라이언트가 웹 브라우저에 URL 을 입력하면 해당하는 HTTP Request를 해당하는 서버의 Servlet Container 에 보낸다

  • Servlet Container는 HttpServletRequest, HttpServletResponse 두 객체 생성

  • 클라이언트가 요청한 URL-> WebContent/WEB-INF/web.xml 파일에 작성

  • Servlet Container 는 service() 메소드를 호출하여 POST, GET 여부 따라 doGet() 또는 doPost() 가 호출

  • doGet() 또는 doPost() 메소드는 동적인 페이지 생성 후 -> HttpServletResponse 객체에 응답 보냄

  • 응답 완료 시 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킨다

-사용자 요청이 JSP 일 경우 흐름

  • 사용자로부터 요청을 받은 웹서버는 요청에 포함된 URL (http://localhost/*.jsp?*) 속의 .jsp확장자들 발견하고 요청이 JSP 페이지인 것 확인

  • JSP를 WAS(웹 컨테이너)로 전송

  • WAS(웹 컨테이너)는 JSP페이지 전체를 Servlet class의 소스코드 변환

 

 

반응형

'Language Study > Java' 카테고리의 다른 글

제주에서 자바_Week4  (0) 2019.08.12
제주에서 자바_Week3_4  (0) 2019.08.11
제주에서 자바_Week3_3  (0) 2019.07.31
제주에서 자바_Week3_2  (0) 2019.07.30
제주에서 자바_Week3_1  (0) 2019.07.29
반응형

1.게시판을 만들어보자^^ (로그인 필요 없이 간단한 게시판 형태)

 

<oracle db>

SQL> create table temp20t(
  2  data char(3) null
  3  );

테이블이 생성되었습니다.

SQL> insert into temp20t values('abc');

1 개의 행이 만들어졌습니다.

SQL> insert into temp20t values(null);

1 개의 행이 만들어졌습니다.

Q. NULL 4글자가 입력 가능? null은 빈값을 의미

insert into temp20t values('null'); -> null과 'null'은 구분하자

 

% select * from temp20t where data = null;        NO

    select * from temp20t where data is null;        YES

(null 과의 비교는 is를 이용한다)

 

<문제점>

package main;

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

public class Test110 {
	public static void main(String[] args) throws Exception {
		String data = "xyz";
		
		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = DriverManager.getConnection(
			"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
		
		
		//sql 이어 붙일 땐 ''에 주의해야한다
		//data에 null 일 때는 에러 -> 왜? null이라는 문자열이 들어가는 것으로 됨
		//나름 해결책 이지만 null 가능 필드가 2개면 경우의 수가 4개 / 3개면 8개
		//이런 문제 떄문에 현업에서는 PreparedStatement를 더 선호한다.
		//현업에서는 아예 char 는 무조건 4자리 이상을 잡게 하는 경우도 있다.
		String sql =(data != null) ? 
				"insert into temp20t values ('"+data+"')":
				"insert into temp20t values(null)";
		Statement stmt = conn.createStatement();
		
		stmt.executeUpdate(sql);
		
		stmt.close();
		conn.close();
	}

}

<해결책>

package main;

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

public class Test111 {
	public static void main(String[] args) throws Exception {
		
		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = DriverManager.getConnection(
			"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
		
		/*Statement 가 어떤 sql 문장이든 실행하는 범용적인데 반해서
		 * preparedStatement 는 생성시에 준비한 그 문장만 실행 할 수 있다
		 * 대신 ?  영역을  setString , setInteger등을 이용하여 채울 수 있다
		 * (순서가 1부터 시작하는 것에 주의)
		 * execute 시에 매개변수 없음에 주의*/
		
		String sql = "insert into temp20t values(?)";
		PreparedStatement stmt = conn.prepareStatement(sql); //sql문장 전용의 바구니
//		stmt.setString(1,"LEE");
		stmt.setString(1, null);//에러 안남 null값이 들어간 행이 생김
		//이걸 쓰면 null 값을 넣을 때 ''를 붙여야 할지를 결정하기 위해 이런저런 고민 할 필요가 없어진다(위의 코드처럼)
		stmt.executeUpdate();
		
		stmt.close();
		conn.close();
	}
}

/*SQL> select * from temp20t;

DATA
------
abc

xyz
xyz
xyz
LEE -> 컴파일 시 들어감*/

AUTOBOXING / UNBOXING

package main;

public class Test112 {
	//매개변수로 String 을 0..*개를 넣어도 에러가 안나는 선언 방식
	public static void test2(Object...args){
		for(int i = 0; i < args.length; i++){
			if(args[i] == null){
				System.out.println("null");
			}else if(args[i] instanceof Integer){
				int r = ((Integer)args[i]).intValue();
				System.out.println("null");
			}else if(args[i] instanceof Double){
				double r = ((Double)args[i]).doubleValue();
				System.out.println(r+0.1);
			}else if(args[i] instanceof String){
				System.out.println((String)args[i]);
			}
		}
		
	}
	
	public static void test(String... args){
		System.out.println(args.length);
	}
	//Object arg_1 = 100; -> 100을 new Integer(100)로 자동변환
	//Object arg_3 = 3.14; => 3.14를 new Double(3.14)로 자동변환
	public static void main(String[] args){
		
		test2(100, "Hello", 3.14, null);
		
		test("apple");
		test();
		test("apple", "banana");
	}
}


/*autoboxing unboxing
 * 
 * Object i = 100;(o)
 * int i = j;(x)
 * 
 * Integer i = 100(o)
 * int j = i;(o)*/

<프레임워크 만들기>

package main;

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

public class Test113 {
	public static int update(String sql, Object... args) throws Exception{
		int rc = 0;

		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = DriverManager.getConnection(
			"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
		PreparedStatement stmt = conn.prepareStatement(sql); //sql문장 전용의 바구니
	
		for(int i = 0; i < args.length; i++){
			if(args[i] == null){
				stmt.setObject(i+1, null);
			}else if(args[i] instanceof Integer){
				int r = ((Integer)args[i]).intValue();
				stmt.setInt(i+1, r);
			}else if(args[i] instanceof Double){
				double r = ((Double)args[i]).doubleValue();
				stmt.setDouble(i+1, r);
			}else if(args[i] instanceof String){
				stmt.setString(i+1, (String)args[i]);
			}
		}
		rc = stmt.executeUpdate();
		
		stmt.close();
		conn.close();
		return rc;
	}
	
	public static void main(String[] args) throws Exception{
		String sql = "insert into temp20t values(?,?)";
		update(sql, "KIM",100);
		
	}
}
/*프레임워크 만들기 */

<Anonymous class>

package main;

interface ITemp{
	public void print();//인스턴스 못만듬 , abstract 클래스이기 떄문에 
	//클래스 : 참조형변수 선언/  인스턴스 생성 / 상속해서 인스턴스 선언
}
public class Test114 {
	public static void main(String[] args){
		/*Anonymous class : 이름 없는 클래스
		 * -> 조상은 있음 : ITemp
		 * ITemp를 상속받고 -> 모든 메소드 오버라이딩 해주고 
		 * 이름이 없어서 재사용은 불가능하다
		 * -클래스 선언하고 , 인스턴스 생성하고는 끝
		 * t가 왜 가리킬 수 있는 거지? A t = new B() 자손이 조상에서 오버라이딩한 것을 가져올 수 있기 때문에 */
		
		final int i = 100; //i = 로컬변수다  -> final로 선언해주면 어나니머스 클래스에서 사용할 수 있음 / 객체 지향 개념
		
		ITemp t = new ITemp(){
			public void print(){
				System.out.println("HelloWorld" + i);
			}
		};
		t.print();//자손 인스턴스가 소환
	}
}

JSP 기본 문법

  • JSP 페이지
    • <%-- JSP 주석  --%>
    • <% 스클립틀릿(자바 명령문) %>  -> 웹 서버 쪽 실행
    • <%= 익스프레션 %> -> 자바식 (연산자 포함식, 메서드 호출식) -> 웹 서버 쪽 실행 => 웹 브라우저로 실행
    • ${  익스프레션 랭귀지 } - 빠른 간단한 연산 가능
<HTML>
	<BODY>
    	<% int total = 0;
        	for(int cnt = 0; cnt <= 100; cnt++)
            	total += cnt;
       	%> //스클립틀릿 -> 자바 명령문
        
        <%= total %> //익스프레션 -> 자바식(연산자 포함식, 메서드 호출식)
	</BODY>
</HTML>
  • 서블릿 클래스
    • 서블릿 클래스 골격 선언 -> service 함수 메서드 선언 -> 명령 -> 파일로 텍스트 출력
//서블릿 클래스 골격 선언
public class Servlet extends HttpServlet{
	//service 함수 메서드 선언
	public void service(HttpServletRequest request, HttpServletResponse response) 
    					throws IOException ServletException{
                        
        //명령
		for(int cnt = 1; cnt <= 100; cnt++)
        	total += cnt;
            //파일로 텍스트 출력
            PrintWriter out = response.getWriter();
            out.println("<HTML>");
            out.println("<BODY>");
            out.println("%d",total);
            out.println("</BODY>");
            out.println("</HTML>");
    }
}
 
        

<web.xml> 에 서블릿 등록

<servlet>
	<servlet-name>Servlet-test</servlet-name>
    <servlet-class>servlet</servlet-class>
</servlet> //서블릿 클래스 이름이 들어감

<servlet-mapping>
	<servlet-name>servlet-test</servlet-name>
    <url-pattern>/servlet</url-pattern>
</servlet-mapping> //서블릿 클래스 호출할 때 사용할 URL 들어감
	

 

<쿠키 : 웹 브라우저 쪽에서 데이터 입력, 수정, 삭제, 조회 >

-> 결제 모듈에서 사용 / A, B, C 서블릿이 각자 있고 각자의 유저가 쿠키를 생성하여 따로 저장할 수 있음 (장바구니 , 로그인 정보에 사용)

package study3;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/*http://localhost:8081/study3/state?use=readCookie
 * 요청 -> 응답, 요청의 방법이 두가지 get / post // get : 엽서 / post : 택배
 * 
 * 엽서와 주소의 내용을 구분하는 선의 역할 : ?
 * ? 오른쪽 내용 : key=value 형태로 구성
 *  request.getParameter를 이용하여 추출할 수 있따
 *  거의 대부분이 get방식이고 form 에서 method = "POST"로 지정된 경우만 POST방식*/
public class StateServlet extends HttpServlet{

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		String use = request.getParameter("use");
		
		if("addCookie".equals(use)){
			Cookie ck = new Cookie("name", "apple");
			response.addCookie(ck);
		}else if("readCookie".equals(use)){
			Cookie[] cks = request.getCookies();
			if(cks != null){
				for(int i = 0; i < cks.length; i++){
					String l = cks[i].getName() + ","+ cks[i].getValue();
					System.out.println(l);
				}
			}else{
				System.out.println("Cookie is null");
			}
		}
		
		System.out.println(use);
	}
	//addcookie 후 read 쿠키를 하니 
	/*Cookie is null
	readCookie
	getCookie
	
	/*쿠키는 서블렛과 다르게 브라우저에서 생성 -> 서버에서 알 수 있는 방법은 응답이 넘어갈 때(addCookie -> response 멤버 변수)
	*요청할 때 쿠키를 물고온다 / 응답 내보낼때만 서블릿이 조작할 수 있음 
	*/
}

세션사용

      최초 getSession() 호출시에는 고유 넘버가 없이 요청이 들어온다
       * 기억장소 생성 - Map<String, Object> 형태
       * 고유 넘버 생성
       * JSESSIONID 키 값으로 고유 넘버를 쿠키에 저장
       * 
       * 그 이후에 getSession() 호출 : 고유 넘버 물고 왔으니 그걸로 기억장소 찾는다
       * "브라우저 마다 개별적인 기억장소가 생성된다"
package study3;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

//session으로 접근 가능하게 만드세요 
// http://localhost:8081/study3/state?use=readCookie

public class SessionServlet extends HttpServlet {

   @Override
   protected void service(HttpServletRequest request, HttpServletResponse response) 
         throws ServletException, IOException {
         
      HttpSession session = request.getSession();
      System.out.println( session.isNew() );
      
      //true
      //JSESSIONID,2C7E8E0D95817C0E56780B2B4644924D
      
      session.setAttribute("apple", "Object!!");
      Object value = session.getAttribute("apple");
      System.out.println(value.toString());
      
      /*false
		Object!!
       	*/
      
      /*최초 getSession() 호출시에는 고유 넘버가 없이 요청이 들어온다
       * 기억장소 생성 - Map<String, Object> 형태
       * 고유 넘버 생성
       * JSESSIONID 키 값으로 고유 넘버를 쿠키에 저장
       * 
       * 그 이후에 getSession() 호출 : 고유 넘버 물고 왔으니 그걸로 기억장소 찾는다
       * 
       * "브라우저 마다 개별적인 기억장소가 생성된다"*/
   }

}

 

<jsp>

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
    <%!
    
    int i = 0;
    
    %>
    <%
    
    int j = 0;
    
    %>
http://www.w3.org/TR/html4/loose.dtd">

<%=i++ %>
<%=j++ %>

<%-- jsp 주석 ,html 파일 요청하듯이 요청한다(web.xml 수정할 필요 없다)
i = 멤버 변수 / j = 로컬 변수의 느낌이 난다
jsp 파일을 요청하면 톰캣은 이것을 *.java 파일로 변환한다(서블릿코드)
이것은 컴파일하고 인스턴스를 만들어 적재하고 인스턴스 재활용 한다

서블릿 이후에 asp의 등장으로 위기를 느낀 자바쪽에서 ASP 비슷하게 만든 게 JSP
  http://192.168.2.11:8081/study/Test115.jsp --%>
package study3;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class JSPServlet extends HttpServlet{
	
	private ServletContext application = null;
	//대표적인 함수 getRealPath
	private ServletConfig config = null;

	
	//적재된 서블릿의 시점을 가져오는 것이 init 함수
	

	@Override
	public void init(ServletConfig config) throws ServletException {
		this.config = config;
		application = config.getServletContext();
	}

	/*-------------------------------------------------------------------------------- 
	 *<%! ... %> 은 여기에 온다
	 *    int i = 0;
	 *-------------------------------------------------------------------*/

	@Override
	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		PrintWriter out = response.getWriter();
		/*--------------------------------------------------
		 * <%....%>은 여기에 온다
		 *     int j = 0;
		 * --------------------------------------------------*/
		/*--------------------------------------------------
		 * <%=... %은 print()로 감싸서 나온다
		 * 	<%=i++ %>
		 * out.println(i++);
			<%=j++ %>
		   out.println(j++);
		   
		   Test115.jsp > 유사한 형태로 변환되고 컴파일되고 인스턴스 만들어지고 적재된 뒤에 실행한다
		 * --------------------------------------------------*/
		out.flush();
		out.close();
	
	}
}

 

어디에 들어있어야 하는지, 왜 되는지 정확하게 알아보기!

 

문제

1. 구구단 배경색 새로고침 시 변경

 

<%@ page contentType="text/html;charset=UTF-8"%><%!
    String getColor(){
        char[] chs = "0123456789abcdef".toCharArray();
        StringBuffer sb = new StringBuffer();

        for(int i=1;i<=6;i++) {
            int index = (int)(Math.random() * 16);
            sb.append(chs[index]);
        }
        return sb.toString();
    }
%>
<html>
<body>
    <table border ="1" bordercolor="black" cellspacing = "0" align="center" cellpadding="7">
    <% for(int i=2;i<=9;i++){ %>
        <tr>
      <% for(int j=1;j<=9;j++){ %>
            <% String color = getColor(); %>
            <td bgColor="#<%=color%>" >
        <%=i%> * <%=j%> = <%=i*j%>
            </td>
      <% } %>
        </tr>
    <% } %>
</body>
</html>

 

2. errortrace.jsp 만들어서 찍어보기

 

<error.jsp>

<%@ page contentType="text/html; charset=utf-8" isErrorPage="true"
	pageEncoding="EUC-KR"%>
<%
	Exception e = (Exception) session.getAttribute("error");
%>
<!DOCTYPE html>
<html>
<body>
	<%
		StackTraceElement[] st = e.getStackTrace();
		for (int i = 0; i < st.length; i++) {
	%>
	<%=st[i]%>
	<%
		}
	%>
</body>
</html>

1. 채팅방을 만들어보자

 

create table talk_room_t(
no number(5),
apple char(4),
banana char(4),
orange char(4)
);
//톡방 만들기
 insert into talk_room_t values(0,'1234','2345','3456');
 
 create table talk_t(
  talk_no number(6),
  room_no number(6),
  content varchar2(123)
 );
 
 create sequence seq_talk;
  //시퀀스 제작
 insert into talk_t values(seq_talk.nextval, 0, 'blabla....');
  //talk_t에 시퀀스 넘버를 받아 값 넣음
 commit;

<talk_login.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>

</head>
<body>
talk_login.jsp<br/>

<%-- POST : 택배, GET : 엽서
	GET 방식 일 떄는 주소 옆에 붙어서가고 POST 방식일 때는 내부에 숨겨서 간다
	-talk_login2.jsp?roomNo=0&pwd=abcd
	
	강사습관 : html을 생성하지 않은 곳은 2를 붙이더라 --%>
<form method = "POST" action = "talk_login2.jsp">
	<input type= "text" name = "roomNo" size = "4"/>
	<input type= "password" name = "pwd" size = "8"/>
	<input type= "submit"/>
	</form>
</body>
</html>

<talk_login2.jsp>

<%@ page import="study3.Util" pageEncoding="EUC-KR"%>
<%

String ctxPath = request.getContextPath();

//문자열 숫자 변환 시에 에러 발생될 수 있다.
int roomNo = Util.parseInt(request.getParameter("roomNo"));
String pwd = request.getParameter("pwd");

if(roomNo == -1 || pwd == null  || "".equals(pwd)){
	response.sendRedirect("/study3/talk_login.jsp");
	
	//sendRedirect 코드 이후의 코드는 의미 없다
	
	return;
}

Exception err = null;

try{
	if(err == null)
		throw new Exception();
}catch(Exception e){
	err = e;
}

if(err != null)
{
	response.sendRedirect(ctxPath + "/error.jsp");
	return;
}
%>

<%--
talk_login2.jsp
see : study3.Util.class

 --%>

 


<TalkRoomVo.jsp>

package study3;

public class TalkRoomVO {
	public Integer getRoomNo() {
		return roomNo;
	}
	public void setRoomNo(Integer roomNo) {
		this.roomNo = roomNo;
	}
	public String getApple() {
		return apple;
	}
	public void setApple(String apple) {
		this.apple = apple;
	}
	public String getBanana() {
		return banana;
	}
	public void setBanana(String banana) {
		this.banana = banana;
	}
	public String getOrange() {
		return orange;
	}
	public void setOrange(String orange) {
		this.orange = orange;
	}
	private Integer roomNo = null;
	private String apple = null;
	private String banana = null;
	private String orange = null;

}

<talk_login2.jsp>

<%@ page import="study3.Util" pageEncoding="EUC-KR" %>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.PreparedStatement" %>
<%@ page import="java.sql.ResultSet" %>
<%@ page import="study3.TalkRoomVO" %>
<%
	
	String ctxPath = request.getContextPath();
	
	//문자열 숫자 변환 시에 에러 발생될 수 있다.
	int roomNo = Util.parseInt(request.getParameter("roomNo"));
	String pwd = request.getParameter("pwd");
	
	if(roomNo == -1 || pwd == null  || "".equals(pwd)){
		response.sendRedirect("/study3/talk_login.jsp");
		return;
		//sendRedirect 코드 이후의 코드는 의미 없다
		
	}
	
	Exception err = null;
	TalkRoomVO vo = null;
	
	try{
			Class.forName("oracle.jdbc.driver.OracleDriver");
			Connection conn = DriverManager.getConnection(
				"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
			String sql = "select * from talk_room_t where no = ?";
			PreparedStatement stmt = conn.prepareStatement(sql);
			stmt.setInt(1,roomNo);
			ResultSet rs = stmt.executeQuery();
			
			System.out.println(rs);
			System.out.println(conn);
			if(rs.next()){
				vo = new TalkRoomVO();
				vo.setRoomNo(rs.getInt("no"));
				vo.setApple(rs.getString("apple"));
				vo.setBanana(rs.getString("banana"));
				vo.setOrange(rs.getString("orange"));
			}
			rs.close();
			stmt.close();
			conn.close();
			
	}catch(Exception e){
		err = e;
	}
	System.out.println(vo);
	
	if(err != null)
	{
		response.sendRedirect(ctxPath + "/error.jsp");
		return;
	}
	//해당 방이 없는 경우
	if(vo == null){
		response.sendRedirect(ctxPath + "/talk_login.jsp");
	}
	else if(vo.getApple().equals(pwd)){
		Cookie ck = new Cookie("level", "apple");
		response.addCookie(ck);
		
		Cookie ck2 = new Cookie("roomNo", String.valueOf(roomNo));
		response.addCookie(ck2);
		
		response.sendRedirect(ctxPath + "/talk_view_apple.jsp");
	}
	else if(vo.getBanana().equals(pwd)){
		Cookie ck = new Cookie("level", "banana");
		response.addCookie(ck);
		
		Cookie ck2 = new Cookie("roomNo", String.valueOf(roomNo));
		response.addCookie(ck2);
		
		response.sendRedirect(ctxPath + "/talk_view_banana.jsp");
	}
	else if(vo.getOrange().equals(pwd)){
		Cookie ck = new Cookie("level", "Orange");
		response.addCookie(ck);
		
		Cookie ck2 = new Cookie("roomNo", String.valueOf(roomNo));
		response.addCookie(ck2);
		
		response.sendRedirect(ctxPath + "/talk_view_orange.jsp");
		
	}
	else{
		response.sendRedirect(ctxPath + "/talk_login.jsp");
	}
	
%>

<%--
talk_login2.jsp
see : study3.Util.class

 --%>

<talk_view_apple.jsp>

<%@ page contentType="text/html;charset=UTF-8" import="study3.Util, study3.TalkVO, java.util.*, java.sql.*" %>

<% String ctxPath = request.getContextPath();

    Cookie[] cks = request.getCookies();
    if(cks == null){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }
    int roomNo = -1;
    String level = null;

    for(int i=0;i<cks.length;i++){
        if(cks[i].getName().equals("level")){
            level = cks[i].getValue();
        }else if (cks[i].getName().equals("roomNo")){
            roomNo=Util.parseInt(cks[i].getValue());
        }
    }

    if(level == null || !level.equals("apple")){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }
    
    
    List<TalkVO> rl = new ArrayList<TalkVO>();
   	Exception err = null;
   	
   	try{
   		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = DriverManager.getConnection(
			"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
   		String sql = "select * from talk_t where room_no = ? order by talk_no desc";
   		PreparedStatement stmt = conn.prepareStatement(sql);
   		stmt.setInt(1, roomNo);
   		ResultSet rs = stmt.executeQuery();
   		
   		while(rs.next()){
   			TalkVO vo = new TalkVO();
   			vo.setTalkNo(rs.getInt("talk_no"));
   			vo.setRoomNo(rs.getInt("room_no"));
   			vo.setContent(rs.getString("content"));
   			rl.add(vo);
   		}
   		
   		rs.close();
   		stmt.close();
   		conn.close();
   		
   	}catch(Exception e){
   		err = e;
   	}
   	
   	if(err != null){
   		response.sendRedirect(ctxPath + "/error.jsp");
   		return;
   	}%>
   
<!DOCTYPE html>
<body>
talk_view_apple.jsp
				<table border ="1" cellspacing = "0" cellpadding="8">
				<%for(TalkVO vo : rl){%><tr>
					<td bgcolor ="hotpink"> <%=vo.getTalkNo()%> </td>
					<td bgcolor = "babypink"> <%=vo.getRoomNo()%> </td>
					<td bgcolor = "skyblue"> <%=vo.getContent()%></td>
				</tr><%}%></table>	
<%= rl %>
</body>
</DOCTYPEhtml><%@ page contentType="text/html;charset=UTF-8" import="study3.Util, study3.TalkVO, java.util.*, java.sql.*" %>

<% String ctxPath = request.getContextPath();

    Cookie[] cks = request.getCookies();
    if(cks == null){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }
    int roomNo = -1;
    String level = null;

    for(int i=0;i<cks.length;i++){
        if(cks[i].getName().equals("level")){
            level = cks[i].getValue();
        }else if (cks[i].getName().equals("roomNo")){
            roomNo=Util.parseInt(cks[i].getValue());
        }
    }

    if(level == null || !level.equals("apple")){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }
    
    
    List<TalkVO> rl = new ArrayList<TalkVO>();
   	Exception err = null;
   	
   	try{
   		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = DriverManager.getConnection(
			"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
   		String sql = "select * from talk_t where room_no = ? order by talk_no desc";
   		PreparedStatement stmt = conn.prepareStatement(sql);
   		stmt.setInt(1, roomNo);
   		ResultSet rs = stmt.executeQuery();
   		
   		while(rs.next()){
   			TalkVO vo = new TalkVO();
   			vo.setTalkNo(rs.getInt("talk_no"));
   			vo.setRoomNo(rs.getInt("room_no"));
   			vo.setContent(rs.getString("content"));
   			rl.add(vo);
   		}
   		
   		rs.close();
   		stmt.close();
   		conn.close();
   		
   	}catch(Exception e){
   		err = e;
   	}
   	
   	if(err != null){
   		response.sendRedirect(ctxPath + "/error.jsp");
   		return;
   	}%>
   
<!DOCTYPE html>
<body>
talk_view_apple.jsp
				<table border ="1" cellspacing = "0" cellpadding="8">
				<%for(TalkVO vo : rl){%><tr>
					<td bgcolor ="hotpink"> <%=vo.getTalkNo()%> </td>
					<td bgcolor = "babypink"> <%=vo.getRoomNo()%> </td>
					<td bgcolor = "skyblue"> <%=vo.getContent()%></td>
				</tr><%}%></table>	
<%= rl %>
</body>
</DOCTYPEhtml>

<게시판삭제, 더하기>

<talk_view_apple.jsp>

<%@ page contentType="text/html;charset=UTF-8" import="study3.Util, study3.TalkVO, java.util.*, java.sql.*" %>

<% String ctxPath = request.getContextPath();


	int roomNo = -1;
	String level = null;
	
    Cookie[] cks = request.getCookies();
    if(cks == null){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }

    for(int i=0;i<cks.length;i++){
        if(cks[i].getName().equals("level")){
            level = cks[i].getValue();
        }else if (cks[i].getName().equals("roomNo")){
            roomNo=Util.parseInt(cks[i].getValue());
        }
    }

    if(level == null || !level.equals("apple")){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }
    
    
    List<TalkVO> rl = new ArrayList<TalkVO>();
   	Exception err = null;
   	
   	try{
   		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = DriverManager.getConnection(
			"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
   		String sql = "select * from talk_t where room_no = ? order by talk_no desc";
   		PreparedStatement stmt = conn.prepareStatement(sql);
   		stmt.setInt(1, roomNo);
   		ResultSet rs = stmt.executeQuery();
   		
   		while(rs.next()){
   			TalkVO vo = new TalkVO();
   			vo.setTalkNo(rs.getInt("talk_no"));
   			vo.setRoomNo(rs.getInt("room_no"));
   			vo.setContent(rs.getString("content"));
   			rl.add(vo);
   		}
   		
   		rs.close();
   		stmt.close();
   		conn.close();
   		
   	}catch(Exception e){
   		err = e;
   	}
   	
   	if(err != null){
   		response.sendRedirect(ctxPath + "/error.jsp");
   		return;
   	}%>
   
<!DOCTYPE html>
<body>
talk_view_apple.jsp

				<table border ="1" cellspacing = "0" cellpadding="8">
					<tr>
						<td width = "80" align = "center">번호</td>
						<td width = "420" align = "center">내용</td>
						<td width = "420" align = "center">&nbsp;</td>
					</tr>
				<%for(TalkVO vo : rl){%><tr>
					<td bgcolor ="hotpink"> <%=vo.getTalkNo()%> </td>
					<td bgcolor = "skyblue"> <%= vo.getContent() %> </td>
					<td><a href = "talk_del2.jsp?talkNo=<%=vo.getTalkNo()%>">삭제 </a></td>
				</tr><%	
				}%></table>	
		<br/>
		<br/>
				
	<form method = "POST" action = "talk_add2.jsp">
		<textarea rows = "7" cols = "40" name = "content"></textarea>
		<br/><input type = "submit">
	
	</form>
<%= rl %>
</body>
</DOCTYPEhtml>

<talk_del2.jsp>

<%@ page import="study3.Util" %>
<%@ page import="java.sql.DriverManager" %>
<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.PreparedStatement" %>
<%@ page contentType="text/html;charset=UTF-8"%><%
    String ctxPath = request.getContextPath();
    int talkNo = Util.parseInt(request.getParameter("talkNo"));
    int roomNo = -1;
    String level = null;
    Exception err = null;

    Cookie[] cks = request.getCookies();
    if(cks == null){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }

    for (int i = 0; i < cks.length; i++) {
        if(cks[i].getName().equals("level"))
            level = cks[i].getValue();
        else if(cks[i].getName().equals("roomNo"))
            roomNo = Util.parseInt(cks[i].getValue());
    }

    if(level == null || roomNo == -1 || level.equals("apple")){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }

    try{
        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection conn = DriverManager.getConnection(
				"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");

        String sql = "delete from talk_t where room_no =? and talk_no = ?";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setInt(1, roomNo);
        ps.setInt(2, talkNo);

        ps.executeUpdate();

        ps.close();
        conn.close();

    }catch (Exception e ) { err = e; }

    if(err != null){
    	System.out.println(err);
        response.sendRedirect(ctxPath + "/error.jsp");
        return;
    } else{
        response.sendRedirect(ctxPath + "/talk_view_apple.jsp");
    }
%>
<html>
<body>

</body>
</html>

<talk_add2.jsp>

<%@ page pageEncoding="EUC-KR"%>
<%@ page import= "study3.Util"%>
<%@ page import= "java.sql.*"%>
    
    <%
    request.setCharacterEncoding("UTF-8");
    String ctxPath = request.getContextPath();
	int roomNo = -1;
	String level = null;
	String content = request.getParameter("content");
	
    Cookie[] cks = request.getCookies();
    if(cks == null){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }

    for(int i=0;i<cks.length;i++){
        if(cks[i].getName().equals("level")){
            level = cks[i].getValue();
            
        }else if (cks[i].getName().equals("roomNo")){
            roomNo=Util.parseInt(cks[i].getValue());
        }
    }
    
    if(level == null || roomNo == -1 || level.equals("orange")){
    	response.sendRedirect(ctxPath + "/talk_login.jsp");
    	return;
    }
    
    Exception err = null;
    try {

        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection conn = DriverManager.getConnection(
				"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
		String sql = "insert into talk_t values (seq_talk.nextval, ?,?)";
		
		PreparedStatement stmt = conn.prepareStatement(sql);
		stmt.setInt(1,roomNo);
		stmt.setString(2,content);
		
		stmt.executeUpdate();
		
		stmt.close();
        conn.close();

    }
   	catch(Exception e ){
   		err = e;
   		}
    
    if(err != null){
    	response.sendRedirect(ctxPath + "/error.jsp");
    }
    else if(level.equals("apple")){
    	response.sendRedirect(ctxPath + "/talk_view_apple.jsp");
    }
    else if(level.equals("banana")){
    	response.sendRedirect(ctxPath + "/talk_view_banana.jsp");
    }
    System.out.println(level);
    System.out.println(roomNo);
    %>

<Util.java>

package study3;

public class Util {
	public static int parseInt(String l){
		try{
			int r = Integer.parseInt(l);
			return r;
		}catch(Exception e){
			return -1;
		}
	}
	
	
	public static String h( String l ){
		if(l == null || l.equals("")){
			return l;
		}
		
		try{
    		byte[] bs = l.getBytes("8859_1");
    		l = new String(bs, "UTF-8");
    	}catch(Exception e){
    		
    	}
		return l;
	}

}

 

<talk_view_banana.jsp>

<%@ page contentType="text/html;charset=UTF-8" import="study3.Util, study3.TalkVO, java.util.*, java.sql.*" %>

<% String ctxPath = request.getContextPath();


	int roomNo = -1;
	String level = null;
	
    Cookie[] cks = request.getCookies();
    if(cks == null){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }

    for(int i=0;i<cks.length;i++){
        if(cks[i].getName().equals("level")){
            level = cks[i].getValue();
        }else if (cks[i].getName().equals("roomNo")){
            roomNo=Util.parseInt(cks[i].getValue());
        }
    }

    if(level == null || !level.equals("banana")){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }
    
    
    List<TalkVO> rl = new ArrayList<TalkVO>();
   	Exception err = null;
   	
   	try{
   		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = DriverManager.getConnection(
			"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
   		String sql = "select * from talk_t where room_no = ? order by talk_no desc";
   		PreparedStatement stmt = conn.prepareStatement(sql);
   		stmt.setInt(1, roomNo);
   		ResultSet rs = stmt.executeQuery();
   		
   		while(rs.next()){
   			TalkVO vo = new TalkVO();
   			vo.setTalkNo(rs.getInt("talk_no"));
   			vo.setRoomNo(rs.getInt("room_no"));
   			vo.setContent(rs.getString("content"));
   			rl.add(vo);
   		}
   		
   		rs.close();
   		stmt.close();
   		conn.close();
   		
   	}catch(Exception e){
   		err = e;
   	}
   	
   	if(err != null){
   		response.sendRedirect(ctxPath + "/error.jsp");
   		return;
   	}%>
   
<!DOCTYPE html>
<body>
talk_view_apple.jsp

				<table border ="1" cellspacing = "0" cellpadding="8">
					<tr>
						<td width = "80" align = "center">번호</td>
						<td width = "420" align = "center">내용</td>
					</tr>
				<%for(TalkVO vo : rl){%><tr>
					<td bgcolor ="hotpink"> <%=vo.getTalkNo()%> </td>
					<td bgcolor = "skyblue"> <%= vo.getContent() %> </td>
				</tr><%	
				}%></table>	
		<br/>
		<br/>
				
	<form method = "POST" action = "talk_add2.jsp">
		<textarea rows = "7" cols = "40" name = "content"></textarea>
		<br/><input type = "submit">
	
	</form>
<%= rl %>
</body>
</DOCTYPEhtml>

<talk_view_orange.jsp>

<%@ page contentType="text/html;charset=UTF-8" import="study3.Util, study3.TalkVO, java.util.*, java.sql.*" %>

<% String ctxPath = request.getContextPath();


	int roomNo = -1;
	String level = null;
	
    Cookie[] cks = request.getCookies();
    if(cks == null){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }

    for(int i=0;i<cks.length;i++){
        if(cks[i].getName().equals("level")){
            level = cks[i].getValue();
        }else if (cks[i].getName().equals("roomNo")){
            roomNo=Util.parseInt(cks[i].getValue());
        }
    }

    if(level == null || !level.equals("orange")){
        response.sendRedirect(ctxPath + "/talk_login.jsp");
        return;
    }
    
    
    List<TalkVO> rl = new ArrayList<TalkVO>();
   	Exception err = null;
   	
   	try{
   		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = DriverManager.getConnection(
			"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
   		String sql = "select * from talk_t where room_no = ? order by talk_no desc";
   		PreparedStatement stmt = conn.prepareStatement(sql);
   		stmt.setInt(1, roomNo);
   		ResultSet rs = stmt.executeQuery();
   		
   		while(rs.next()){
   			TalkVO vo = new TalkVO();
   			vo.setTalkNo(rs.getInt("talk_no"));
   			vo.setRoomNo(rs.getInt("room_no"));
   			vo.setContent(rs.getString("content"));
   			rl.add(vo);
   		}
   		
   		rs.close();
   		stmt.close();
   		conn.close();
   		
   	}catch(Exception e){
   		err = e;
   	}
   	
   	if(err != null){
   		response.sendRedirect(ctxPath + "/error.jsp");
   		return;
   	}%>
   
<!DOCTYPE html>
<body>
talk_view_apple.jsp

				<table border ="1" cellspacing = "0" cellpadding="8">
					<tr>
						<td width = "80" align = "center">번호</td>
						<td width = "420" align = "center">내용</td>
					</tr>
				<%for(TalkVO vo : rl){%><tr>
					<td bgcolor ="hotpink"> <%=vo.getTalkNo()%> </td>
					<td bgcolor = "skyblue"> <%= vo.getContent() %> </td>
				</tr><%	
				}%></table>	
		<br/>
		<br/>
<%= rl %>
</body>
</DOCTYPEhtml>

<jsp 문법>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="EUC-KR"
    isELIgnored = "true"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>

</head>
<body>

	${100 + 100 };
</body>
</html>

//${100 + 100}; 은 서버에서 동작하고 200이라는 결과를 만들어 내어서 응답에 포함시켰따고 봐야한다.

최근 jsp 에서는 간단한 연산을 - ${...} : EL Language 을 이용하여 할 수 있는 기술을 포함

 

-isELIgnored ="true" 가 설정되면 ${100 + 100 }은 EL이 아닌 단순 문자열로 인식한다(무시한다)

 

-실제로 html안은 복잡한 코드보다 단순한 코드가 훨씬 많다 
모든 작업을 EL로 처리가능하면 디자인 속도가 훨씬 빠를 것이다. 

-request.setAttribute 또는 session.setAttribute를 통해서 저장된 값은 키 값을 이용해서 EL에서 사용이 가능하다

정리 : session , request, application 3개 객체는 모두 
void setAttribute(String, Object),
Object getAttribute(String)
void removeAttribute(String) 을 지원한다

 

EL이 반응이 좋아서 확장한 기능인 jstl을 지원하게 되었다

-jstl : 태그를 사용하여 만든 언어

-> SGML 에서 태그를 처음 도입 => 문서를 전산화 할 수 있는 언어를 개발

-> MathML, MusicML, Postscript 등 파생된 서브셋이 엄청 많다 

-> pdf로 발전하여

-> XML, HTML,로 성공하였다

 

태그의 특징

- 최 외곽의 태그는 단 하나만 존재하야 한다

- 태그는 중첩해서 선언하지 않는다

- 속성은 시작태그에 선언한다

- 속성은 KEY = "VALUE" 또는 OR KEY = 'VALUE'

    => 단, ''안에 ''은 못온다

- 하나의 태그에서 속성은 두번 선언하지 않는다

- 시작태그가 있으면 반드시 끝 태그가 있다

 

 


파일업로드 

 

<web.xml>에 서블릿 등록

<servlet> <servlet-name>abcd9</servlet-name> <servlet-class>study3.FileUpServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>abcd9</servlet-name> <url-pattern>/fileup</url-pattern> </servlet-mapping>

 <Test122.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<body>

<!--  input type = "file" : 파일을 서버로 업로드 할 때 사용
이때 반드시 enctype = "multipart/form-data" 을 사용한다 

fileup 에 해당하는 서블릿은 cos.jar 파일의 MultipartRequest 를 이용하여 업로드를 처리하는 것이 일반적
-->
	<form method = "POST" action = "fileup" enctype = "multipart/form-data">
		<input type = "text" name = "title" size = "20">
		<input type = "file" name = "apple">
		<input type = "submit">
	</form>
</body>
</html>

<fileUpServlet.jsp>

package study3;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;

import java.io.InputStream;


public class FileUpServlet extends HttpServlet{
	private ServletContext application = null;
	

	@Override
	public void init(ServletConfig config) throws ServletException {
		application = config.getServletContext();
	}

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
			String l = process2(request);
			System.out.println(l);
	}
	
	/*request : 요청 , 브라우저에서 서버로 전달하는 개념
	 * request.getInputStream() 은 브라우저에서 서버로 전달되는 내용을 볼 수 있다
	 * 이 내용을 재구성하는 기능이 cos.jar 파일의 MultipartRequest 이다.
	 * .*/
	
	public String process(HttpServletRequest request) throws IOException{
		byte[] buf = new byte[1024];
		int len = 0;
		
		StringBuffer sb = new StringBuffer();
			
		InputStream in = request.getInputStream();
		
		while((len = in.read(buf)) != -1){
			sb.append(new String(buf, 0, len));
		}
		in.close();
		return sb.toString();

		
	}
	
	
	public String process2(HttpServletRequest request) throws IOException{
		
		//fileup 디렉터리의 실제 저장 위치(절대 경로) 값을 파악한다.
		String path = application.getRealPath("/WEB-INF/fileup");
		System.out.println(path);
		
		//cos.jar에서 제공되는 클래스
		//DefaultFileRenamePolicy :  이름이 겹칠 때 이름 바꿔서 올린다
		//따라서 올릴 때 이름과 서버에 올려진 이름이 다를 수 있따.
		MultipartRequest mpr = new MultipartRequest(
				request, path, 1024*1024*20, "UTF-8",
				new DefaultFileRenamePolicy());
		
		//업로드한 원래 파일이름
		String ofn = mpr.getOriginalFileName("apple");
		
		//중첩될 경우 이름을 바꾸어 저장하는 이름
		String fsn = mpr.getFilesystemName("apple");
		
		System.out.println(ofn +","+ fsn);
		
		//MultipartRequest 쓰면 request.getParameter 못쓴다. 
        // 대신 MultipartRequest 안의 getParameter 써야 한다.
     // 한글 처리도 내부에서 해주더라 !! ( "UTF-8"로 설정해서 
		String title = mpr.getParameter("title");
		System.out.print(title);
		
		System.out.print(path);
		return null;
		

	}
	

}

filedown

<web.xml>

<servlet> <servlet-name>abcd10</servlet-name> <servlet-class>study3.FileDownServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>abcd10</servlet-name> <url-pattern>/filedn</url-pattern> </servlet-mapping>

<Test123.jsp>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<body>
<!--  WEB-INF는 브라우저가 접근이 불가능하다 -->
	<a href = "WEB-INF/fileup/user.png">fileDown</a>
	<a href ="filedn?fsn=user.png">fileDown</a>
</body>
</html>

 

<fileDownServlet.jsp>

package study3;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FileDownServlet extends HttpServlet {

	   @Override
	   protected void service(HttpServletRequest request, HttpServletResponse response) 
	         throws ServletException, IOException {
	      
	      String fsn = request.getParameter("fsn");
	      String ofn = request.getParameter("ofn");
	      
	      if(ofn == null){
	    	  ofn = fsn;
	      }
	      
	      String path = request.getServletContext().getRealPath("/WEB-INF/fileup");
	      
	      
	      /*전송 이전에 어떤 성경의 정보를 전달할 지를 먼저 브라우저에 통보한다 
	       * application/octet-stream 과 같은 것을 MIME TYPE이라고한다
	       * 
	       * 주의 : 반드시 응답이 내보내기 전에 쓰여져야한다*/
	      response.setContentType("application/octet-stream");
	      response.setHeader("content-disposition", "attachment;filename=" + ofn);
	      
	      //서버에 보관중인 파일을 읽어서 브라우저로 내보내는 전송 프로그램
	      InputStream in= new FileInputStream(path +"\\"+ fsn);
	      OutputStream out = response.getOutputStream();
	      
	      byte[] buf = new byte[1024*4];
	      int len = 0;
	      
	      while((len = in.read(buf)) != -1){
	    	  out.write(buf,0,len);
	    	  out.flush();
	      }
	      
	      out.close();
	      
	      in.close();
	   
	   }

	}
반응형

'Language Study > Java' 카테고리의 다른 글

제주에서 자바_Week3_4  (0) 2019.08.11
##자바 헷갈리는 이론  (0) 2019.08.01
제주에서 자바_Week3_2  (0) 2019.07.30
제주에서 자바_Week3_1  (0) 2019.07.29
제주에서 자바_Week2_3  (0) 2019.07.25
반응형

1.방명록dao

 

2.서블렛의 한계

단점

-> 동기화 사용

package study3;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LikeServlet extends HttpServlet{

	int i = 0;
	
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println(this.toString());
		/*많은 사람들이 동시에 접속해도 동일한 문자열이 계속 찍힌다 -> 동일한 인스턴스가 재사용되고 있다.
		 * 메모리 관리에는 장점이다
		 * 한꺼번에 많이 들어와도 적게 메모리를 소모한다
		 * */
		PrintWriter out = response.getWriter();
		out.println("<html><body>");
		
		/*왜 synchronized ?
		 * 동시 요청 시 여러개의 쓰레드가 하나의 서블릿 인스턴스를 사용할 수 있다.*/
		synchronized(this){
			i = i+1;
			for(int i = 0 ; i < 20000; i ++){
				out.println(this.i);
				
			}
		}
	
		out.println("</body></html>");
		out.flush();
		out.close();
	}
}

 

 

3.서블렛 여러 기능

<ConfigServlet.java>

package study3;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ConfigServlet extends HttpServlet{

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("service");
		
		//컨텍스트 경로
		String l = request.getContextPath();
		System.out.println("getContextPath : "  + l);
		
		//ip 주소 다음 나오는 전체 경로
		String m = request.getRequestURI();
		System.out.println("getRequestURI : "  + m);
		
		//접속한 브라우저의 ip 주소값
		String n = request.getRemoteAddr();
		System.out.println("getRemoteAddr : "  + n);
		
		//접속한 브라우저와 운영체제 정보를 담은 문자열이 얻어진다
		//이것을 이용하여 모바일로 접근한 건지 컴으로 접근 한 건지 알수 있고 
		//모바일용 화면과 컴용 화면을 구분하여 제공할 수 도 있다.
		String o = request.getHeader("User-Agent");
		System.out.println("User-Agent : "  + o);
		

		/*getContextPath : /study3
		getRequestURI : /study3/config
		getRemoteAddr : 0:0:0:0:0:0:0:1
		User-Agent : Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; rv:11.0) like Gecko	*/
		
	}

	/*init
service
service
service
service -> 서블릿의 인스턴스는 재활용 된다. 
인스턴스는 재활용을 위해 내부적으로 적재된다 => init
적재되는 시점에 호출되는 함수가 init - 최초 요청 시 에만 호출된다.*/
	@Override
	public void init(ServletConfig config) throws ServletException {
//		String val = config.getInitParameter("apple");
//		System.out.println(val);
		
		/*WEB-INF 폴더의 절대 경로값을 얻어온다
		 * 브라우저가 접근 못하는 폴더가 업로드 파일을 놓기에 가장 적합
		 * 허락받고 (돈내고) 다운 받을 때 FileInputStream 으로 읽어 내보낸다
		 * FileInputStream : 절대 경로를 필요로한다
		 * getRealPath : 유용하게 쓰인다.*/
		ServletContext application = config.getServletContext();
		String path = application.getRealPath("/WEB-INF/");
		System.out.println(path);
		
//		System.out.println("init");
	}
	/*blabla
C:\workspace3\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\study3\WEB-INF\
service*/
}

<LikeServlet.java>

package study3;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LikeServlet extends HttpServlet{

	int i = 0;
	
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println(this.toString());
		/*많은 사람들이 동시에 접속해도 동일한 문자열이 계속 찍힌다 -> 동일한 인스턴스가 재사용되고 있다.
		 * 메모리 관리에는 장점이다
		 * 한꺼번에 많이 들어와도 적게 메모리를 소모한다
		 * */
		PrintWriter out = response.getWriter();
		out.println("<html><body>");
		
		/*왜 synchronized ?
		 * 동시 요청 시 여러개의 쓰레드가 하나의 서블릿 인스턴스를 사용할 수 있다.*/
		synchronized(this){
			i = i+1;
			for(int i = 0 ; i < 20000; i ++){
				out.println(this.i);
				
			}
		}
	
		out.println("</body></html>");
		out.flush();
		out.close();
	}
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
	<servlet>
		<servlet-name>abcd5</servlet-name>
		<servlet-class>study3.LikeServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>abcd5</servlet-name>
		<url-pattern>/like</url-pattern>
	</servlet-mapping>
	
	
	<servlet>
		<servlet-name>abcd6</servlet-name>
		<servlet-class>study3.ConfigServlet</servlet-class>
		<init-param>
			<param-name>apple</param-name>
			<param-value>blabla</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>abcd6</servlet-name>
		<url-pattern>/config</url-pattern>
	</servlet-mapping>
	
	
</web-app>
반응형

'Language Study > Java' 카테고리의 다른 글

##자바 헷갈리는 이론  (0) 2019.08.01
제주에서 자바_Week3_3  (0) 2019.07.31
제주에서 자바_Week3_1  (0) 2019.07.29
제주에서 자바_Week2_3  (0) 2019.07.25
제주에서 자바_Week2_2  (0) 2019.07.24
반응형

Day 1

 

1.아파치

아파치 소프트웨어 재단의 오픈소스 프로젝트. 일명 웹서버로 불리며, 클라이언트 요청이 왔을때만 응답하는 정적 웹페이지에 사용
  • 웹서버 = 80번 포트로 클라이언트 요청(POST,GET,DELETE)이 왔을때만 응답함.

  • 정적인 데이터만 처리한다.(HTML,CSS,이미지 등)

2.톰캣

dynamic(동적)인 웹을 만들기 위한 웹 컨테이너, 서블릿 컨테이너라고 불리며, 웹서버에서 정적으로 처리해야할 데이터를 제외한 JSP, ASP, PHP 등은 웹 컨테이너(톰캣)에게 전달한다.
  • WAS(Web Application Server)
  1. 컨테이너, 웹 컨테이너, 서블릿 컨테이너라고 부름
  2. JSP,서블릿처리,HTTP요청 수신 및 응답
  3. 아파치만 쓰면 정적인 웹페이지만 처리하므로 처리속도가 매우 빠르고 안정적이다.

<전반적인 서버 운영>

-톰캣 운영

C:\Users\USER>cd \

C:\>cd apa*

C:\apache-tomcat-8.0.45>cd bin

 

C:\apache-tomcat-8.0.45\conf\server.xml -> 8080 포트 => 8081 로 변경

 

C:\apache-tomcat-8.0.45\bin>startup.bat

 

-> ipconfig 후 ipv4 주소 + 8081  => http://192.168.2.95:8081/

 

  • web은 실제로 파일 다운로드 소켓 프로그램 기본과 같다
    • Client :  웹 브라우저
    • Server : 톰캣(Web Application Server : WAS) 

 

  • 브라우저 => 톰캣 접속 => 서버의 파일 다운받아 보여줌

 

  • 톰캣 서버 하나에는 여러개의 Web Application 이 설치 가능=> context
    • Context가 가져야 하는 것 : 홈 디렉터리, 접근 경로

   C:\StudyHome\ 생성 
   C:\StudyHome\WEB-INF\
   C:\StudyHome\WEB-INF\classes
   C:\StudyHome\WEB-INF\lib

 

클라이언트는 홈 디렉토리 아래의 모든 파일을 다운로드 가능하다

단, WEB-INF는 접근이 불가능하다(내부 설정파일 등을 놓는다)

 

classes : java class 파일을 놓는 곳

lib : 동작에 필요한 jar 파일을 놓는 곳

 

C:\StudyHome\WEB-INF>copy C:\apache-tomcat-8.0.45\webapps\ROOT\WEB-INF\web.xml
        1개 파일이 복사되었습니다.

-> WEB-INF 폴더에 web.xml 파일을 복사해 넣는다.

 

web.xml 이렇게 변경
http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  version="3.1"
  metadata-complete="true">

= >기본적인 Context 설정은 되어있다 

=> 이것을 톰캣에 등록해야한다.

 

다시

->C:\apache-tomcat-8.0.45\conf / server.xml에서 변경

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context docBase="C:\StudyHome" path="/study" reloadable="true"></Context>

-> 다시 C:\apache-tomcat-8.0.45\bin>startup.bat

 

->StudyHome/test.html 생성

<html>
    <body> HelloWorld : ^^*</body>
</html>

http://192.168.2.95:8081/study/test.html로 연결

 

흐름도

C:\StudyHome\apple\test.html로 복사

http://192.168.2.95:8081/study/apple/test.html

 

-docBase 디렉토리 하위 폴더의 파일은 폴더명을 경로명으로 바꾸어 접속 할 수있다

 

C:\StudyHome\WEB-INF\test.html로 복사

http://192.168.2.95:8081/WEB-INF/test.html

오류 !

-WEB-INF 는 특수한 의미를 갖는다
-> 브라우저에 공개치 않는다 

 

-javaWork 에 클래스를 만들어보자

C:\StudyHome>cd C:\JavaWork

 

HelloWorld2.java를 만들자

package apple;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import java.io.IOException;


public class HelloWorld2 extends HttpServlet{
public void service() throws IOException, ServletException{
}

}

C:\JavaWork>javac -d C:\StudyHome\WEB-INF\classes -classpath servlet-api.jar HelloWorld2.java

 

-HelloWorld2.java를 변경하자 -> 꼭 compile 하기!

-web.xml변경하자

<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <servlet> <servlet-name>abcd</servlet-name> <servlet-class>apple.HelloWorld2</servlet-class> </servlet> <servlet-mapping> <servlet-name>abcd</servlet-name> <url-pattern>/study01</url-pattern> </servlet-mapping> </web-app>

-다시 서버 돌려보자

http://192.168.2.95:8081/study/study01

 

<tomcat>

29-Jul-2019 12:19:34.131 정보 [main] org.apache.catalina.startup.Catalina.start Server startup in 2683 ms
HelloWorld2 

 

-HelloWorld2 다시 수정

package apple;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

public class HelloWorld2 extends HttpServlet {
@Override
   public void service( HttpServletRequest request, 
      HttpServletResponse response)
      throws IOException, ServletException 
      {
         System.out.println("HelloWorld2");
PrintWriter out = response.getWriter();
out.println(""); out.println("    ");
out.println("HelloWorld 2: T 0 T *");
out.println("    "); out.println("");


out.close();
      }
   }
   

-> 이러고 서버 닫았다가 다시 키면 홈페이지에 out.println("HelloWorld 2: T 0 T *");  찍힌다

 

WEB-INF 사용 연결 방식

-> 서블릭의 동작 흐름

0. WAS 쪽에 적절한 설정이 되어 있다고 가정

1. 브라우저에서 /study/study01 으로 요청이 들어온다

2. /study 로 경로를 설정한 Context 있나?

3. 2.에서 찾은 contetxt 의 docBase 폴더 (C:\StudyHome) 아래의 /WEB-INF/web.xml찾음

4. url-pattern 중 / study01에 해당하는 설정 -> servlet-mapping 아래에 -> 서블릿 abcd라는 것을 지명하고 있음
    -서블릿은 서버쪽에서 동작하는 것

5. abcd로 이름 붙여진 서블릿 클래스가 있나? apple.HelloWorld2

6. apple.HelloWorld2 을 찾아 -> 인스턴스 생성 -> 오버라이딩 하는 service 함수호출한다

7. System.out.println ("HelloWorld2"); 은 서버쪽에서 찍힌다.

8. PrintWriter out = response.getWriter(); 를 이용하여 내보내는 것은 요청으로 들어온 브라우저 쪽으로 내보내진다

9. 요청했던 브라우저는 응답으로 전달된 내용을 받아 화면에 출력한다

 

<HelloWorld2.java> 변경한다
package apple;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

public class HelloWorld2 extends HttpServlet {
@Override
   public void service( HttpServletRequest request, 
      HttpServletResponse response)
      throws IOException, ServletException 
      {
         System.out.println("HelloWorld2");
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
}
catch(Exception e){
//에러가 난 정보를 역추적해서 출력해준다
e.printStackTrace();
}


PrintWriter out = response.getWriter();
out.println(""); out.println("    ");
out.println("HelloWorld 2: T 0 T *");
out.println("    "); out.println("");


out.close();
      }
   }
   

-ojdbc.jar => 현재 컴파일 하고 있는 StudyHome > WEB-INF > lib 폴더 안에 복사 붙여넣기 

   -> oracle db와 톰캣을 함께 사용할 수 있게 된다.

 

<HelloWorld2.java> 또 바꿔..

 

package apple;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;


public class HelloWorld2 extends HttpServlet {
@Override
   public void service( HttpServletRequest request, 
      HttpServletResponse response)
      throws IOException, ServletException 
      {
         System.out.println("HelloWorld2");
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn= DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
System.out.println(conn);
conn.close();
}
catch(Exception e){
e.printStackTrace();
}


PrintWriter out = response.getWriter();
out.println(""); out.println("    ");
out.println("HelloWorld 2: T 0 T *");
out.println("    "); out.println("");


out.close();
      }
   }
   

-> 컴파일 하고 서버 돌리면 톰캣에 요렇게 찍힘

Context.reload Reloading Context with name [/study] is completed
HelloWorld2
oracle.jdbc.driver.T4CConnection@6b77a082
package apple;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.*;

public class HelloWorld2 extends HttpServlet {
@Override
   public void service( HttpServletRequest request, 
      HttpServletResponse response)
      throws IOException, ServletException 
      {
         System.out.println("HelloWorld2");
String theTime = null;
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn= DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");

Statement stmt = conn.createStatement();
String sql = "SELECT SYSDATE FROM DUAL";
ResultSet rs = stmt.executeQuery(sql);

if(rs.next()) {
theTime = rs.getString(1);
}
rs.close();

stmt.close();
conn.close();
}
catch(Exception e){
e.printStackTrace();
}


PrintWriter out = response.getWriter();
out.println(""); out.println("    ");
out.println("HelloWorld 2: T 0 T *" + theTime);
out.println("    "); out.println("");


out.close();
      }
   }
   

-> 이렇게하고 서버 실행하면 

HelloWorld 2: T 0 T *2019-07-29 14:28:26.0

<이클립스 다이나믹 프로젝트>

-프로젝트 -> context로 인식 -> src를 서버와 연결(add and remove) -> xml 변경 후


<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <servlet> <servlet-name>abcd</servlet-name> <servlet-class>study2.HelloWorld3</servlet-class> </servlet> <servlet-mapping> <servlet-name>abcd</servlet-name> <url-pattern>/study2</url-pattern> </servlet-mapping> </web-app>

-> .java에서 Run as tomcat 서버로 돌리면 완성

 

<HelloWorld3.java>

 

package study2;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloWorld3 extends HttpServlet {

   @Override
   public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      // TODO Auto-generated method stub

      List ls = new ArrayList();
      try {
         Class.forName("oracle.jdbc.driver.OracleDriver");
         Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521/XE", "HR", "HR");
         Statement stmt = conn.createStatement();
         String sql = "SELECT no, gul, THE_THIME FROM bangmyung_t";
         ResultSet rs = stmt.executeQuery(sql);

         while (rs.next()) {
            BangMyungVO vo = new BangMyungVO();
            vo.setNo(rs.getInt(1));
            vo.setGul(rs.getString(2));
            vo.setTheTime(rs.getString(3));
            ls.add(vo);
         }
         rs.close();
         stmt.close();
         conn.close();
      } catch (Exception e) {
         e.printStackTrace();
      }
      response.setContentType("text/html; charset=euc-kr");
      PrintWriter out = response.getWriter();
      out.println("");       out.println("   ");
      for (BangMyungVO vo : ls) {
         out.println(vo.getNo() + "\t" + vo.getGul() + "\t" + vo.getTheTime());
      }
      out.println("   ");       out.println("");
      out.close();
   }

}
<BangMyungVO.java>

package study2;

public class BangMyungVO {
public Integer getNo() {
return no;
}
public void setNo(Integer no) {
this.no = no;
}
public String getGul() {
return gul;
}
public void setGul(String gul) {
this.gul = gul;
}
public String getTheTime() {
return theTime;
}
public void setTheTime(String theTime) {
this.theTime = theTime;
}
private Integer no = null;
private String gul = null;
private String theTime = null;
}

<test_01.html>


<!DOCTYPE html> <head> <body> test_01.html <!-- cellspacing="0" : 셀 간 간격 cellpadding="12" : 셀의 벽과 내용과의 간격 border="1" : 경계줄의 굵기 bgcolor="#ccddee" 배경색, 각각 16진수이고 앞 두자리 : red, 다음 두자리 : green, 마지막 두자리 : blue => RGB 값을 섞은 값 rowspan="3", colspan="2" : 엑셀에서의 셀 병합과 같은 개념 rowspan은 상하, colspan은 좌우 셀과 병합한다. <font size = "20px" face = "Impact">apple</font> : 브라우저에 깔린 글꼴만 가능 align ="left| center | right" : 내용물의 좌우 정렬 속성을 정한다 width : 셀의 폭을 결정함 같은 오와 열에 있는 것들은 자동으로 지정된 크기에 맞춰진다(일일이 모든 칸에 크기를 줄 필요가 없다) --> <table border="0" cellspacing="2" cellpadding="12"> <tr bgcolor="#aabbcc"> <td width = "400px" rowspan="2"><font size = "20px" face = "Impact">apple</font></td> <td width = "250px">banana</td> </tr> <tr> <td bgcolor="#ccddee">kiwi</td> </tr> <tr> <td colspan="2" bgcolor="#ccddee" align="center">kiwi</td> </tr> </table> </body> </html>



apple banana
kiwi
kiwi



 

반응형

'Language Study > Java' 카테고리의 다른 글

제주에서 자바_Week3_3  (0) 2019.07.31
제주에서 자바_Week3_2  (0) 2019.07.30
제주에서 자바_Week2_3  (0) 2019.07.25
제주에서 자바_Week2_2  (0) 2019.07.24
제주에서 자바_Week2_1  (0) 2019.07.22
반응형

Day 4

1. Thread(스레드)

  • 하나의 프로세스 내부에서 독립적으로 실행되는 하나의 작업 단위를 말하며,
  • 세부적으로는 운영체제에 의해 관리되는 하나의 작업 혹은 태스크
  • 스레드와 태스크(혹은 작업)은 바꾸어 사용해도 무관
  • 스레드 구현 방법 : 1. 스레드 이용  / 2. Runnable 이용하는 방법
JVM에 의해 하나의 프로세스가 발생하고 main( ) 안의 실행문 들이 하나의 스레드
main( ) 이외의 또 다른 스레드를 만들려면 Thread 클래스를 상속하거나 Runnable 인터페이스를 구현
다중 스레드 작업 시에는 각 스레드 끼리 정보를 주고받을 수 있어 처리 과정의 오류를 줄일 수 있음
프로세스끼리는 정보를 주고받을 수 없음

 

package Lecture.Week2;

//외우기
class CustomThreaded implements Runnable{
    //implements 받아오려면 runaable을 오버라이딩 해줘야 한다. / 오버라이딩 시 throws exception 같은 것은 붙일 수 없다.
    @Override
    public void run() {
        for(int i = 0; i < 100; i++){
            System.out.println("HelloWorld" + i);
        }
    }

}
    public class Test12 {
        public static void main(String[] args){
            //단순한 함수 호출
            Runnable rb = new CustomThreaded();
            rb.run();

            /*new Thread를 하면 가상의 cpu를 OS에서 할당한다. (분신)
            //할당받은 CPU는 생성자에 넘겨진 포인터를 물고 간다.
            start() 호출 : 준비과정을 거쳐 새로운 가상 CPU가 rb.run()을 호출한다.

            1. Runnable  상속받은 클래스 선언
            2. new Thread 하면서 1의 인스턴스의 포인터를 넘긴다
            2. Thread::start() 를 호출하면 가상 CPU(쓰레드) 가 run()을 호출*/
            Thread th = new Thread(rb); //thread의 참조형 변수
            th.start(); //이걸 해야 돌아감
        }
}

2. 프로세스 ,프로그램, 스레드

  • 프로세스 : 데이터(data) + 자원(memory) + 쓰레드(Thread) 로 구성(a running program)
  • 프로그램 : executable file
  • 스레드 : a light-weighted process (독자 행동을 하지만 조금 다르다)
    • 스레드는 프로세스 안에서만 존재가 가능하다
    • 스레드 간 메모리를 공유할 수 있다
    • 프로세스 간 메모리 전달은 가능해도 공유는 불가능하다
    • 프로세스간의 메모리 전달의 대표적 수단이 소켓이다(복사 & 붙이기도 전달로 볼 수 있지만 이건 윈도우에서 국한된 개념)
    • 프로세스 종료 == 프로세스가 가진 모든 쓰레드의 종료
    • start() : 이 스레드가 실행을 시작하도록 함-> 가상 머신 run이 thread의 메소드를 호출한다
    • run() : 이 스레드가 별도의 Runnable 실행 객체를 사용하여 작성한 경우 해당 runnable 객체의 run 메소드 호출
      그렇지 않을 경우 , 이 메서드는 아무것도 수행하지 않고 반환함.
package Lecture.Week2;
class Toilet{
    public void bigWork(String by){
        System.out.println("Step1," + by);
        System.out.println("Step2," + by);
        System.out.println("Step3," + by);
        System.out.println("Step4," + by);
        System.out.println("Step5," + by);

    }
}

/*참조형 : 오른쪽이 가르키는 대상을 왼쪽이 가르친다.
* 멤버변수 : 인스턴스 만들어진 시점에 생성*/


class A implements Runnable{
    private Toilet toilet = null;

    public A(Toilet t){
        toilet = t;
    }

    public void run(){
        for(int i = 0; i < 100;){
//            System.out.println("APPLE");
            toilet.bigWork("APPLE");
            try{
                int time = (int)(Math.random() *1000); //초 단위로 쉬게 하기
                Thread.sleep(time); //try  catch 필요
            }
            catch (InterruptedException e){}
        }
    }
}


class B implements Runnable{
    private Toilet toilet = null;

    public B(Toilet t){
        toilet = t;
    }

    public void run(){
        for(int i = 0; i < 100;){
//            System.out.println("BANANA");
            toilet.bigWork("BANANA");

            try{
                int time = (int)(Math.random() *1000); //초 단위로 쉬게 하기
                Thread.sleep(time); //try  catch 필요
            }
            catch (InterruptedException e){}
        }
    }
}
public class Test13 {
    public static void main(String[] args){
        Toilet t = new Toilet();
        new Thread( new A(t)).start(); //RUNNABLE에서 implements 받은 A의 인스턴스를 생성자에 넣어주고 START
        new Thread( new B(t)).start();
    }
}
/*쓰레드는 독자적으로 돌아가는 프로그램이 된다
* APPLE 과 BANANA 끼어들게 안 짯는데도 결과 가 나옴
* APPLE
BANANA
BANANA
APPLE
BANANA
BANANA
APPLE
BANANA
BANANA
BANANA....
*/

결과 :

Step1,APPLE
Step1,BANANA
Step2,APPLE
Step2,BANANA
Step3,BANANA
Step3,APPLE
Step4,BANANA
Step4,APPLE
Step5,BANANA
Step5,APPLE


* > 아무런 제약이 없다면 이렇게 동시 진행될 수도 있다
* 쓰레드는 독자적이기 떄문에 일어나는 현상
* -> 화장실 문을 잠가야 하니까 

=> 그것을 동기화(Synchronization)이라고 한다.

 

class Toilet{
    public void bigWork(String by){
        synchronized (this) { //this : 참조형 변수 (자기 자신에 대한)
            System.out.println("Step1," + by);
            System.out.println("Step2," + by);
            System.out.println("Step3," + by);
            System.out.println("Step4," + by);
            System.out.println("Step5," + by);
        }
    }
}

 

-모든 인스턴스에는 lock이라는 개념의 자물쇠? 열쇠?가 있다

-synchronized (this) => this가 가리키는 인스턴스가 가지고 있는 록을 획득해야 { .. 에 진입 가능

  획득하지 못하면 쓰레드는 멈추어 기다려야 한다. 

   }로 일을 마쳤으면 lock을 반납한다.

-이런 방법으로 공유하는 메모리에서 작업 도중 끊기는 일을 막을 수 있다. 

 

 

-스레드 조인  / run

package Lecture.Week2;


class A1 implements Runnable{
    public void run(){
        for(int i = 0; i <10; i++){
            System.out.println("A running");
        }
    }
}

class B1 implements Runnable{
    public void run(){
        for(int i = 0; i <10; i++){
            System.out.println("B running");
        }
    }
}

class C1 implements Runnable{
    public void run(){
        for(int i = 0; i <10; i++){
            System.out.println("C running");
        }
    }
}


public class Test14 {
    public static void main(String[] args){
        Thread[] threads = new Thread[3];

        threads[0] = new Thread(new A1());
        threads[1] = new Thread(new B1());
        threads[2] = new Thread(new C1());

        threads[0].start();
        threads[1].start();
        threads[2].start();

        try{
            threads[0].join(); //threads[0]이 끝나기전에는 내려가지 않는다.
            threads[1].join();//join()메소드는 쓰레드가 멈출때까지 기다리게 한다.
            threads[2].join();
        }//모든 쓰레드들이 다 끝나고 난 다음에 최종정리가 찍힌다.
        catch (InterruptedException e){}
//        new Thread(new A1()).start();
//        new Thread(new B1()).start();
//        new Thread(new C1()).start();

        System.out.println("최종정리");
    }
}

3. 자바 - DB 연동

줄 건다 -> 바구니 건다 -> 바구니에 물건 담는다 -> 왕복한다 -> 바구니 내린다 -> 줄 내린다

conn 형성 -> stmt 형성 -> 쿼리 작업 -> stmt.close() -> conn.close()

 

Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/study","root","1111");

Statement stmt = conn.createStatement();//바구니 만든다

String sql = "insert into studentt values ('10107', '또오치','쌍문동')"; //바구니에 담는다

stmt.executeUpdate(sql2);//쿼리 실행-> sql문 실어서 간다

stmt.close(); //바구니 내린다

conn.close(); //줄 푼다.

<전체 코드>

package Lecture.Week2;

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

public class Test15 {
    public static void main(String[] args) throws Exception{
        Class.forName("com.mysql.jdbc.Driver");
        /*Connection은 mysql에 소켓으로 접속하는 것과 관계가 깊음
        * study : 데이터베이스 명
        * root  / 1111 : 계정 및 암호
        * 127.0.0.1 : 네트워크 카드 밖으로 나가지 않고 나에게 접속할 때
        * Statement는 바구니라고 생각하면 된다. */
        Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/study","root","1111");
        //소켓을 이용해서 접속한다-> 줄 단다
        //db 연결

//        System.out.println(conn.toString());
            //connection 객체에 의해 프로그램에 리턴되는 객체에 의해 구현되는 일종의 메소드 집합
        Statement stmt = conn.createStatement();//바구니 건다
        String sql = "insert into studentt values ('10107', '또오치','쌍문동')";
        String sql2 = "delete from studentt where stid = '10107'";
        String sql3 = "update studentt set addr = '이도동' where stid = '10101'";

        stmt.executeUpdate(sql2);//쿼리 실행-> sql문 실어서 간다

        stmt.close(); //바구니 내린다
        conn.close(); //줄 푼다.

        /*Connection : IP, PORT, ID, PWD  -> 줄
        * Statement : SQL, 결과 -> 바구니
        * -> SQL로 -> RETURN 받아 -> STATEMENT.close() (바구니 먼저 내리고) -> CONNECTION.close() (줄 마지막으로 내리고)
        * executeUpdate : 함수의 리턴값은 변경된 레코드 개수 -> select는 레코드를 변경하지 않기 때문에 executeUpdate는 inser/delete/update문장에 사용한다
         */
 }
}

//java -classpath .;mysql-connector-java-5.0.8-bin.jar Test15
package Lecture.Week2;

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

public class Test16 {
    public static void main(String[] args) throws Exception {
        /*static {
            //클래스가 로딩되는 시점에 호출

            /*connection , statement 모두 인터페이스다
            * DriverManager, getConnection 안에서 Connection 상속받은 모종의 클래스의 인스턴스를 리턴한다.
            * -> Mysql에 접속할 수 있는 기능을 구현하고 있다.        }*/

        Class.forName("com.mysql.jdbc.Driver"); //모종의 클래스 세팅하는 코드
        Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/study","root","1111");
//        System.out.println(conn.getClass().getName()); // conn이 어디 클래스에서 가져오나 찍어보는 것 -> com.mysql.jdbc.Connection
        Statement stmt = conn.createStatement(); //바구니 생성
//
        String sql = "select stid,name,addr from studentt";
        ResultSet rs = stmt.executeQuery(sql);

        while (rs.next()){
            String stid = rs.getString("stid");
            String name = rs.getString("name");
            String addr= rs.getString("addr");
            System.out.println(stid + "\t" + name +"\t" +addr);
        }
        rs.close();

        stmt.close();
        conn.close();

    }
}

///암기 하자

-select문에 정보들어가서 바구니에 담긴 걸 : CURSOR이라고 한다. -> 서버 쪽이라서 서버사이드 커서 

-쿼리에서 정보로 넘어갈 때 한 튜플을 채우고 그 밑으로 내려가면서 채운다 

Stid name
←   ↓
←   ↓
←   ↓
←   ↓

 

 

4. O-R Mapping 규칙(Golden Rule, Rule of Thumb)

  • ResultSet 은 CURSOR(select 결과)에 접근 가능한 정보
  • CURSOR는 서버에 생긴다
  • Connection 이 닫인 다음에서는 ResultSet은 사용 불가하다
    (Connection 닫기 전에 사용 끝나야 한다)
    -> connection은 비싼고 제한적인 지원이다
    -> 접속 후에 빨리 끊어주는게 바람직 하다 (콜 센터 연상)

<ArrayList 사용>

package Lecture.Week2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

class StudentV0{
    /*property : 멤버 변수 -> public으로 열지 않는다.
    -> 대신에 getter , setter을 사용해 가져온다
    -> private 하게 선언 해야한다.*/
    private String stId = null;
    public String getStId(){ return stId;}
    public void setStId(String i){ stId = i;}

    private String name = null;
    public String getName(){ return name;}
    public void setName(String i){ name = i;}

    private String addr = null;
    public String getAddr(){ return addr;}
    public void setAddr(String i){ name = i;}
}




public class Test17{
    public static void main(String[] args) throws Exception {

        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/study","root","1111");
        Statement stmt = conn.createStatement(); //바구니 생성

        /*O-R Mapping 규칙(Golden Rule, Rule of Thumb)

        Field => property
        * table -> class
        * record => instance*/
        //connection은 살아있을때 할거 다해야 하고 / 빨리 끊어야한다 -> 아래 코드에서 이상적으로 구현

        //왜 arrayList 일까? -> 중간 삽입삭제가 필요없고 쌓기만 하는거니까 속도가 빠른 ArrayList
        //VO : Value Object : 값을 담는 객체
        /*테이블 구조와 동일하게 레코드 하나를 인스턴스에 담을 수 있는 역할
        *
        *  DTO : DATA TRANSFER OBJECT
        * Entity 등을 사용하는 경우도 있는데 실은 다 같은 얘기*/
        List<StudentV0> rl = new ArrayList<StudentV0>();

        String sql = "select stid,name,addr from studentt";
        ResultSet rs = stmt.executeQuery(sql);

        while (rs.next()){
            StudentV0 vo = new StudentV0(); //-> 하나의 인스턴스로 만들어 버림
            vo.setStId(rs.getString("stid"));
            vo.setName(rs.getString("name"));
            vo.setAddr(rs.getString("addr"));
            rl.add(vo);
        }
        rs.close();

        stmt.close();
        conn.close();
        //conn.close()이후에도 LIST 안에는 결과가 담겨 있다.
        for(StudentV0 vo : rl){
            System.out.println(vo.getStId() + "\t" + vo.getName() + "\t" + vo.getAddr());
        }
    }
}

<Oracle DB 연동>

package Lecture.Week2;

//import java.sql.Connection;
//import java.sql.DriverManager;
import java.sql.*;

public class Test18 {
    public static void main(String[] args) throws Exception {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
        System.out.println(conn.getClass().getName());
        /*oracle.jdbc.driver.T4CConnection -> connection은 인터페이스 -> 모종의 클래스(T4C)를 상속받아 사용 -> 오로지 오라클에서만 사용가능
          2019-07-25 17:23:23.0

          MYSQL과 코드가 거의 틀린점이 없다
          Connection, Statement 를 상속한 ORACLE 과 연동 가능한 클래스를 OracleDriver에서 DriverManager에 세팅해주면 Oracle에 맞추어
          개발된 , Connection Statement ResultSet 등을 상속받은 클래스가 공급되는 구조
         */

        Statement stmt = conn.createStatement();
        //현재 시간 - MYSQL : now() / ORACLE : SYSDATE
        String sql = "SELECT SYSDATE FROM DUAL";
        ResultSet rs = stmt.executeQuery(sql);
        //결과 레코드가 하나인 경우에는 while 대신에 if문 사용한다.
        if (rs.next()){
            //필드명 대신에 숫자 가능 / 1은 나열된 펏번째 필드를 의미
            String l = rs.getString(1); //첫번째 필드 얘기
            System.out.println(l);
        }

        rs.close();
        stmt.close();

        conn.close();
    }
}

 

Day 5

  1. ORACLE
SQL> conn hr/hr;
연결되었습니다.
SQL> CREATE TABLE STUDY01t(
  2  ID NUMBER(3),
  3  DATA VARCHAR2(10)
  4  );
SQL> INSERT INTO STUDY01t VALUES (100, 'HelloWorld');

-오라클 숫자 : NUMBER(3) -최대 3자리 숫자

-VARCHAR2 : 오라클에서 만든 속도가 조금 빠른 VARCHAR

 

SQL> CREATE TABLE STUDY11t(
  2  ID NUMBER(5),
  3  DATA CHAR(10)
  4  );
SQL> CREATE SEQUENCE seq_study11t;

시퀀스가 생성되었습니다.
SQL> insert into study11t values(seq_study11t.NEXTVAL, 'apple');

-오라클은 mysql은 일련번호가 만드는 방법이 다르다

:mysql : auto_increment primary key를 썼다

 

SQL> SELECT ID, DATA || '*' FROM STUDY11t;
:mysql 의 concat과 동일한 기능을 수행한다.
//char여서 조금 더 떨어져 있음 (|| 공백처리)
//CHAR(10)으로 선언한 필드에 'apple'을 넣으면 'apple       '이 된다
//mysql은 그냥 'apple'이 된다

        ID DATA||'*'
---------- ----------------------
         1 apple     *
         2 apple     *
         3 apple     *
         4 apple     *
SQL> SELECT ID, TRIM(DATA) || '*' FROM STUDY11t;
//TRIM() : 좌/우 공백 문자를 제거하는 역할을 한다

        ID TRIM(DATA)||'*'
---------- ----------------------
         1 apple*
         2 apple*
         3 apple*
         4 apple*
SQL> CREATE TABLE Study12t(
  2  THE_TIME DATE
  3  );
SQL> INSERT INTO STUDY12t VALUES(SYSDATE);
SQL> SELECT * FROM STUDY12T;

THE_TIME
--------
19/07/26
SQL> SELECT TO_CHAR(THE_TIME) FROM STUDY12T;

TO_CHAR(THE_TIME
----------------
19/07/26
19/07/26
19/07/26

SQL> SELECT TO_CHAR(THE_TIME,'YYYY-MM-DD') FROM STUDY12T;

TO_CHAR(THE_TIME,'YY
--------------------
2019-07-26
2019-07-26
2019-07-26

//ORACLE 날짜 시간은 DATE자료형을 사용한다

//현재 시간은 SYSDATE를 이용한다

//보여지는 형식은 TO_CHAR을 이용하여 형식을 지정하면 된다.

 

SQL> SELECT TO_CHAR(THE_TIME,'YYYY-MM-DD HH24:MI:SS') FROM STUDY12T;

TO_CHAR(THE_TIME,'YYYY-MM-DDHH24:MI:SS
--------------------------------------
2019-07-26 11:52:54
2019-07-26 11:53:30
2019-07-26 11:53:32

Q. 역삼동 사는 학생들의 국어점수와 STID를 서브쿼리로?

SQL> SELECT * FROM SCORET WHERE STID IN (SELECT STID FROM STUDENTT WHERE ADDR LIKE '%역삼%') AND SUBID = 'KOR1';

STID       SUBID         SCORE
---------- -------- ----------
10101      KOR1             60
10103      KOR1             70

Q. 학생별 평균점수를 GROUP BY로 구하기(GROUP BY 에서 지정한 컬럼은 SELECT 절에서 쓸 수 있다)

 

SQL> SELECT STID, AVG(SCORE) FROM SCORET GROUP BY STID;

STID       AVG(SCORE)
---------- ----------
10104      73.3333333
10101      76.6666667
10102      93.3333333
10103      76.6666667
10105      63.3333333
10106      66.6666667

#INNER JOIN

SQL> SELECT * FROM STUDENTT INNER JOIN SCORET ON STUDENTT.STID = SCORET.STID; 
= SQL> SELECT * FROM STUDENTT, SCORET WHERE STUDENTT.STID = SCORET.STID; //조금 더 직관적


STID       NAME               ADDR               STID       SUBID         SCORE
---------- ------------------ ------------------ ---------- -------- ----------
10101      홍길동             역삼동             10101      KOR1             60
10101      홍길동             역삼동             10101      ENG1             80
10101      홍길동             역삼동             10101      MAT1             90
10102      고길동             개포동             10102      KOR1             90
10102      고길동             개포동             10102      MAT1             90
10102      고길동             개포동             10102      ENG1            100
10103      이기자             역삼동             10103      KOR1             70
10104      박기자             한남동             10104      KOR1             80
10105      김영삼             홍제동             10105      KOR1             50
10106      김대중             한남동             10106      KOR1             60
10103      이기자             역삼동             10103      ENG1             90

STID       NAME               ADDR               STID       SUBID         SCORE
---------- ------------------ ------------------ ---------- -------- ----------
10104      박기자             한남동             10104      ENG1             70
10105      김영삼             홍제동             10105      ENG1             60
10106      김대중             한남동             10106      ENG1             80
10103      이기자             역삼동             10103      MAT1             70
10104      박기자             한남동             10104      MAT1             70
10105      김영삼             홍제동             10105      MAT1             80
10106      김대중             한남동             10106      MAT1             60

# OUTER JOIN 

SQL> SELECT * FROM SUBJECTT LEFT OUTER JOIN SCORET
  2  ON SUBJECTT.SUBID = SCORET.SUBID;

SUBID    NAME               STID       SUBID         SCORE
-------- ------------------ ---------- -------- ----------
KOR1     국어1              10101      KOR1             60
ENG1     영어1              10101      ENG1             80
MAT1     수학1              10101      MAT1             90
KOR1     국어1              10102      KOR1             90
MAT1     수학1              10102      MAT1             90
ENG1     영어1              10102      ENG1            100
KOR1     국어1              10103      KOR1             70
KOR1     국어1              10104      KOR1             80
KOR1     국어1              10105      KOR1             50
KOR1     국어1              10106      KOR1             60
ENG1     영어1              10103      ENG1             90

SUBID    NAME               STID       SUBID         SCORE
-------- ------------------ ---------- -------- ----------
ENG1     영어1              10104      ENG1             70
ENG1     영어1              10105      ENG1             60
ENG1     영어1              10106      ENG1             80
MAT1     수학1              10103      MAT1             70
MAT1     수학1              10104      MAT1             70
MAT1     수학1              10105      MAT1             80
MAT1     수학1              10106      MAT1             60
PHY1     물리
SQL> SELECT * FROM SUBJECTT, SCORET
  2  WHERE SUBJECTT.SUBID = SCORET.SUBID(+);

SUBID    NAME               STID       SUBID         SCORE
-------- ------------------ ---------- -------- ----------
KOR1     국어1              10101      KOR1             60
ENG1     영어1              10101      ENG1             80
MAT1     수학1              10101      MAT1             90
KOR1     국어1              10102      KOR1             90
MAT1     수학1              10102      MAT1             90
ENG1     영어1              10102      ENG1            100
KOR1     국어1              10103      KOR1             70
KOR1     국어1              10104      KOR1             80
KOR1     국어1              10105      KOR1             50
KOR1     국어1              10106      KOR1             60
ENG1     영어1              10103      ENG1             90

SUBID    NAME               STID       SUBID         SCORE
-------- ------------------ ---------- -------- ----------
ENG1     영어1              10104      ENG1             70
ENG1     영어1              10105      ENG1             60
ENG1     영어1              10106      ENG1             80
MAT1     수학1              10103      MAT1             70
MAT1     수학1              10104      MAT1             70
MAT1     수학1              10105      MAT1             80
MAT1     수학1              10106      MAT1             60
PHY1     물리

-> 오라클용 아우터 조인 문법

-NULL 값으로 채워지는 일이 발생하는 쪽에 + 표시 붙인다.

 

-INNER JOIN ON , OUTER JOIN ON => 국제 표준 SQL

-각 DB별로 변형 SQL을 탑재 

-ORCLE 의 변형방법을 다른 DB 업체들이 따라하기도 하고 

-오라클만 쓴느 사람들은 오라클의 방법만 고집하는 경우가 많다

 

SQL> SELECT STID, AVG(SCORE) AS AVG FROM SCORET GROUP BY STID;

STID              AVG
---------- ----------
10104      73.3333333
10101      76.6666667
10102      93.3333333
10103      76.6666667
10105      63.3333333
10106      66.6666667
SQL> SELECT * FROM (SELECT STID, AVG(SCORE) AS AVG FROM SCORET GROUP BY STID);

STID              AVG
---------- ----------
10104      73.3333333
10101      76.6666667
10102      93.3333333
10103      76.6666667
10105      63.3333333
10106      66.6666667
SQL> SELECT X.STID, X.AVG FROM (SELECT STID, AVG(SCORE) AS AVG FROM SCORET GROUP BY STID) X; //테이블 별칭 줄때 AS를 사용하지 않는다.
//MYSQL에서는 쓰인다.


STID              AVG
---------- ----------
10104      73.3333333
10101      76.6666667
10102      93.3333333
10103      76.6666667
10105      63.3333333
10106      66.6666667
SQL>  SELECT x.stid, x.AVG FROM (
  2     SELECT stid, AVG( score ) AS AVG
  3     FROM scoret GROUP BY stid) x;

STID              AVG
---------- ----------
10104      73.3333333
10101      76.6666667
10102      93.3333333
10103      76.6666667
10105      63.3333333
10106      66.6666667

6 개의 행이 선택되었습니다.
SQL>  SELECT y.name, x.AVG FROM (
  2     SELECT stid, AVG( score ) AS AVG
  3     FROM scoret GROUP BY stid) x , studentt y WHERE x.stid = y.stid ;

NAME                      AVG
------------------ ----------
박기자             73.3333333
홍길동             76.6666667
고길동             93.3333333
이기자             76.6666667
김영삼             63.3333333
김대중             66.6666667

Constraint in Oracle

-primary key , foreign key, check, unique, not null

 

SQL> ALTER TABLE STUDENTT ADD CONSTRAINT PK_STUDENTT_STID PRIMARY KEY (STID);

테이블이 변경되었습니다.

-참조 무결성 : FK 쪽에는 PK에 없는 데이터는 존재하면 안된다

SQL> ALTER TABLE SCORET ADD CONSTRAINT FK_SCORET_STID
      2  FOREIGN KEY(STID) REFERENCES STUDENTT (STID);
SQL> DELETE FROM STUDENTT WHERE STID = '10101';
DELETE FROM STUDENTT WHERE STID = '10101'
*
1행에 오류:
ORA-02292: 무결성 제약조건(HR.FK_SCORET_STID)이 위배되었습니다- 자식 레코드가
발견되었습니다
SQL> ALTER TABLE SCORET ADD CONSTRAINT CH_SCORET_SCORE
  2  CHECK (SCORE >= 0 AND SCORE <= 100);

테이블이 변경되었습니다.

SQL> ALTER TABLE SUBJECTT ADD CONSTRAINT UQ_SUBJECT_SUBID
  2  UNIQUE (SUBID);

테이블이 변경되었습니다.
SQL> INSERT INTO SUBJECTT VALUES(NULL, '없음0');

-> NULL 값의 중복은 허용한다

SQL> INSERT INTO SUBJECTT VALUES('KOR1', '없음0');
INSERT INTO SUBJECTT VALUES('KOR1', '없음0')
*
1행에 오류:
ORA-00001: 무결성 제약 조건(HR.UQ_SUBJECT_SUBID)에 위배됩니다

왜? NOT NULL은 보장안함  / NO DUPLICATE 는 보장 

 

 권장사항 : constraint 는 테스트 끝나고서 ,,,,
         ( 회원가입 담당자가 일 다 안한 상태에서 게시판 담당자가 테스트 하려면? 절레절레)
 
-- constraint 지우기(제약 걸어있을 시 순서대로)

SQL> ALTER TABLE subjectt DROP CONSTRAINT uq_subject_subid;

테이블이 변경되었습니다.

SQL>
SQL> ALTER TABLE scoret DROP CONSTRAINT fk_scoret_stid;

테이블이 변경되었습니다.

SQL>
SQL> ALTER TABLE studentt DROP CONSTRAINT pk_studentt_stid;

 

-방명록 만들기

SQL> CREATE TABLE BANGMYUNG_T(
  2  NO INT,
  3  GUL VARCHAR2(100),
  4  THE_THIME DATE
  5  );

테이블이 생성되었습니다.

 


SQL> CREATE SEQUENCE SEQ_BANGMYUNG;

시퀀스가 생성되었습니다.
SQL> INSERT INTO BANGMYUNG_T VALUES(SEQ_BANGMYUNG.NEXTVAL, '만나서 반갑습니다', SYSDATE);

1 개의 행이 만들어졌습니다.

--MYSQL 

CREATE TABLE BANGMYUNG_T(

    NO INT AUTO_INCREMENT PRIMARY KEY,

    GUL VARCHAR(100),

    THE_TIME DATETIME

);

 

INSERT INTO BANGMYUNG_T VALUES (DAFAULT, '만나서 반갑습니다', NOW());

 

오라클 디비 JDBC

package Lecture.Week2;

import java.sql.*;

public class Test20 {
    public static void main(String[] args) throws Exception{
        Class.forName("oracle.jdbc.driver.OracleDriver");
        Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
        System.out.println(conn.getClass().getName());

        Statement stmt = conn.createStatement();

        String gul = "HelloWorld";
        //String sql = "INSERT INTO BANGMYUNG_T VALUES" + "(SEQ_BANGMYUNG.NEXTVAL, '만나서 반갑습니다'" +" ,SYSDATE)";

        String sql = "INSERT INTO bangmyung_t VALUES " +
                "( seq_bangmyung.NEXTVAL, '" + gul +"'" +
                ", SYSDATE )";

        stmt.executeUpdate(sql);
        conn.close();
    }
}
package Lecture.Week2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

class BangMyungV0{
    private Integer no = null;
    public void setNo (Integer i ){no = i;}
    public Integer getNo() {return no;}


    /*멤버 변수는 private 하게 선언하는게 바람직함
    * 멤버 변수는 오버라이딩 개념이 없다
    * 조상에서 생성된 변수는 자손에서 재 정의하는게 바람직하지 않다
    * 멤버 변수는 get, set으로 가져와야 한다. */
    private  String gul = null;
    public  void setGul(String i ){gul = i;}
    public String getGul() {return gul;}

    private String theTime = null;
    public void setTheTime(String i){theTime = i;}
    public String getTheTime(){return theTime;}
}


public class Test21 {
    public static void main(String[] args)throws Exception{
        Class.forName("oracle.jdbc.driver.OracleDriver");

        Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");
        Statement stmt = conn.createStatement();
        String sql = "select * from bangmyung_t";

        ResultSet rs = stmt.executeQuery(sql);

        List<BangMyungV0> ls = new ArrayList<BangMyungV0>();
        while(rs.next()){
            BangMyungV0 vo = new BangMyungV0();

            vo.setNo(rs.getInt("no"));
            vo.setGul(rs.getString("gul"));
            vo.setTheTime(rs.getString("THE_THIME"));

            ls.add(vo);
        }

        while (rs.next()){
            String no = rs.getString("no");
            String gul = rs.getString("gul");
            String THE_THIME = rs.getString("THE_THIME");

            System.out.println(no);
            System.out.println(gul);
            System.out.println(THE_THIME);
        }
        rs.close();

        stmt.close();
        conn.close();

        for(BangMyungV0 t: ls ){
            System.out.println(t.getNo() + "\t" + t.getGul() + "\t" + t.getTheTime()+"\t");
        }


    }
}

-함수로 선언해서 재사용성을 높였다 

SQL 문장에서 에러 -> stmt.executeUpdate(sql) 에서 예외발생 -> conn.close() 실행 안한다 -> conn은 빨리 끊어야한다. 

 

위의 내용을 왜 아래처럼 짤까? -> executeUpdate 상황에서 에러나도 conn.close()는 되어야 한다?

-> 되어야 한다. finally 영역 도입 시 try 영역에서 에러가 나건 안나건 무조건 실행한다. 

-> stmt.close() con.close()를 finally로 옮김

-> 변수 선언 정리

 

getConnection() 에서 에러나면? conn stmt 는 null 인채로 finally 행

stmt.close() conn.close()가 stmt, conn이 null 이 아닐 때만 호출하도록 개선했다.

 

-try -catch문 사용

package Lecture.Week2;

import java.sql.*;

class BangMyungV0{
    private Integer no = null;
    public void setNo (Integer i ){no = i;}
    public Integer getNo() {return no;}
    private  String gul = null;
    public  void setGul(String i ){gul = i;}
    public String getGul() {return gul;}

    private String theTime = null;
    public void setTheTime(String i){theTime = i;}
    public String getTheTime(){return theTime;}
}


public class Test21 {
    public static void addGul(String gul) throws Exception {
        Connection conn = null;
        Statement stmt = null;

        try{
            conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");

 String sql = "INSERT INTO bangmyung_t VALUES " +
                    "( seq_bangmyung.NEXTVAL, '" + gul +"'" +
                    ", SYSDATE )";
            stmt.executeUpdate(sql);
        }
        catch (Exception e){

        }finally { //try에서 에러가 나건 안나건 무조건 거친다.
            if (stmt != null) {stmt.close();}
            if(conn != null){conn.close();}
        }

public static void main(String[] args)throws Exception{
        Class.forName("oracle.jdbc.driver.OracleDriver");
        addGul("HelloWORLD");

트랜잭션 : 두 개 이상의 업데이트 문장을 하나처럼 묶어주는 작업 

-> LOG 에 쌓인 걸 한번에 반영하거나 버린다  

-> 동일한 CON에서 작업한 내용만 트랜잭션으로 묶을 수 있다. 

 

-비디오 가게에서의 예

대여 : INSERT
대여중 : 대여 기능에 들어가야함
예치금 --
대여중 -> 삭제
대여 기록 -> INSERT
연체금 -> 예치금에서 뺀다
대여중 -> 대여 가능
댓글 입력
댓글 수 ++ 

 

 

//autocommit

SQL> create table txt_tx(
  2  data int
  3  );
package Lecture.Week2;

import java.sql.DriverManager;
import java.sql.*;

/*conn을 통해서 executeUpdate를 하면 LOG를 거쳐 TABLE에 저장된다
* JDBC는 AUTOCOMMIT을 지원한다
* executeUpdate 시에 무조건 commit이 자동으로 먹는다
* 원래 커밋이 자동으로 먹게 되어있다. -> 로그에 잠시 머물다가 곧바로 커밋으로 올라감
* conn.setAutoCommit(false) // commit이 자동으로 먹지 않는다.*/

public class Test23 {
public static void main(String[] args) throws Exception{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");

conn.setAutoCommit(false);

Statement stmt = conn.createStatement();
stmt.executeUpdate("insert into txt_tx values (101)");
stmt.executeUpdate("insert into txt_tx values (102)");
stmt.executeUpdate("insert into txt_tx values (103)");
stmt.executeUpdate("insert into txt_tx values (104)");

stmt.close();
conn.commit();//테이블에 올려버린다
// conn.rollback();//로그를 그냥 비운다 => 테이블에 반영이 안된다
conn.close();
}
}
SQL> select * from txt_tx;

      DATA
----------
       100
       101
       102
       103
       104
package Lecture.Week2;

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

public class Test23_2 {
        public static void main(String[] args) throws Exception{
            Class.forName("oracle.jdbc.driver.OracleDriver");
            Connection conn= null;
            Statement stmt = null;

//            conn.setAutoCommit(false); -> 있으면 롤백 에러 잡고 아니면 commit되서 올라감

            try{
                conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521/XE","HR","HR");

                stmt = conn.createStatement();
                stmt.executeUpdate("insert into txt_tx values (105)");
                stmt.executeUpdate("insert into txt_tx values (106)");
                stmt.executeUpdate("insert into txt_tx values (107)");
                stmt.executeUpdate("insert into txt_tx values (108)");

                conn.commit();//테이블에 올려버린다

                //에러가 나면 앞에있는 것도 몽땅 다 롤백

            }catch (Exception e){//try 에서 에러가 안나면 catch에서 안잡힘
                if(conn != null){ conn.rollback();}
                throw e;
            }finally {
                if(stmt != null) stmt.close();
                if(conn != null)conn.close();
            }
        }
    }


//향상된 코드 
반응형

'Language Study > Java' 카테고리의 다른 글

제주에서 자바_Week3_2  (0) 2019.07.30
제주에서 자바_Week3_1  (0) 2019.07.29
제주에서 자바_Week2_2  (0) 2019.07.24
제주에서 자바_Week2_1  (0) 2019.07.22
제주에서 자바_Week1  (0) 2019.07.20
반응형

문제 설명

수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

 

제한사항

  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.

입출력 예

participantcompletionreturn

[leo, kiki, eden] [eden, kiki] leo
[marina, josipa, nikola, vinko, filipa] [josipa, filipa, marina, nikola] vinko
[mislav, stanko, mislav, ana] [stanko, ana, mislav] mislav

입출력 예 설명

예제 #1
leo는 참여자 명단에는 있지만, 완주자 명단에는 없기 때문에 완주하지 못했습니다.

예제 #2
vinko는 참여자 명단에는 있지만, 완주자 명단에는 없기 때문에 완주하지 못했습니다.

예제 #3
mislav는 참여자 명단에는 두 명이 있지만, 완주자 명단에는 한 명밖에 없기 때문에 한명은 완주하지 못했습니다.

 


##시간복잡도를 줄이기 위해 hashMap을 사용하여야 한다

-> HashMap은 Map을 구현한다. Key와 value를 묶어 하나의 entry로 저장한다는 특징을 갖는다. 그리고 hashing을 사용하기 때문에 많은양의 데이터를 검색하는데 뛰어난 성능을 보인다.

 

  • Map 인터페이스의 한 종류로 ( "Key", value) 로 이뤄져 있다.
  • key 값을 중복이 불가능 하고 value는 중복이 가능. value에 null값도 사용 가능하다.
  • 멀티쓰레드에서 동시에 HashMap을 건드려 Key - value값을 사용하면 문제가 될 수 있다. 멀티쓰레드에서는 HashTable을 쓴다

. HashMap 생성자 / 메서드

 

생성자 / 메서드

설명 

 

HashMap()

 

- HashMap 객체를 생성

 

ex) HashMap<String , Integer> map = new HashMap<String , Integer>();

 

      Map<String, Integer> map = new HashMap<String, integer>();

 

HashMap(int initlalCapacity)

 

- 지정된 값을 초기 용량으로 하는 HashMap객체를 생성한다.

 

HashMap(int initlalCapacity, float loadFactory)

 

- 지정된 값을 초기용량과 load factory의 HashMap 객체를 생성한다. 

 

HashMap(Map m) 

 

- 주어진 Map에 저장된 모든 요소를 포함하는 HashMap을 생성한다. 

 

void clear()

 

- HashMap에 저장된 모든 객체를 제거한다. 

 

ex) map.clear();

 

Object clone()

 

- 현재 HashMap을 복제하여 반환한다. 

 

ex) newmap = (HashMap)map.clone();

 

boolean containsKey(Object Key)

 

- HashMap에 지정된 키(Key)가 포함되어 있는지 알려준다. 

 

boolean containsValue(Object Value)

 

- HashMap에 지정된 값(Value)가 포함되어 있는지 알려준다. 

 

Set entrySet()

 

- HashMap에 저장된 Key - Value갑슬 엔트리(키와 값을 결합)의 형태로 Set에 저장하여 반환

 

ex) map.put("A", 1);

 

      map.put("B", 2);

 

      map.put("C", 3);

 

      Set set = map.entrySet();

 

      System.out.println("set values are" + set);

 

      (result) set values : [A=1,B=2,C=3]

 

Object get(Object Key)

 

- 지정된 Key 의 값을 반환한다. 

 

ex) map.put("A", 1);

 

      map.put("B", 2);

 

      map.put("C", 3);

 

      String val = (String)map.get("B");

 

System.out.println("Value for key B is: " + val);

 

 

 

(result) Value for key B is 2

 

bloolean isEmpty

 

- HashMap이 비어있는지 확인한다.

 

ex) boolean val = map.isEmpty();

 

Set keySet()

 

- HashMap에 저장된 모든 키가 저장된 Set을 반환한다.

 

ex) map.put("A", 1);

 

      map.put("B", 2);

 

      map.put("C", 3);

 

      Set keyset = map.keySet();

 

      System.out.println("Key set values are" + keyset);

 

      (result) Key set values are [A,B,C]

 

Object put(Object Key, Object Value)

 

- HashMap에 키와 값을 저장.

 

ex) map.put("A", "aaa");

 

      map.put("B", "bbb");

 

      map.put("C", "ccc");

 

void putAll(Map m)

 

- Map에 해당하는 모든 요소를 HashMap에 저장한다. 

 

Object remove(Object Key)

 

- HashMap에서 지정된 키로 지정된 값을 제거한다.

 

ex) map.remove("key");

 

int size()

 

- HashMap에 저장된 요소의 개수를 반환한다. 

 

Collection values()

 

- HashMap에 저장된 모든 값을 컬렉션 형태로 반환한다. 

출처: https://vaert.tistory.com/107 [Vaert Street]

 

<hash 사용>

import java.util.*; 
  
class Solution { 
    public String solution(String[] participant, String[] completion) { 
        Map<String, Integer> hash = new HashMap<>(); 
        for (String arg : participant) hash.put(arg, hash.getOrDefault(arg, 0) + 1); 
//getOrDefault를 넣어주지 않으면 중복 체크가 되지 않음 , HashMap의 put은 key가 존재하면 value를 새로운 값으로 바꿔주니까 / 이미 등록된 동명이인이 있다면 hm.getOrDefault로 인해서 2라는 값이 들어감

        for (String arg : completion) hash.put(arg, hash.get(arg) - 1); 
  
        for (String key : hash.keySet()) { 
            if (hash.get(key) != 0) return key; 
        } 
  
        return null; 
    } 
}

 

<다른 사람 답>

import java.util.*; 
class Solution { 
    public String solution(String[] participant, String[] completion) { 
        Arrays.sort(participant); 
        Arrays.sort(completion); 
        int i; 
        for ( i=0; i<completion.length; i++){ 

            if (!participant[i].equals(completion[i])){ 
                return participant[i]; 
            } 
        } 
        return participant[i]; 
    } 
}
반응형

'Algorithm Study > Programmers' 카테고리의 다른 글

두 정수 사이의 합 / java  (0) 2019.08.28
2016년/java  (0) 2019.08.28
가장 큰 수 / java / 정렬  (0) 2019.08.17
k번째수/java/정렬(출제 빈도 높음)  (0) 2019.08.16
체육복/java/탐욕법 알고리즘  (0) 2019.08.15
반응형

Day 3

1. 데이터 베이스 설계 프로세스 

  1. 업무 분석
    • 명사, 동사 업무 정확하게 기술
    • 업무 파악에 도움되는 어떤 형태의 자료도 확보
    • 가능한 UI를 그려 가며 인터뷰 진행(설계에 결정적인 영향 끼침)
    • 경험이 중요
  2. 엔티티 도출 (Entity)
    • 추상 명사 중에서 PK로 구분되어지는 것이 Entity 가 된다
    • 기록될 만한 가치가 있는 정보인지 판별
    • PK : 단일 필드의 특징이 있어야 한다
      • Primary key (기본키)
        • 레코드를 구분하는 기준으로 사용되는 필드(들)
        • 예 ) 주민번호 , 사번, 군번,...
        • 주민번호처럼 두개의 필드가 결합해서 PK를 이룰 수도 있다
        • 3가지 성격
          • ND (NO DUPLICATE) : 중복되어서는 안된다
          • NN( NOT NULL) : 생략되어서는 안된다
          • NC (NO CHANGE) : 가급적 변경되어서는 안된다.
    • 엔티티 : ERD에서 사각형으로 표현
      • 예 ) 회원, 글, 과목, 학생
  3. 관계 도출(Relation) 
    • 엔티티들 사이에서 동사가 어울리게 존재 가능 -> 기록할 만한 가치가 있다면 그것이 관계
    • 예 ) 회원은 글을 쓴다(쓴다) - 학생은 과목을 수강한다(수강한다)
    • 3가지 종류
      • 1대1 대응 : Be 동사에 해당하는 관계 or 상속관계
        • ex) 사병은 군인이다 / 장교는 군인이다 / 군인은 군번을 구분된다
      • 1대다 대응 : 
        • 회원은 글을 쓴다.
      • 다대다 대응
        • 학생은 과목을 수강하고 -> 회원은 글을 읽는다 -> 추천한다
    • 관계의 물리적인 구현 방법
      • 일대일 대응 : 조상의 PK를 자손이 PK 이자 FK로 참조한다
      • 일대다 대응 : 다 쪽에서 일 쪽의 PK를 FK로 참조한다
      • 다대다 대응: 새로운 테이블 생성 -> 그 PK는 양쪽의 PK를 참조하는 FK를 결합하여 구성
  4. 속성(Attribute) 파악
    • 일반 명사 중 자료형과 값으로 표현될 수 있는 것들
      • 예) 성적, 글쓴 시간, 이름, 전화번호, 주소 ---
    • 엔티티 , Relation 에 1:1로 매핑하는 곳에 배치한다
    • 실제 구현시 필드에 해당
  5. ERD 구성
    • 2가지 종류 : 두가지 다 그릴 줄 알아야한다. 
      • 분석에 가까운 형태
      • 구현에 가까운 형태
    • 엔티티는 사각형, 관계는 마름모 
      관계는 화살표 OR 실선 (도착쪽이 PK)
      PK는 꽉찬 사탕 막대기 , 그 외 필드는 텅빈 사탕 막대기
      NOT NULL 필드는 굵은 글씨로 표기한다
    • 그릴때 용이한 많은 툴이 있다(유료)
      Microsoft Visio
    • 정규화 vs 비정규화
정규화 비정규화
More Table , Less Column Less Table, More Column
속도 느림 속도 빠름
테이블 구조 안정적 테이블 구조 자주 변경될 여지 O
자료 중복저장 허용 X(성적 있으면 등수 자동) 자료의 중복저장 허용O(속도를 위해 등수 필요)

=> 정규화를 중심으로 적절한 비정규화를 추구하는게 방향  / 경험이 가장 중요하다

ER 다이어그램 예시

6. FK (Foreign Key) :외래키

  • 다른 테이블의 PK로 쓰이는 필드를 내쪽에서 참조해서 쓰는 필드(들)
  • 성적 테이블에 stid , subid - 성적 테이블의 stid는 학생테이블에 쓰이는 의미를 가져다가 쓴다. "
    -> 성적테이블의 stid의 10101은 학생테이블 stid의 10101과 동일한 의미이다

7. 비디오 가게 만들기

비디오 가게 ER 다이어그램

8. 정규화

mysql> select stid, name, (kor1 + eng1 + mat1)/3 as avg from score2t;
+-------+-----------+---------+
| stid  | name      | avg     |
+-------+-----------+---------+
| 10101 | 홍길동    | 76.6667 |
| 10102 | 고길동    | 93.3333 |
| 10103 | 이기자    | 76.6667 |
| 10104 | 박기자    | 73.3333 |
| 10105 | 김영삼    | 63.3333 |
| 10106 | 김대중    | 66.6667 |
+-------+-----------+---------+
6 rows in set (0.00 sec)
  • 정규화
    • Less Column  : 테이블당 필드의 개수가 적다 - 5 ~ 12개
    • More Table : score2t 가 한개가 되는 걸 우리는 3개를 만들었다
    • 필드와 데이터의 중복 저장을 허용안한다(비디오점의 대여 여부) 
  • 비정규화 : More Column, Less Table 
    • 필드와 데이터의 중복 저장을 허용한다(속도 문제)

대부분 정규화를 기본으로 해서 적절한 비정규화를 도입한다.

#테이블의 껍데기만 만드는 것
mysql> create table student_xt as
    -> select stid, name, addr from score2t where 0 = 1;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
#테이블에 select 결과를 입력하는 것mysql> insert into student_xt select stid, name, addr from score2t where 1 = 1;
Query OK, 6 rows affected (0.02 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> select * from student_xt;
+-------+-----------+-----------+
| stid  | name      | addr      |
+-------+-----------+-----------+
| 10101 | 홍길동    | 역삼동    |
| 10102 | 고길동    | 개포동    |
| 10103 | 이기자    | 역삼동    |
| 10104 | 박기자    | 한남동    |
| 10105 | 김영삼    | 홍제동    |
| 10106 | 김대중    | 한남동    |
+-------+-----------+-----------+
6 rows in set (0.02 sec)

 

#score_xt //하나도 흘리지 않고 새로운 테이블에 옮겨갈 때

mysql> create table score_xt as
    -> select stid, 'KOR1' as subid, kor1 as score from score2t where 0 =1;
Query OK, 0 rows affected (0.23 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> insert into score_xt select stid, 'KOR1', kor1 as score from score2t where 1= 1;
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> insert into score_xt
    -> select stid, 'ENG1', eng1 as score from score2t where 1=1;
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> insert into score_xt
    -> select stid, 'MAT1', mat1 as score from score2t where 1=1;
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0
mysql> select * from score_xt;
+-------+-------+-------+
| stid  | subid | score |
+-------+-------+-------+
| 10101 | KOR1  |    60 |
| 10102 | KOR1  |    90 |
| 10103 | KOR1  |    70 |
| 10104 | KOR1  |    80 |
| 10105 | KOR1  |    50 |
| 10106 | KOR1  |    60 |
| 10101 | ENG1  |    80 |
| 10102 | ENG1  |    90 |
| 10103 | ENG1  |    90 |
| 10104 | ENG1  |    70 |
| 10105 | ENG1  |    60 |
| 10106 | ENG1  |    80 |
| 10101 | MAT1  |    90 |
| 10102 | MAT1  |   100 |
| 10103 | MAT1  |    70 |
| 10104 | MAT1  |    70 |
| 10105 | MAT1  |    80 |
| 10106 | MAT1  |    60 |
+-------+-------+-------+
18 rows in set (0.00 sec)

#비정규화 된 설계에서 정규화 된 설계로 옮길 수도 있고

정규화된 설계에서 비정규화 된 설계로 옮길 수도 있어야 한다. 

 

9. JOIN -> 서브쿼리와 유사

studentt : stid (pk) <- scoret : stid(fk)

 

-대부분의 join은 pk - fk 사이에서 일어난다 

 

mysql>select * from studentt INNER JOIN scoret ON studentt.stid = scoret.stid;
//studentt에 있는 pk(stid)를 참조 받아 두 테이블을 조인시킴
+-------+-----------+-----------+-------+-------+-------+
| stId  | name      | addr      | stId  | subId | score |
+-------+-----------+-----------+-------+-------+-------+
| 10101 | 홍길동    | 역삼동    | 10101 | KOR1  |   100 |
| 10101 | 홍길동    | 역삼동    | 10101 | ENG1  |   100 |
| 10101 | 홍길동    | 역삼동    | 10101 | MAT1  |   100 |
| 10102 | 고길동    | 개포동    | 10102 | KOR1  |    90 |
| 10102 | 고길동    | 개포동    | 10102 | MAT1  |    90 |
| 10102 | 고길동    | 개포동    | 10102 | ENG1  |   100 |
| 10103 | 이기자    | 역삼동    | 10103 | KOR1  |    70 |
| 10104 | 박기자    | 한남동    | 10104 | KOR1  |    80 |
| 10105 | 김영삼    | 홍제동    | 10105 | KOR1  |    50 |
| 10106 | 김대중    | 한남동    | 10106 | KOR1  |    60 |
| 10103 | 이기자    | 역삼동    | 10103 | ENG1  |    90 |
| 10104 | 박기자    | 한남동    | 10104 | ENG1  |    70 |
| 10105 | 김영삼    | 홍제동    | 10105 | ENG1  |    60 |
| 10106 | 김대중    | 한남동    | 10106 | ENG1  |    80 |
| 10103 | 이기자    | 역삼동    | 10103 | MAT1  |    70 |
| 10104 | 박기자    | 한남동    | 10104 | MAT1  |    70 |
| 10105 | 김영삼    | 홍제동    | 10105 | MAT1  |    80 |
| 10106 | 김대중    | 한남동    | 10106 | MAT1  |    60 |
+-------+-----------+-----------+-------+-------+-------+

- INNER JOIN : PK - FK 데이터가 일치하는 레코드를 짜매준다. 

 mysql>SELECT name, addr, score From studentt INNER JOIN scoret ON studentt.stid = scoret.stid WHERE subid = 'MAT1';
//join을 이용하면 흩어진 데이터를 통합해서 보여지게 할 수 있다 (서브 쿼리도 가능 , 헌대 성능이 틀리다) 
-> 해서 같은 결과를 만들되 성능이 향상되게 만드는 것이 SQL 튜닝의 영역
Q. subjectt , scoret를 inner join해서 10101 국어1 90..이런식으로 나오게
mysql> select stid,name,score from subjectt INNER JOIN scoret ON subjectt.subid = scoret.subid;

+-------+---------+-------+
| stid  | name    | score |
+-------+---------+-------+
| 10101 | 국어1   |   100 |
| 10101 | 영어1   |   100 |
| 10101 | 수학1   |   100 |
| 10102 | 국어1   |    90 |
| 10102 | 수학1   |    90 |
| 10102 | 영어1   |   100 |
| 10103 | 국어1   |    70 |
| 10104 | 국어1   |    80 |
| 10105 | 국어1   |    50 |
| 10106 | 국어1   |    60 |
| 10103 | 영어1   |    90 |
| 10104 | 영어1   |    70 |
| 10105 | 영어1   |    60 |
| 10106 | 영어1   |    80 |
| 10103 | 수학1   |    70 |
| 10104 | 수학1   |    70 |
| 10105 | 수학1   |    80 |
| 10106 | 수학1   |    60 |
+-------+---------+-------+
18 rows in set (0.00 sec)
mysql> select stid,name,score, subjectt.subid from subjectt INNER JOIN scoret ON subjectt.subid = scoret.subid;
//같은이름의 subid 가져오려면 어디서 가져와야하는지 명시 해야한다.
+-------+---------+-------+-------+
| stid  | name    | score | subid |
+-------+---------+-------+-------+
| 10101 | 국어1   |   100 | KOR1  |
| 10101 | 영어1   |   100 | ENG1  |
| 10101 | 수학1   |   100 | MAT1  |
| 10102 | 국어1   |    90 | KOR1  |
| 10102 | 수학1   |    90 | MAT1  |
| 10102 | 영어1   |   100 | ENG1  |
| 10103 | 국어1   |    70 | KOR1  |
| 10104 | 국어1   |    80 | KOR1  |
| 10105 | 국어1   |    50 | KOR1  |
| 10106 | 국어1   |    60 | KOR1  |
| 10103 | 영어1   |    90 | ENG1  |
| 10104 | 영어1   |    70 | ENG1  |
| 10105 | 영어1   |    60 | ENG1  |
| 10106 | 영어1   |    80 | ENG1  |
| 10103 | 수학1   |    70 | MAT1  |
| 10104 | 수학1   |    70 | MAT1  |
| 10105 | 수학1   |    80 | MAT1  |
| 10106 | 수학1   |    60 | MAT1  |
+-------+---------+-------+-------+

 

//subjectt -> y로 scoret -> x로 각각 줄여서 쓰면 이렇게 가능

mysql> select stid, name, score, y.subid FROM scoret as x INNER JOIN subjectt as y ON y.subid = x.subid;
+-------+---------+-------+-------+
| stid  | name    | score | subid |
+-------+---------+-------+-------+
| 10101 | 국어1   |   100 | KOR1  |
| 10101 | 영어1   |   100 | ENG1  |
| 10101 | 수학1   |   100 | MAT1  |
| 10102 | 국어1   |    90 | KOR1  |
| 10102 | 수학1   |    90 | MAT1  |
| 10102 | 영어1   |   100 | ENG1  |
| 10103 | 국어1   |    70 | KOR1  |
| 10104 | 국어1   |    80 | KOR1  |
| 10105 | 국어1   |    50 | KOR1  |
| 10106 | 국어1   |    60 | KOR1  |
| 10103 | 영어1   |    90 | ENG1  |
| 10104 | 영어1   |    70 | ENG1  |
| 10105 | 영어1   |    60 | ENG1  |
| 10106 | 영어1   |    80 | ENG1  |
| 10103 | 수학1   |    70 | MAT1  |
| 10104 | 수학1   |    70 | MAT1  |
| 10105 | 수학1   |    80 | MAT1  |
| 10106 | 수학1   |    60 | MAT1  |
+-------+---------+-------+-------+
18 rows in set (0.00 sec)
mysql> SELECT stid, avg(score) as avg FROM scoret group by stid;
+-------+----------+
| stid  | avg      |
+-------+----------+
| 10101 | 100.0000 |
| 10102 |  93.3333 |
| 10103 |  76.6667 |
| 10104 |  73.3333 |
| 10105 |  63.3333 |
| 10106 |  66.6667 |
+-------+----------+
6 rows in set (0.00 sec)

//서브쿼리를 사용해 JOIN 할 수 있다.

mysql> SELECT * from (SELECT stid, avg(score) as avg FROM scoret group by stid) AS x INNER JOIN studentt AS y ON y.stid = x.stid;
+-------+----------+-------+-----------+-----------+
| stid  | avg      | stId  | name      | addr      |
+-------+----------+-------+-----------+-----------+
| 10101 | 100.0000 | 10101 | 홍길동    | 역삼동    |
| 10102 |  93.3333 | 10102 | 고길동    | 개포동    |
| 10103 |  76.6667 | 10103 | 이기자    | 역삼동    |
| 10104 |  73.3333 | 10104 | 박기자    | 한남동    |
| 10105 |  63.3333 | 10105 | 김영삼    | 홍제동    |
| 10106 |  66.6667 | 10106 | 김대중    | 한남동    |
+-------+----------+-------+-----------+-----------+
6 rows in set (0.00 sec)

10. 외부조인(OUTER JOIN)

mysql> SELECT * FROM subjectt INNER JOIN scoret ON subjectt.subid = scoret.subid;
//일단 subjectt 와 scoret를 조인
+-------+---------+-------+-------+-------+
| subId | name    | stId  | subId | score |
+-------+---------+-------+-------+-------+
| KOR1  | 국어1   | 10101 | KOR1  |   100 |
| ENG1  | 영어1   | 10101 | ENG1  |   100 |
| MAT1  | 수학1   | 10101 | MAT1  |   100 |
| KOR1  | 국어1   | 10102 | KOR1  |    90 |
| MAT1  | 수학1   | 10102 | MAT1  |    90 |
| ENG1  | 영어1   | 10102 | ENG1  |   100 |
| KOR1  | 국어1   | 10103 | KOR1  |    70 |
| KOR1  | 국어1   | 10104 | KOR1  |    80 |
| KOR1  | 국어1   | 10105 | KOR1  |    50 |
| KOR1  | 국어1   | 10106 | KOR1  |    60 |
| ENG1  | 영어1   | 10103 | ENG1  |    90 |
| ENG1  | 영어1   | 10104 | ENG1  |    70 |
| ENG1  | 영어1   | 10105 | ENG1  |    60 |
| ENG1  | 영어1   | 10106 | ENG1  |    80 |
| MAT1  | 수학1   | 10103 | MAT1  |    70 |
| MAT1  | 수학1   | 10104 | MAT1  |    70 |
| MAT1  | 수학1   | 10105 | MAT1  |    80 |
| MAT1  | 수학1   | 10106 | MAT1  |    60 |
+-------+---------+-------+-------+-------+
18 rows in set (0.00 sec)
mysql> INSERT INTO subjectt values('PHY1', '물리');

//이렇게 물리가 추가 된다고 해도 성적데이터가 없으니 짜매어줄 대상이 없다

//회원가입이 되어도 글 쓴게 없으면 조인 걸어도 나타나지 않는다

//-> 한쪽 테이블에서만 보여지고 짜매지지 않는 경우라도 한 건 보여지게 만드는 형태의 조인이 OUTER JOIN이다

// 부족함(NULL 로 채움) 이 나타나는 반대편을 명시한다(LEFT)

mysql> SELECT * FROM subjectt LEFT OUTER JOIN scoret ON subjectt.subid = scoret.subid;
+-------+---------+-------+-------+-------+
| subId | name    | stId  | subId | score |
+-------+---------+-------+-------+-------+
| KOR1  | 국어1   | 10101 | KOR1  |   100 |
| ENG1  | 영어1   | 10101 | ENG1  |   100 |
| MAT1  | 수학1   | 10101 | MAT1  |   100 |
| KOR1  | 국어1   | 10102 | KOR1  |    90 |
| MAT1  | 수학1   | 10102 | MAT1  |    90 |
| ENG1  | 영어1   | 10102 | ENG1  |   100 |
| KOR1  | 국어1   | 10103 | KOR1  |    70 |
| KOR1  | 국어1   | 10104 | KOR1  |    80 |
| KOR1  | 국어1   | 10105 | KOR1  |    50 |
| KOR1  | 국어1   | 10106 | KOR1  |    60 |
| ENG1  | 영어1   | 10103 | ENG1  |    90 |
| ENG1  | 영어1   | 10104 | ENG1  |    70 |
| ENG1  | 영어1   | 10105 | ENG1  |    60 |
| ENG1  | 영어1   | 10106 | ENG1  |    80 |
| MAT1  | 수학1   | 10103 | MAT1  |    70 |
| MAT1  | 수학1   | 10104 | MAT1  |    70 |
| MAT1  | 수학1   | 10105 | MAT1  |    80 |
| MAT1  | 수학1   | 10106 | MAT1  |    60 |
| PHY1  | 물리    | NULL  | NULL  |  NULL |
+-------+---------+-------+-------+-------+
19 rows in set (0.00 sec)

//count(*) 는 레코드의 갯수를 센다. 

//count(score) 은 해당 필드의 null 이 아닌 데이터의 갯수를 센다

mysql> SELECT subjectt.subid, count(score) FROM subjectt LEFT OUTER JOIN scoret ON subjectt.subid = scoret.subid GROUP BY subjectt.subid;
+-------+--------------+
| subid | count(score) |
+-------+--------------+
| ENG1  |            6 |
| KOR1  |            6 |
| MAT1  |            6 |
| PHY1  |            0 |
+-------+--------------+
4 rows in set (0.00 sec)

11. CONSTRAINT - 물리적인 제약 조건을 필드에 걸어준다 

-> 제약 조건 : CHECK, UNIQUE, PRIMARY KEY, FOREIGN KEY 4가지를 주로 쓴다 .

 

-> score 값을 (0 - 100) 사이의 값만 허용해야한다

mysql>ALTER TABLE scoret ADD CONSTRAINT CHECK_scoret_score CHECK (score >= 0 AND score <= 100);
mysql>insert into scoret valus ('10101', 'PHY1', 80);
ERROR 1264 (22003): Out of range value for column 'score' at row 1

 

지울떄는

mysql>ALTER TABLE scoret DROP CONSTRAINT CHECH_scoret_score;

 

-CHECK CONSTRAINT 는 WHERE 절의 조건을 이용하여 제약을 걸 수 있다. 

(IN, NOT IN, = != ... 을 사용할 수 있다

mysql> ALTER TABLE subjectt ADD CONSTRAINT PK_subjectt_subid
    -> PRIMARY KEY(subid);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> INSERT INTO subjectt VALUES('KOR1','국어');
ERROR 1062 (23000): Duplicate entry 'KOR1' for key 'PRIMARY'

-참조 무결성 : PK 쪽에서 쓰여진 데이터만 FK 쪽에서 쓰여질 수 있다

  • 회원 가입 해야 글 쓴다
  • 회원 등록 해야 예약한다
  • 등록된 아이템만 대여 가능하다 ...

#PRIMARY (subjectt) 쓰인적 있기 때문에 -> FOREIGN KEY부분에서 잘 쓸 수 있음

mysql> ALTER TABLE scoret ADD CONSTRAINT FX_scoret_subid
    -> FOREIGN KEY(subid) REFERENCES subjectt(subid);
Query OK, 20 rows affected (0.05 sec)
Records: 20  Duplicates: 0  Warnings: 0

mysql> INSERT INTO scoret VALUES ('10101', 'XXXX', 50);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`study`.`scoret`, CONSTRAINT `FX_scoret_subid` FOREIGN KEY (`subId`) REFERENCES `subjectt` (`subId`))

 

12. UNIQUE CONSTRAINT  : NULL 허용하는데 중복은 안된다 -> 테이블 분리할 때 사용

다대다로 만들고 -> UNIQUE 걸어서 -> 일대일처럼 동작

 

mysql> create table study05t(
    -> id int not null
    -> );
Query OK, 0 rows affected (0.02 sec)
mysql> ALTER TABLE study05t ADD CONSTRAINT UQ_study05t_id UNIQUE(id);
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

#일대일 상황에서 테이블 분리하는 방법 

-일단 다대다로 생각하고 테이블을 생성한다

-pk 중 하나에 unique constraint를 건다

-> 다대다 => 일대일로 바뀐다 .

 

#constraint 지우는 법

mysql> ALTER TABLE study05t DROP INDEX UQ_study05t_id;
Query OK, 1 row affected (0.04 sec)
Records: 1  Duplicates: 0  Warnings: 0

문제

짜장면집 결제 DB

중요한 핵심

반응형

'Language Study > Java' 카테고리의 다른 글

제주에서 자바_Week3_1  (0) 2019.07.29
제주에서 자바_Week2_3  (0) 2019.07.25
제주에서 자바_Week2_1  (0) 2019.07.22
제주에서 자바_Week1  (0) 2019.07.20
4. 클래스  (0) 2019.05.29
반응형
# https://coding-factory.tistory.com/ 에서 그림 인용 

Day 1

1. 입력스트립(Input Stream) & 출력 스트림(Output Stream) 

- 자바 데이터는 스트림(Stream) 통해 입출력.

-스트림 ; 단일방향으로 연속적으로 흘러가는 것 

    => 순서대로 읽고, 순서대로 내보냄 / byte 단위로 전송

-프로그램 기준 데이터가 들어오면 입력 스트림 , 데이터가 나가면 출력 스트림

프로그램 기준 스트림

-Java.io 패키지 : 파일 시스템의 정보를 얻기 위한 file 클래스와 데이터 입출력하기 위한 다양한 입출력 스트림 클래스 제공

 Java.io 패키지의 주요 클래스

설명 

 File

 파일 시스템의 파일 정보를 얻기 위한 클래스 

 Console 

 콘솔로부터 문자를 입출력하기 위한 클래스 

 InputStream / OutputStream

 바이트 단위 입출력을 위한 최상위 입출력 스트림 클래스 

 FileInputStream / FileOuputStream

 바이트 단위 입출력을 위한 하위 스트림 클래스

 DataInputStream / DataOutputStream

 ObjectInputStream / ObjectOutputStream

 PrintStream

 BufferedInputStream / BufferedOutputStream

 Reader / Writer

 문자 단위 입출력을 위한 최상위 입출력 스트림 클래스

 FileReader / FileWriter

 문자 단위 입출력을 위한 하위 스트림 클래스

 InputStreamReader / OutputStreamWriter

 PrintWriter

 BufferedReader / BufferedWriter

 

  • 바이트 단위 입출력 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터들 주고 받음
  • 문자 단위 입출력 스트림 : 오로지 문자만 주고 받을 수 있게 함

-inputStream : 바이트 기반 입력 스트림의 최상위 클래스(추상 클래스)

  • 모든 바이트 기반 입력 스트림은 이 클래스를 상속받아 만들어짐
  • FileInputStream
  • BufferedInputStream
  • DataInputStream

 메서드

설명 

 read()

입력 스트림으로부터 1바이트를 읽고 읽은 바이트를 리턴합니다. 

 read(byte[ ] b)

 입력 스트림으로부터 읽은 바이트들을 매개값으로 주어진 바이트 배열b에 저장하고 실제로 읽은 바이트 수를 리턴합니다.

 read(byte[] b, int off, int len)

입력 스트림으로부터 len개의 바이트만큼 읽고 매개값으로 주어진 바이트 배열 b[off]부터 len개까지 저장합니다. 그리고 실제로 읽은 바이트 수인 len개를 리턴합니다. 만약 len개를 모두 읽지 못하면 실제로 읽은 바이트 수를 리턴합니다. 

 close()

사용한 시스템 자원을 반납하고 입력스트림을 닫습니다. 

 

-OutputStream : 바이트 기반 출력 스트림의 최상위 클래스(추상 클래스) / 모든 바이트 기반 출력 스트림 클래스는 이 클래스를 상속받아 만들어짐

  • FileOutputStream : 파일에 저장하는 방법 제공
  • PrintStream
  • BufferedOutputStream
  • DataOutputStream

 메서드

설명 

 write(int b)

 출력 스트림으로부터 1바이트를 보냅니다.(b의 끝 1바이트) 

 write(byte[ ] b)

 출력 스트림으로부터 주어진 바이트 배열 b의 모든 바이트를 보냅니다.

 write(byte[ ] b, int off, int len)

 출력 스트림으로 주어진 바이트 배열 b[off]부터 len개까지의 바이트를 보냅니다. 

 flush() 

 버퍼에 잔류하는 모든 바이트를 출력합니다. 

 close()

 사용한 시스템 자원을 반납하고 출력 스트림을 닫습니다. 
package Lecture.Week2;

import java.io.*;

public class Test04 {
    public static void main(String[] args) throws IOException {
        InputStream in = new FileInputStream("a.dat" );
        OutputStream out = new FileOutputStream("b.dat");

        //복사 : dir *.dat 로 확인하고 type b.dat로 확인하고..
//        while(true){
//            int r = in.read();
//            if(r == -1){//더이상 읽을 것이 없을 때
//                break;
//            }
//            out.write(r);
//        }
//        out.close();
//        in.close();


        //엄청 많이 씀 -> 외우세용
        int r = 0;
        byte[] buf= new byte[1024*8];
        while(( r = in.read(buf)) != -1 ){// 더 읽을게 남아있다.
            out.write(buf, 0, r);
        }
        out.close();
        in.close();
    }
}

 

이를 데코레이터 패턴으로 이해하면 

-> out 이 가리키는 대상은
FileOutputStream("d.dat")에 저장하되
ObjectOutputStream 에서 제공하는 방법을 사용하게 된다.

ObjectOutputStream 은 writeInt writeDouble writeUTF 등을 제공
-> 전송 시에 안깨진다.
* ObjectOutputStream 은 writeInt WriteDouble writeUTF 등을 제공 -> 전송

 

*OutputStream InputStream : 전송단위 byte
* Reader Writer : 전송단위 char : 문자로 된 데이터 전송용

* char : 2바이트 , 유니코드 지원
* 유니코드 : 모든 글자를 다 포용하지 못한다
* -웬만한 건 글자는 포용한다 , 한글 영문 중국어 아랍어 일본어
* 확장 가능한 가변 길이를 가지는 문자체제 도입 UTF - 8.

*OutputStreamWriter InputStreamReader 는 char 입출력을 byte 입출력으로 전환해 줍니다
* 2byte -> 1byte로 바꿔줌*

 

 

 

 2. 자바 네트워크에 대한 이해

  • 네트워크란?
    • 다른 장치로 데이터를 이동시킬 수 있는 컴퓨터들 , 주변 장치들의 집합
    • 네트워크의 연결된 모든 장치들을 노드라고 한다
    • 복잡한 레이어의 대표적인 모델이 OSI 7계층
    • TCP / IP 모델 사용
  • IP 주소
    • 모든 호스트는 인터넷 주소(Host, IP 주소) 라 불리는 유일한 32비트 숫자로 구성된 주소 체계 이용
    • 32비트의 주소 체계를 IPv4 주소라고한다 -> 극복 IPv6
    • IP주소를 도메인이름으로 바꾸어 주는 시스템  : DNS
  • 포트 & 프로토콜
    • 포트 
      • 물리적 포트 
      • 논리적 포트
    • 프로토콜
      • 클라이언트와 서버간의 통신 규약
      • TCP / UDP
  • TCP / UDP
    • TCP / IP계층 모델은 4계층 구조(애플리케이션, 전송, 네트워크, 데이터 링크 계층)
    • 전송 계층에서 사용하는 프로토콜 TCP / UDP 
      • TCP (transmission Control Protocol) : 신뢰할 수 있는 프로토콜 / 데이터 상대 측까지 제대로 전달되었는지 확인 메시지를 주고 받음으로써 데이터의 송수신 상태를 점검
      • UDP(user datagram protocol) : 신뢰할 수 없는 프로토콜 / 데이터 보내기만 하고 제대로 전달되었는지 확인 하지 않음

3. TCP 통신 / Socket 프로그래밍

  • TCP 통신 방식 : 소켓 프로그래밍의 하나 / 스트림 통신 프로토콜 / 양쪽 소켓이 연결 상태여야만 가능 -> 연결 지향 프로토콜
    • 수신,  송신 측이 미리 연결 맺고 연결된 순서대로 데이터 교환해야함
    • Java.net 패키지에 관련 클래스들 미리 준비 해놓음
  • 소켓? 
    • 네트워크 끝 부분 / 실제 데이터가 어떻게 전송되는 지 상관하지 않고 read/write 인터페이스 제공
    • 네트워크 계층과 전송 계층이 캡슐화
    • TCP / IP 계층의 TCP를 지원하기 위해 Socket, ServerSocket 클래스 제공
    • 클라이언트 : socket 객체 생성, tcp 서버와 연결 시도
    • 서버 : SocketServer 객체 생성 , TCP 연결을 청취하여 클라이언트와 서버 연결
  • 소켓 스트림 

  • TCP 소켓은 java.net.Socket 클래스 의미
    • Socket 클래스 생성자
      • 예외 처리 2개
        • 호스트를 찾을 수 없거나, 서버의 포트가 열려있지 않는 경우 (UnknownHostException 예외) 발생
        • 네트워크 실패, 방화벽 때문에 서버 접근 할 수 없을 때 (IOException 예외) 발생
생성자 설명
Socket(Inet(Address address, int port) InetAdderss 객체와 port 이용하여 socket 객체를 생성한다
Socket(String host, int port)  host, port를 이용하여 socket객체를 생성한다.
  • Socket 클래스의 주요 메서드 
반환형 메서드 설명
void close() 소켓 객체를 닫는다
InetAddress getInetAddress() 소켓 객체를 InetAddress 객체로 반환한다
InputStream getInputStream() 소켓 객체로부터 입력할 수 있는 InputStream 객체를 반환한다
InetAddress getLocalAddress() 소켓 객체의 로컬 주소를 반환한다.
int getPort() 소켓 객체의 포트를 반환한다
boolean isClosed() 소켓 닫혀있으면 true, 아니면 false 반환
isConnected() 소켓 객체가 연결되어 있으면 true, 연결되어 있지 않으면 false를 반환
void setSoTimeout(int timeout) 소켓 객체의 시간을 밀리 세컨드로 설정
  • 소켓 이용한 입출력 스트림 생성
    • 두 개의 네트워크 사이에서 바이트 스트림 통신 제공
    • 바이트를 읽기 위한 메서드와 쓰기 위한 메서드 제공
    • 두 가지 메서드를 이용하여 클라이언트와 서버간에 통신할 수 있다.
java.io.InputStream getInputStream() throws IOException; 
java.io.OutputStream getOutputStream() throws IOException;

Socket socket = new Socket(“211.238.132.50”,4000); 
InputStream in = socket.getIputStream(); 
OutputStream os = socket.getOutputStream();
  • 소켓 정보 : 로컬 ip주소와 포트를 알 수 있는 메서드와 socket 으로 연결된 호스트의 ip 주소와 포트를 알 수 있는 메서드 제공
  • TCP Server Socket
    • 클라이언트의 TCP 연결을 받기 위해서 java.net.ServerSocket 클래스의 객체를 생성
    • ServerSocket 클래슨느 네트워크 통신을 수행하기 위해 자신을 바로 사용 X 
      -> 클라이언트의 TCP 요청에 대한 Socket 객체를 생성하는것 
    • accept() 메서드 : 클라이언트의 TCP 요청 있을 때 까지 블로킹되는 메서드
    • 클라이언트 TCP 요청 -> ACCEPT 메서드-> TCP 소켓 반환
    • 일반적으로 accept() 메서드는 무한루프 처리하게 됨
    • ServerSocket 클래스의 생성자
      • 기존의 tcp 포트 번호가 사용중이라면 IOException 발생
생성자  설명
ServerSocket(int port) port 이용하여 ServerSocket 객체 생성
  • ServerSocket 클래스 주요 메서드 
    • accept() 가 제일 중요
반환형 메서드 설명
Socket accept() 클라이언트의 소켓 객체가 생성되면 서버가 클라이언트와 통신할 수 있는 소켓 객체를 반환
void close() 서버소켓 객체 닫음
int getLocalPort() 서버소켓 객체가 청취하고 있는 포트번호 반환
getSoTimeout() 서버소켓 클래스의 accept() 메서드가 유효할 수 있는 밀리 세컨드로 반환
boolean isClosed() 서버 소켓 객체의 닫힌 상태를 반환
void setSoTimeout(int timeout) 서버 소켓 클래스의 accept() 메서드가 유효할 수 있는 시간을 밀리 세컨드로 설정
package Lecture.Week2;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
//서버

/*대기 하는 쪽 : 서버
* 찾아 가는 쪽 : 클라이언트
* 먼저 서버가 구동한다. => 포트번호로 묶고 구동해야한다.(1123)
* accept : 대기하다가 클라이언트가 찾아오면 소켓을 생성해서 리턴
* 클라이언트가 찾아가기 위해 ?ip, port번호
* 잘 찾아가면 소켓 생성
* 속 성공 시 두 소켓은 전혀 다른 것이지만 서로 통신할 수 있게 된다. */
public class Test06S {
    public  static void main(String[] args) throws Exception{
        ServerSocket svr = new ServerSocket(1123);
        System.out.println("before accept");

        Socket skt = svr.accept();
        System.out.println("after accept");

        InputStream in = new FileInputStream("a.txt");
        OutputStream out = skt.getOutputStream();

        int r = 0;
        while(( r = in.read()) != -1 ) {
            out.write(r);
            out.flush();//소켓으로 넘어가야함
        }

        out.close();
        in.close();


        System.out.println(r);
        out = new FileOutputStream("copy.txt");
        in = skt.getInputStream();
        r = 0;
        while((r = in.read())!= -1){
            out.write(r);
        }
        skt.close();

        svr.close();
    }
}

서버 & 서버 소켓 이용한 간단한 에코 프로그램

4. 예외 처리 (try - catch) : 사용자의 잘못된 조작, 개발자의 잘못된 코딩으로 인해 발생하는 프로그램 오류

 예외 구문

이유 

ArithmeticException

정수를 0으로 나눌경우 발생 

ArrayIndexOutOfBoundsExcetion

배열의 범위를 벗어난 index를 접근할 시 발생

ClassCastExcetion

변환할 수 없는 타입으로 객체를 반환 시 발생 

NullPointException 

 존재하지 않는 레퍼런스를 참조할때 발생 

IllegalArgumentException

잘못된 인자를 전달 할 때 발생 

IOException

입출력 동작 실패 또는 인터럽트 시 발생 

OutOfMemoryException 

메모리가 부족한 경우 발생  

NumberFormatException 

문자열이 나타내는 숫자와 일치하지 않는 타입의 숫자로 변환시 발생 

  • 예외 처리 코드 
try{
    //에러가 발생할 수 있는 코드
    throw new Exception(); //강제 에러 출력 
}catch (Exception e){
    //에러시 수행
     e.printStackTrace(); //오류 출력(방법은 여러가지)
     throw e; //최상위 클래스가 아니라면 무조건 던져주자
}finally{
    //무조건 수행
} 

문제

1. 점수 관리 프로그램

package HW7_프로그램만들기;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Scanner;
class Score {
    int Student_num;
    int score;
    Score(int Student_num, int score) {
        this.Student_num = Student_num;
        this.score = score;
    }
}
public class Test087 {
    static LinkedList<Score> l2 = null;
    static int Student_num = 0;
    static int score = 0;
    static Scanner scan;
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        scan = new Scanner(System.in);
        String l = null;
        while (true) {
            System.out.println("[ M E N U ]");
            System.out.println("1. 새 자료");
            System.out.println("2. 자료 입력");
            System.out.println("3. 파일로 저장");
            System.out.println("4. 파일에서 불러오기");
            System.out.print("> ");
            l = br.readLine();
            if (l.equals("1")) {
                l2 = new LinkedList<Score>();
                System.out.println("# 새롭게 리스트를 만들거나 초기화하였습니다.");
            } else if (l.equals("2")) {
                if (l2 == null) {
                    System.out.println("# 리스트 인스턴스가 없습니다. 1번을 선택하여 생성해주세요.");
                } else {
                    System.out.print("학번 : ");
                    Student_num = scan.nextInt();
                    System.out.print("점수 : ");
                    score = scan.nextInt();
                    l2.add(new Score(Student_num, score));
                    System.out.println("# 리스트에 학번이 " + Student_num + "인 학생의 점수를 추가했습니다.");
                }
            } else if (l.equals("3")) {
                BufferedWriter bw = new BufferedWriter(new FileWriter("scores.txt"));
                for (int i = 0; i < l2.size(); i++) {
                    bw.write((i + 1) + "번 째 학생 정보");
                    bw.newLine();
                    bw.write("Student_num: " + l2.get(i).Student_num);
                    bw.newLine();
                    bw.write("score: " + l2.get(i).score);
                    bw.newLine();
                    System.out.println("# 성적리스트를 파일로 저장하였습니다.");
                }
                bw.close();
            } else if (l.equals("4")) {
                l2 = new LinkedList<Score>();
                BufferedReader br2 = new BufferedReader(new FileReader("scores.txt"));
                String str = null;
                int r = 0;
                boolean flag = false;
                String[] s = null;
                int s_num = 0;
                int sc = 0;
                while ((str = br2.readLine()) != null) {
                    if (r % 3 == 1) {
                        s = str.split(": ");
                        s_num = Integer.parseInt(s[1]);
                        flag = true;
                        r++;
                        continue;
                    }
                    if (flag) {
                        flag = false;
                        s = str.split(": ");
                        sc = Integer.parseInt(s[1]);
                        l2.add(new Score(s_num, sc));
                    }
                    r++;
                }
                System.out.println("# 저장파일을 불러왔습니다.");
            } else if (l.equals("quit")) {
                System.out.println("# 프로그램을 종료합니다.");
                break;
            }
            if (l.equals("quit"))
                break;
        }
        br.close();
    }
}

2. mp3파일 소켓 저장

<Client>

package Task.Week2;

import java.io.*;
import java.net.Socket;
/*1. 서버에 접속할 소켓생성 CCC
2. 서버의 InputStream을 받아오기
- 서버의 data를 1 byte씩 받아 온다. (InputStream)
3. 저장할 파일에 연결
4. InputStream을 통해 받아온 data를 1 byte씩파일에 작성
- Data가 글자가 아닌 byte이므로 1 byte씩 저장 (FileOutputStream)
5. 연결 해제
*/

public class Client {
    public static void main(String[] args) {
        try(
                Socket skt = new Socket("127.0.0.1", 1123);
                ObjectOutputStream oos = new ObjectOutputStream(skt.getOutputStream());
                InputStream is = skt.getInputStream();
                ObjectInputStream ois = new ObjectInputStream(is);

        ){
            oos.writeUTF("music.mp3");
            oos.flush();
            int status = ois.readInt();
            System.out.println(status);
            if(status == 200){
                System.out.println("파일 받기");
                OutputStream file = new BufferedOutputStream(new FileOutputStream("music2.mp3"));
                int r = 0;
                while((r = is.read()) != -1){
                    System.out.println("파일 수신 준비");
                    file.write(r);
                }
            }else{

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

<Server>

package Task.Week2;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/*Server writeread SSSS
objectinput
1. 클라이언트에서의 접속을 받아 소켓을 생성해줄 서버소켓 생성
2. 클라이언트의 요청에 의해 소켓 생성
3. 클라이언트의 OutputStream을 받아오기
4. 음악파일에 연결
5. 음악파일을 1 byte씩 읽어 (readInt )클라이언트에 전송
- 음악파일에서 1 byte씩 가져왔으므로 Client에도 1 byte씩 보내주어야 함 (FileInputStream, OutputStream)
6. 전송이 끝나면 연결 해제
*/
public class Server {
    public static void main(String[] args) {

        System.out.println("Before accept()");
        try(
                ServerSocket svr = new ServerSocket(1123);
                Socket skt = svr.accept();
                ObjectInputStream ois = new ObjectInputStream(skt.getInputStream());
                OutputStream os = skt.getOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(os);
        ){

            System.out.println("After accept()");
            String title = ois.readUTF();
            File f = new File(title);
            boolean b = f.exists();
            System.out.println(b);
            if(b){
                oos.writeInt(200);
                oos.flush();

                InputStream file = new BufferedInputStream(new FileInputStream(title));
                int r = 0;
                while((r =file.read()) != -1){
                    System.out.println("파일 전송 준비");
                    os.write(r);
                    os.flush();
                }
                file.close();
                //파일이 길이를 리턴한다. (long 형 자료에 주의)
                System.out.println(f.length());
            }else{
                oos.writeInt(404);
                oos.flush();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Day 2

1. package Lecture.Week2;

public class Test11 {
public static void main(String[] args){
String l = "HelloWorld";
String t = l.substring(2,5);
String r = "HellWorld";
String t1 = l.substring(2,5);

System.out.println( r== l ); //StringPool형태로 나와서 -> false
/*""로 생성한 String은 POOl을 쓴다. 포인터가 비교 가능 , 그 외의 경우(substring) 은 pool쓴다는 보장이 없다
* 그떄는 equals로 비교한다.*/
System.out.println("llo" == t);//""로 비교하면 틀리게 나올수도 있따 -> false
System.out.println("llo".equals(t)); //true

int r2 = Integer.parseInt("100");
System.out.println( r2 == 100);//true
/*문자열을 숫자로 변환시에 : Double.parseDouble() 있음*/

String tl = "10101,100";
int idx = tl.indexOf(",");
System.out.println(tl.substring(0,idx));
System.out.println(tl.substring(idx + 1)); //아래 것보다 더 메모리 향상에 도움이 됨 . 아래는 몇개의 배열이 될 지 모르니까 / , 하나 정도 있을때 좋음

String[] ls = tl.split(",");//,가 여러 개 있는 경우 이 방법이 편함
System.out.println(ls[0]);
System.out.println(ls[1]);
}
}

/*false
false
true
true
10101
100
10101
100*/

2. 데이터베이스 (Mysql

데이터베이스를 먼저 구축 -> 안에 테이블 생성 

mysql> show databases;
mysql> create database study;
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| study              |
| test               |
+--------------------+
5 rows in set (0.00 sec)
mysql>use study; //사용하는 데이터베이스로 변경
mysql> create table study01t( //study01t 생성
    -> id int not null,              //자료형 ; int(4byte)
    -> score tinyint not null
//자료형 : tinyint(1byte)
    -> );
Query OK, 0 rows affected (0.01 sec)
mysql>drop table study01t; //테이블 지우기
mysql>insert into study01t values (10101, 100);//테이블에 값 입력
mysql>insert into study01t values(10102, 90);
mysql> select * from study01t;
+-------+-------+
| id         | score |
+-------+-------+
| 10101 |   100 |
| 10102 |    90 |
| 10103 |    80 |
+-------+-------+
3 rows in set (0.00 sec)
mysql>insert into study01t (score, id) //입력시 순서 바꾸어서 입력할 수 있다
     -> values(90, 10104);
Query OK, 1 row affected (0.00 sec)
mysql> select * from study01t; 
+-------+-------+ 
| id         | score | 
+-------+-------+ 
| 10101 |   100 | 
| 10102 |    90 | 
| 10103 |    80 | 
| 10104 |    90 | 
+-------+-------+ 
4 rows in set (0.00 sec)

-테이블에 있어야하는 개념 

  •   필드 (Field) - 컬럼
    • 자료형을 지정한다(int, tinyint)
    • 같은 자료형의 같은 의미의 값이 와야한다
  • 레코드(Record) - ROW
    • 입력의 단위 
    • 데이터들이 연관되어진 묶음

=> 이 두가지 개념이 있어야 테이블이라고 할 수 있다.

테이블 구성 요소

mysql> delete from study01t where id = 10101;  //where 조건을 만족하는 레코드를 없앤다.
Query OK, 1 row affected (0.01 sec)
mysql> select * from study01t; 
+-------+-------+ 
| id    | score | 
+-------+-------+ 
| 10102 |    90 | 
| 10103 |    80 | 
| 10104 |    90 | 
+-------+-------+ 
3 rows in set (0.00 sec)
mysql> delete from study01t where id <10104; 
Query OK, 2 rows affected (0.00 sec)
mysql> select * from study01t; 
+-------+-------+ 
| id    | score | 
+-------+-------+ 
| 10104 |    90 | 
+-------+-------+ 
1 row in set (0.00 sec)
mysql> delete from study01t;  //조건을 주지 않으면 다 지운다.
Query OK, 1 row affected (0.01 sec)
mysql> delete from study01t where 0 = 1; //모든 레코드가 만족하지 않아 지워지지 않음
mysql> delete from study01t where 1 = 1; //모든 레코드가 만족하니까 모두 지워짐
mysql> update study01t set score=90 where id = 10101; //조건만족 하는 것만 업데이트 해줌
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> update study01t set score = score - 10 where id = 10101; //수식 연산 조건도 가능 , 기존의 값 사용 가능 
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> update study01t set score = id - 10000 where id = 10101;  //같은 레코드의 다른 필드의 값을 가져와서도 변경 가능
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from study01t;
+-------+-------+
| id      | score |
+-------+-------+
| 10101 |   101 |
| 10102 |    90 |
| 10103 |    80 |
| 10104 |    90 |
+-------+-------+
4 rows in set (0.00 sec)
mysql> update study01t set score = id - 10000 where id != 10101;  
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0

mysql> select * from study01t;
+-------+-------+
| id    | score |
+-------+-------+
| 10101 |    80 |
| 10102 |   102 |
| 10103 |   103 |
| 10104 |   104 |
+-------+-------+
4 rows in set (0.00 sec)
mysql> update study01t set id = 0, score = 0 where id = 10101; //두 칼럼이 변경 시에는 "," 사용
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from study01t;
+-------+-------+
| id    | score |
+-------+-------+
|     0 |     0 |
| 10102 |   102 |
| 10103 |   103 |
| 10104 |   104 |
+-------+-------+
4 rows in set (0.00 sec)
mysql> select score+5, id from study01t  //select는 데이터를 가공해서 보여줄 수있다.
    -> where id != 0;  
+---------+-------+
| score+5 | id    |
+---------+-------+
|     107 | 10102 |
|     108 | 10103 |
|     109 | 10104 |
+---------+-------+
3 rows in set (0.00 sec)
mysql> select score + 5 as sungjuk, id from study01t where id != 0; //컬럼 이름 바꿔서 출력 하지만 실제로 바뀐 것 아니라 보여지는 거만 바꾸어짐 
+---------+-------+
| sungjuk | id    |
+---------+-------+
|     107 | 10102 |
|     108 | 10103 |
|     109 | 10104 |
+---------+-------+
3 rows in set (0.00 sec)
mysql> select score , score as sungjuk from study01t; //하나의 칼럼을 여러번 출력해도 무방하다.
+-------+---------+
| score | sungjuk |
+-------+---------+
|     0 |       0 |
|   102 |     102 |
|   103 |     103 |
|   104 |     104 |
+-------+---------+
4 rows in set (0.00 sec)

mysql> create table study02t(
    -> id char(5) not null,
    -> name varchar(10) null
    -> );
Query OK, 0 rows affected (0.02 sec)
 insert into study02t values('a0001', 'abcd'); //문자열 : ''로 감싼다. char or varchar 자료형 
//char : 고정길이 문자열 (학번, 주민번호) / 처리속도가 훨씬 빠름
-> 'a01' 넣어도 무조건 5자리 차지 (낭비 각오) 
//varchar : 길이를 최대값까지 설정해주지만 가변적이다 //처리 속도가 조금 느림
-> 'apple'을 넣으면 5자리만 공간 사용 , (낭비 적다)
mysql> select concat(id, '*') from study02t;
//oracle  : 'a01 *'
+-----------------+
| concat(id, '*') |
+-----------------+
| a0001*          |
| a0001*          |
| a0001*          |
+-----------------+
3 rows in set (0.00 sec)
mysql> select * from Studentt where addr = '역삼동'; //역삼동에 사는 모든 학생들 검색
mysql> select * from Studentt where addr LIKE '역%'; //역으로 시작하는 문장 검색
mysql> select * from Studentt where addr LIKE '%삼동'; //삼동으로 끝나는 문장 검색
mysql> select * from studentt
    -> where substr(addr, 1,2) = '역삼';

+-------+-----------+-----------+
| stId  | name      | addr      |
+-------+-----------+-----------+
| 10101 | 홍길동    | 역삼동    |
| 10103 | 이기자    | 역삼동    |
+-------+-----------+-----------+
2 rows in set (0.00 sec)
mysql> select substr(addr, 1,2) from studentt;  //부분 문자열 추출 가능
+-------------------+
| substr(addr, 1,2) |
+-------------------+
| 역삼              |
| 개포              |
| 역삼              |
| 한남              |
| 홍제              |
| 한남              |
+-------------------+
6 rows in set (0.00 sec)
mysql> select length(addr) from studentt;  //글자 길이 .utf-8인 경우 한글은 3바이트 
+--------------+
| length(addr) |
+--------------+
|            9 |
|            9 |
|            9 |
|            9 |
|            9 |
|            9 |
+--------------+
6 rows in set (0.00 sec)

#aggregate functions : 5가지 => 딱 하나의 결과만 나옴

min / max / count / avg /  sum

mysql> select * from scoret where subid = 'KOR1';
+-------+-------+-------+
| stId  | subId | score |
+-------+-------+-------+
| 10101 | KOR1  |    60 |
| 10102 | KOR1  |    90 |
| 10103 | KOR1  |    70 |
| 10104 | KOR1  |    80 |
| 10105 | KOR1  |    50 |
| 10106 | KOR1  |    60 |
+-------+-------+-------+
6 rows in set (0.00 sec)

mysql> select min(score) from scoret where subid = 'KOR1'; //국어점수 최소값 1개
+------------+
| min(score) |
+------------+
|         50 |
+------------+
1 row in set (0.00 sec)

## studentt , subjectt , scoret 는 얽혀있다 -> 여러개의 테이블이 연관 관계를 가지고 데이터베이스를 구성한다

 

mysql> select * from scoret where subid ='KOR1'
    ->  and stid IN( select stid from studentt where addr LIKE '역삼%');
//여러개 나오는 결과를 이용할 떄 IN , NOT IN 을 사용한다
//하나의 쿼리의 결과를 이용해서 다른 쿼리를 돌릴 수 있다 : 서브쿼리: ( ) 로 묶여 있는것
+-------+-------+-------+
| stId  | subId | score |
+-------+-------+-------+
| 10101 | KOR1  |    60 |
| 10103 | KOR1  |    70 |
+-------+-------+-------+
2 rows in set (0.00 sec)
mysql> select * from scoret where subid = 'KOR1' and
    -> score <= (select avg(Score) from scoret where subid =  'KOR1');
//유일한 서브쿼리의 결과와 비교는 비교연산자를 쓴다 
//서브쿼리는 반드시 괄호로 묶어 주어야 한다.
//국어 점수가 평균(68.666)이 안되는 학생 
+-------+-------+-------+
| stId  | subId | score |
+-------+-------+-------+
| 10101 | KOR1  |    60 |
| 10105 | KOR1  |    50 |
| 10106 | KOR1  |    60 |
+-------+-------+-------+
3 rows in set (0.00 sec)
mysql> select avg(score) from scoret where subid =  'MAT1' and stid in (select stid from studentt where name like '김%');  //김씨 성을 가진 학생들의 수학 평균
+------------+
| avg(score) |
+------------+
|    70.0000 |
+------------+
1 row in set (0.00 sec)
mysql> update scoret set score = score - 5 where subid = 'ENG1' and stid in ( select * from (select stid from scoret where subid = 'ENG1' and score <= 70) AS X); // 영어 70점 이하의 점수를 받은 학생들의 성적을 -5하라

"AGGREAGATE FUNCTION 은 GROUP BY , HAVING 과 연동된다"

mysql> select stid, avg(score) from scoret group by stid; //stid에 동일한 값을 가진 레코드를 짜매어 평균낸 결과
+-------+------------+
| stid  | avg(score) |
+-------+------------+
| 10101 |    76.6667 |
| 10102 |    93.3333 |
| 10103 |    76.6667 |
| 10104 |    73.3333 |
| 10105 |    63.3333 |
| 10106 |    66.6667 |
+-------+------------+
6 rows in set (0.00 sec)

 select stid, avg(score) form scoret group by stid where avg(score) <=75; error 

-> 왜 ? where은 통계처리에 우선한다.

   해서 having은 통계처리 이후에 동작한다. 


select stid, avg(score) from scoret group by stid having avg(score) <= 75;
 "" 서브쿼리는 크게 3종류로 나뉜다 . ""
   1. where 절의 서브쿼리
   2. from 절의 서브쿼리 ( inline view )
   3. select 절의 서브쿼리 ( 엄청난 결과 / 엄청난 부담 )
   
from 절의 서브쿼리 : select 결과를 마치 table처럼 보면 된다. 

select stid, avg(score) as xx from scoret group by stid;
+-------+------+
| stid  | xx   |
+-------+------+
| 10101 |   77 |
| 10102 |   93 |
| 10103 |   77 |
| 10104 |   72 |
| 10105 |   62 |
| 10106 |   67 |
+-------+------+ 


select stid, round(avg(score), 2) as xx from scoret group by stid;
+-------+-------+
| stid  | xx    |
+-------+-------+
| 10101 | 76.67 |
| 10102 | 93.33 |
| 10103 | 76.67 |
| 10104 | 71.67 |
| 10105 | 61.67 |
| 10106 | 66.67 |
+-------+-------+
//round(): 반올림 하기

select * from ( select stid, round(avg(score), 2) as xx
from scoret group by stid) where xx <= 75;
mysql> create view score2v as
    -> select stid, round(avg(score), 2) as xx from
    -> scoret group by stid;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from score2v;
+-------+-------+
| stid  | xx    |
+-------+-------+
| 10101 | 76.67 |
| 10102 | 93.33 |
| 10103 | 76.67 |
| 10104 | 73.33 |
| 10105 | 63.33 |
| 10106 | 66.67 |
+-------+-------+
6 rows in set (0.00 sec)

# 뷰는 실제로 데이터가 존재하는 테이블이 아니라 테이블 데이터를 이용해서 만들어진 하나의 결과 화면일 뿐 이다.

# 뷰를 대상으로 수정 삭제는 무의미 하다.

 

mysql> select stid, name, (select avg(score) from scoret) as avg from studentt;
+-------+-----------+---------+
| stid  | name      | avg     |
+-------+-----------+---------+
| 10101 | 홍길동    | 75.0000 |
| 10102 | 고길동    | 75.0000 |
| 10103 | 이기자    | 75.0000 |
| 10104 | 박기자    | 75.0000 |
| 10105 | 김영삼    | 75.0000 |
| 10106 | 김대중    | 75.0000 |
+-------+-----------+---------+
6 rows in set (0.00 sec)

 

mysql> select x.stid, x.name from studentt as x; //studentt 가 너무 기니까 x로 바꾸어 쓴다
mysql> select studentt.stid, studentt.name from studentt;  //테이블명.컬럼명 식 
+-------+-----------+
| stid  | name      |
+-------+-----------+
| 10101 | 홍길동    |
| 10102 | 고길동    |
| 10103 | 이기자    |
| 10104 | 박기자    |
| 10105 | 김영삼    |
| 10106 | 김대중    |
+-------+-----------+
mysql> select x.stid, x.name, (select avg(score) from scoret where stid = x.stid) as avg from studentt as x;
+-------+-----------+---------+
| stid  | name      | avg     |
+-------+-----------+---------+
| 10101 | 홍길동    | 76.6667 |
| 10102 | 고길동    | 93.3333 |
| 10103 | 이기자    | 76.6667 |
| 10104 | 박기자    | 73.3333 |
| 10105 | 김영삼    | 63.3333 |
| 10106 | 김대중    | 66.6667 |
+-------+-----------+---------+
6 rows in set (0.00 sec)
mysql> select x.stid, x.avg from(select stid, avg(score) as avg from scoret group by stid)as x;
+-------+---------+
| stid  | avg     |
+-------+---------+
| 10101 | 76.6667 |
| 10102 | 93.3333 |
| 10103 | 76.6667 |
| 10104 | 73.3333 |
| 10105 | 63.3333 |
| 10106 | 66.6667 |
+-------+---------+

 

create table temp01t as
->select stid, avg(score) as avg from 
->scoret group by stid;
+-------+---------+

| stid  | avg     |
+-------+---------+
| 10101 | 76.6667 |
| 10102 | 93.3333 |
| 10103 | 76.6667 |
| 10104 | 73.3333 |
| 10105 | 63.3333 |
| 10106 | 66.6667 |
+-------+---------+
6 rows in set (0.00 sec)
mysql> select x.stid, x.avg,(select count(*)+1 from temp01t where avg > x.avg) as rank from temp01t as x;  //등수
+-------+----------+------+
| stid  | avg      | rank |
+-------+----------+------+
| 10101 | 100.0000 |    1 |
| 10102 |  93.3333 |    2 |
| 10103 |  76.6667 |    3 |
| 10104 |  73.3333 |    4 |
| 10105 |  63.3333 |    6 |
| 10106 |  66.6667 |    5 |
+-------+----------+------+

서브쿼리가 여섯명의 등수를 구할 떄 쿼리가 6*6으로 36번이나 돌아야한다 . 만약 1000명이라면? 말이안됨

-> 임시 테이블을 만들자

mysql> select * from temp02t order by rank;
+-------+----------+------+
| stid  | avg      | rank |
+-------+----------+------+
| 10101 | 100.0000 |    1 |
| 10102 |  93.3333 |    2 |
| 10103 |  76.6667 |    3 |
| 10104 |  73.3333 |    4 |
| 10106 |  66.6667 |    5 |
| 10105 |  63.3333 |    6 |
+-------+----------+------+
6 rows in set (0.00 sec)

mysql> select * from temp02t order by rank desc;
+-------+----------+------+
| stid  | avg      | rank |
+-------+----------+------+
| 10105 |  63.3333 |    6 |
| 10106 |  66.6667 |    5 |
| 10104 |  73.3333 |    4 |
| 10103 |  76.6667 |    3 |
| 10102 |  93.3333 |    2 |
| 10101 | 100.0000 |    1 |
+-------+----------+------+
6 rows in set (0.00 sec)

-임시테이블과 뷰는 흩어진 데이터에서 자신이 원하는 데이터로 가공할 수 있는 방법 제공(비정형 데이터에서 정형화 된 데이터를 만들어 낸다)

-뷰는 오버헤드가 있지만 데이터 변경을 즉각 반영한다 / 임시테이블은 오버헤드가 적지만, 데이터의 변경을 즉각 반영 못함

-select 서브쿼리는 오버헤드가 크다 (1000명의 등수를 처리하는 결과를 1000명이 동시 열람하면 100만건의 쿼리가 동작하는 셈 -> group by 오버헤드 포함) 

-임시 테이블은 이런 부담을 극적으로 줄여준다

 

mysql> create table study3t(
    -> no int not null auto_increment primary key,
    -> theTime datetime not null
    -> );
mysql> insert into study3t values(default, now());
Query OK, 1 row affected (0.01 sec)

mysql> select * from study3t;
+----+---------------------+
| no | theTime             |
+----+---------------------+
|  1 | 2019-07-23 17:16:05 |
|  2 | 2019-07-23 17:16:16 |
+----+---------------------+
2 rows in set (0.00 sec)

now() : 현재 시간 => 입력 시 datetime 자료형 쓴다.

//datetime 자료형에 들어있는 값은 연산이 가능하다.

 

mysql> select no, date_add(theTime, INTERVAL 1 MONTH) from study3t;
+----+-------------------------------------+
| no | date_add(theTime, INTERVAL 1 MONTH) |
+----+-------------------------------------+
|  1 | 2019-08-23 17:16:05                 |
|  2 | 2019-08-23 17:16:16                 |
+----+-------------------------------------+
2 rows in set (0.00 sec)
mysql> select no, date_add(theTime, INTERVAL 4 DAY) from study3t;
+----+-----------------------------------+
| no | date_add(theTime, INTERVAL 4 DAY) |
+----+-----------------------------------+
|  1 | 2019-07-27 17:16:05               |
|  2 | 2019-07-27 17:16:16               |
+----+-----------------------------------+
2 rows in set (0.00 sec)

mysql> select no, date_add(theTime, INTERVAL 4 HOUR) from study3t;
+----+------------------------------------+
| no | date_add(theTime, INTERVAL 4 HOUR) |
+----+------------------------------------+
|  1 | 2019-07-23 21:16:05                |
|  2 | 2019-07-23 21:16:16                |
+----+------------------------------------+
2 rows in set (0.00 sec)

//날짜 데이터를 다룰 때 연산의 필요성이 없으면 char 쓴다.

mysql> create table study04t(
    -> no int not null auto_increment primary key,
    -> theTime char(19) not null
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> insert into study04t values (default, now());
Query OK, 1 row affected (0.01 sec)

mysql> select * from study04t;
+----+---------------------+
| no | theTime             |
+----+---------------------+
|  1 | 2019-07-23 17:27:03 |
+----+---------------------+
1 row in set (0.00 sec)
반응형

'Language Study > Java' 카테고리의 다른 글

제주에서 자바_Week2_3  (0) 2019.07.25
제주에서 자바_Week2_2  (0) 2019.07.24
제주에서 자바_Week1  (0) 2019.07.20
4. 클래스  (0) 2019.05.29
3. 참조 타입  (0) 2019.05.28

+ Recent posts