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