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();
}
}
<%@ 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;
}
}
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();
}
}
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>
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....
*/
* > 아무런 제약이 없다면 이렇게 동시 진행될 수도 있다 * 쓰레드는 독자적이기 떄문에 일어나는 현상 * -> 화장실 문을 잠가야 하니까
=> 그것을 동기화(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()
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
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() : 좌/우 공백 문자를 제거하는 역할을 한다
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();
}
}
}
//향상된 코드
mysql>SELECT name, addr, score From studentt INNER JOIN scoret ON studentt.stid = scoret.stid WHERE subid = 'MAT1'; //join을 이용하면 흩어진 데이터를 통합해서 보여지게 할 수 있다 (서브 쿼리도 가능 , 헌대 성능이 틀리다) -> 해서 같은 결과를 만들되 성능이 향상되게 만드는 것이 SQL 튜닝의 영역
-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.
모든 호스트는 인터넷 주소(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 * 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 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)