Section 4. 더 깊이 알아보기

기본키

중복되지 않는 고유값만 허용
NULL 값 허용하지 않음
테이블당 하나의 기본키만 지정 가능

1
2
3
4
5
6
7
-- 기본키 넣는 방법 2
CREATE TABLE people (
first_name CHAR(2),
last_name CHAR(3),
nickname VARCHAR(10),
PRIMARY KEY (first_name)
);

다중 기본키

1
2
3
4
5
6
CREATE TABLE people (
first_name CHAR(2),
last_name CHAR(3),
nickname VARCHAR(10),
PRIMARY KEY (first_name, last_name)
);

고유키

중복 제한, NULL 값 가능

1
2
3
4
5
6
7
-- 고유키 넣는 방법 2
CREATE TABLE people (
person_id INT AUTO_INCREMENT PRIMARY KEY,
first_name CHAR(2),
last_name CHAR(3),
UNIQUE (first_name)
);

외래키

1
2
3
4
5
6
ALTER TABLE _자식테이블명
ADD CONSTRAINT _제약명
FOREIGN KEY ( _자식테이블외래키 )
REFERENCES 부모테이블명 ( _부모테이블기본키 )
-- ON DELETE _삭제시제약
-- ON UPDATE _수정시제약

외래키 제약

제약 |설명 |비고
——— | ———
NO ACTION, RESTRICT| 자식 테이블에 해당 외래키가 있을 때 수정/삭제되지 않음 |
CASCADE |자식 테이블의 해당 행도 수정/삭제 |
SET NULL |자식 테이블의 외래키를 NULL로 |자식 외래키가 NOT NULL일 시 설정 불가
SET DEFAULT |자식 테이블의 외래키를 기본값으로 |InnoDB 엔진에서 사용 불가

(오키) 자바의정석, 챕터 13 - 쓰레드

쓰레드 구현과 실행

1.Thread 클래스 상속

1
2
3
4
5
6
7
8
9
10
class MyThread extends Thread {
public void run() { // run을 오버라이딩

// 작업 내용
// this.getName();
}
}

MyThread t1 = new MyThread();
t1.start();

2.Runnable 인터페이스 구현

1
2
3
4
5
6
7
8
9
10
11
12
class myThread2 implements Runnable {
public void run() { // 인터페이스 추상 메서드 run 구현

// 작업 내용
//Thread.currentThread().getName();
}
}

Runnable r = new MyThread2();
Thread t2 = new Thread(r); // Thread(Runnable r)
// Thread t2 = new Thread(new MyThread2());
t2.start();

쓰레드가 종료 될때까지 기달리는 함수 join();

1
2
t1.join();
t2.join();

쓰레드의 I/O 블락킹 (blocking)

쓰레드의 우선순위 함수 setPriority (int newPriority);
인자로 쓰는 상수
MAX_PRIORITY = 10; // 최대
NORM_PRIORITY = 5; //보통
MIN_PRIOIRTY = 1; // 최소

쓰레드 그룹, 지정하지 않으면 main 쓰레드 그룹에 속하게 되고 자신이 상속한 부모의 우선순위를 따라간다. (5)

13-18 데모 쓰레드 (deamon thread)

일반 쓰레드의 작업을 돕는 보조적인 역할 수행
일반 쓰레드가 종류 되면 자동으로 종료

사용 처: 가비지 컬렉터, 자동저장, 화면 자동 갱신 등

일반 적인 구현 예: 무한루프에 조건문 확인 하여 특정 일을 처리 이후 대기

1
2
3
4
5
6
7
8
9
10
11
12
13
public void run() {
while(true) {
try {
Thread.sleep(3*1000); // 3초마다 대기
}
if(autoSave) { // 조건문 확인
autoSave(); // 일 처리
}
}
}
Thread t = new Thread(new)
setDaemon(boolean on); // 설정
isDeamon() ; 데몬 쓰레드 인지 확인

13-20 쓰레드의 상태

생성 만 된 상태 (start() 호출 전): NEW
실행 혹은 실행 가능한 상태 (줄서있는 상태): RUNNABLE
동기화 블럭에 위해 일시정된 상태(LOCK 풀릴때까지): BLOCKED
일시정지 상태:WAITING, TIMED_WAITING
종료: TERMINATED

suspend(); // 일시 정지

sleep(long mills); // 잠자기
wait(); join(); // 기다리기

I/O block; // 입출력 대기 상태
interrupt(); // 깨우는 것
stop();
resume();
yield();

sleep()

exception 이 필수로 나와서 try catch 로 싸야 한다.
util 함수를 하나 만들어 쓰면 간편

interrupt()

대기 상태(WAITING)를 실행 대기 상태(RUNNABLE)로 만든다.

1
2
3
4
5
6
7
8
class ThreadEx extends Thread {
public void run() {
//...
while( downloaded && !isInterrupted()) {
// download 완료 혹은 취소
}
}
}

suspend(), resume(), stop()

dead-lock 교착 상태 발생 빈번이 되어서 현재 deprecated 되었음 > 사용 권장 X
유사 기능이 필요할때는 멤버 변수를 활용 해서 유저 레벨 에서 구현 하면 된다.

join()

th1.join(); // th1이 종료 할때까지 기달린다.
try - catch 로 묶고 Interrupted Exception로 나올수도 있다.

yield()

yield()와 interrupt()을 적절히 사용 하면 응답성과 효율을 높힌다.
sleep() 으로 길게 돌고 있을때 busy-wait 가 될수 있다.

그래서 interrupt 로 빨리 깨워서 동작 시키거나
sleep() 하는 대신 yield() 호출 해서 효율을 높힌다.

동기화 synchronization

  • 멀티 쓰레드, 서로 간섭이 없도록 ‘동기화’ 해준다

임계영역 : critical section
lock을 얻은 쓰레드 한개만 임계영역에 들어갈수 있다.

1.메세드 전체 임계 영역 지정

1
2
3
4
public synchronized void calcSum() {

//.. 전체를 critical section 으로 지정
}

2.특정 부분만 지정

1
2
3
synchronized(객체의 참조 변수) {
// ...
}

wait()와 notify()

동기화 효율을 높이기 위해 wait(), notify() 사용
Object 클래스에 정의 되어 있으며, 동기화 블록 내에서만 사용 할수 있다.

wait() - 객체의 lock을 풀고 쓰레드를 해당 객체의 waiting pool 에 넣는다.
notify() - waiting pool 에서 대기 중인 쓰레드 중의 하나를 깨운다
notifyAll() - waiting pool 에서 대기 중인 모든 쓰레드를 깨운다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Account {
int balance = 1000;

public synchronized void withdraw(int money) {
while (balance < money) {
try {
wait(); // 대기 - 락을 풀고 대기 한다

} catch (interruptedException e) {}
}
balance -= money;
}

public synchronized void deposit(int money) {
balance += money;
notify(); // - 대기 중인 쓰레드 중 하나 에게 알림
}
}

Section 3. MySQL 설치

테이블 생성, 변경, 삭제 및 데이타 입력

테이블 생성 CREATE TABLE
변경 ALTER TABLE, CHANGE COLUMN
삭제 DROP COLUMN, DROP TABLE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CREATE TABLE people (
person_id INT,
person_name VARCHAR(10),
age TINYINT,
birthday DATE
);

-- 테이블명 변경
ALTER TABLE people RENAME TO friends,

-- 컬럼 자료형 변경
CHANGE COLUMN person_id person_id TINYINT,

-- 컬럼명 변경
CHANGE COLUMN person_name person_nickname VARCHAR(10),

-- 컬럼 삭제
DROP COLUMN birthday,

-- 컬럼 추가
ADD COLUMN is_married TINYINT AFTER age;

DROP TABLE friends;

값입력 INSERT INTO

1
2
3
4
5
6
7
8
9
10
INSERT INTO people
VALUES (2, '전우치', 18, '2003-05-12');
-- 여러 행을 한 번에 입력 가능

INSERT INTO people
(person_id, person_name, age, birthday)
VALUES
(4, '존 스미스', 30, '1991-03-01'),
(5, '루피 D. 몽키', 15, '2006-12-07'),
(6, '황비홍', 24, '1997-10-30');

테이블 생성시 제약 넣기

AUTO_INCREMENT 새 행 생성시 자동 1씩 증가
PRIMARY KEY 중복 입력 불가 / 빈 값 불가
UNIQUE 중복 입력 불가
NOT NULL 빈 값 불가
UNSIGNED 양수 only
DEFAULT 값이 없을때 기본값

1
2
3
4
5
6
7
CREATE TABLE people (
person_id INT AUTO_INCREMENT PRIMARY KEY,
person_name VARCHAR(10) NOT NULL,
nickname VARCHAR(10) UNIQUE NOT NULL,
age TINYINT UNSIGNED,
is_married TINYINT DEFAULT 0
);

숫자 자료형

정수, 각 1,2,3,4,8 Bytes
TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT

고정소수점(Fixed Point) 수, 좁은 범위의 수, 정확한 값
DECIMAL(s,d) 실수 부분 s와 소수 부분 d

부동소수점(Floating Point) 수, 넓은 범위의 수, 덜 정확한 값
FLOAT, DOUBLE

문자 자료형

CHAR(s), VARCHAR(s) Fixed와 가변 문자열(실제 글자수 + 1Byte for 글자수 정보)
행 최대 저장이 65,535 이라서 VARCHAR 을 65,535 까지 쓰면 행에 다른 값 저장이 안됨

TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT 긴 글을 저장 할때 사용 LONGTEXT은 4G 까지 저장 가능

시간 자료형

DATE, TIME
DATETIME (입력된 시간 자체 저장), TIMESTAMPE (설치된 컴퓨터의 시간대로 저장)

  • 시간 데이터를 가감없이 기록 할때 DATETIME
  • 시간 자동 기록, 국제적인 서비스 할 경우 TIMESTAMP 사용

데이터 변경, 삭제

DELETE: WHERE 와 함께 사용 해서 삭제, WHERE 없을시 전부 삭제 되니 주의 요
TRUNCATE: 테이블 초기화 로 AUTO INCREMENT 하던 ID 값등이 RESET 된다.

1
2
DELETE FROM businesses
WHERE status = 'CLS';

UPDATE : 자료 업데이트 ‘SET’ 와 ‘WHERE’ 와 같이 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
UPDATE menus
SET menu_name = '삼선짜장'
WHERE menu_id = 12;

UPDATE menus
SET
menu_name = '열정떡볶이',
kilocalories = 492.78,
price = 5000
WHERE
fk_business_id = 4
AND menu_name = '국물떡볶이';

-------------------------------------------

UPDATE menus
SET price = price + 1000
WHERE fk_business_id = 8;

UPDATE menus
SET menu_name = CONCAT('전통 ', menu_name)
WHERE fk_business_id IN (
SELECT business_id
FROM sections S
LEFT JOIN businesses B
ON S.section_id = B.fk_section_id
WHERE section_name = '한식'
);

`WHERE’ 없으면 전부 업데이트 됨으로 주의 요

1
2
UPDATE menus
SET menu_name = '획일화';

예제 프로젝트 Database 및 값

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
CREATE TABLE sections (
section_id INT AUTO_INCREMENT PRIMARY KEY,
section_name CHAR(3) NOT NULL,
floor TINYINT NOT NULL
);

INSERT INTO sections (section_name, floor)
VALUES ('한식', 2),
('분식', 2),
('중식', 3),
('일식', 3),
('양식', 3),
('카페', 1),
('디저트', 1);

-----------------------------------------------------------------------------

CREATE TABLE businesses (
business_id INT AUTO_INCREMENT PRIMARY KEY,
fk_section_id INT NOT NULL,
business_name VARCHAR(10) NOT NULL,
status CHAR(3) DEFAULT 'OPN' NOT NULL,
can_takeout TINYINT DEFAULT 1 NOT NULL
);

INSERT INTO businesses (fk_section_id, business_name, status, can_takeout)
VALUES (3, '화룡각', 'OPN', 1),
(2, '철구분식', 'OPN', 1),
(5, '얄코렐라', 'RMD', 1),
(2, '바른떡볶이', 'OPN', 1),
(1, '북극냉면', 'OPN', 0),
(1, '보쌈마니아', 'OPN', 1),
(5, '에그사라다', 'VCT', 1),
(6, '달다방', 'OPN', 1),
(7, '마카오마카롱', 'OPN', 1),
(2, '김밥마라', 'OPN', 1),
(7, '소소스윗', 'OPN', 1),
(4, '사사서셔소쇼스시', 'VCT', 1),
(3, '린민짬뽕', 'CLS', 1),
(7, '파시조아', 'OPN', 1),
(1, '할매장국', 'CLS', 0),
(5, '노선이탈리아', 'OPN', 1),
(6, '커피앤코드', 'OPN', 1),
(2, '신림동백순대', 'VCT', 1);

-----------------------------------------------------------------------------

CREATE TABLE menus (
menu_id INT AUTO_INCREMENT PRIMARY KEY,
fk_business_id INT NOT NULL,
menu_name VARCHAR(20) NOT NULL,
kilocalories DECIMAL(7,2) NOT NULL,
price INT NOT NULL,
likes INT DEFAULT 0 NOT NULL
);

INSERT INTO menus (fk_business_id, menu_name, kilocalories, price, likes)
VALUES (5, '물냉면', 480.23, 8000, 3),
(8, '아메리카노', 16.44, 4500, 6),
(17, '고르곤졸라피자', 1046.27, 12000, 12),
(6, '보쌈', 1288.24, 14000, 2),
(15, '장국', 387.36, 8500, -1),
(17, '까르보나라', 619.11, 9000, 10),
(9, '바닐라마카롱', 160.62, 1500, 4),
(16, '백순대', 681.95, 11000, 24),
(6, '마늘보쌈', 1320.49, 16000, 7),
(16, '양념순대볶음', 729.17, 12000, 0),
(14, '단팥빵', 225.88, 1500, 13),
(1, '간짜장', 682.48, 7000, 3),
(9, '뚱카롱', 247.62, 2000, 8),
(5, '비빔냉면', 563.45, 8000, 4),
(10, '참치김밥', 532.39, 3000, 0),
(2, '치즈떡볶이', 638.42, 5000, 15),
(11, '플레인와플', 299.31, 6500, 2),
(2, '찹쌀순대', 312.76, 3000, -4),
(15, '육개장', 423.18, 8500, 2),
(4, '국물떡볶이', 483.29, 4500, 1),
(10, '돈가스김밥', 562.72, 4000, 0),
(1, '삼선짬뽕', 787.58, 8000, 32),
(11, '수플레팬케익', 452.37, 9500, 5),
(4, '라볶이', 423.16, 5500, 0),
(8, '모카프라푸치노', 216.39, 6000, 8),
(14, '옛날팥빙수', 382.35, 8000, 2);

-----------------------------------------------------------------------------

CREATE TABLE ratings (
rating_id INT AUTO_INCREMENT PRIMARY KEY,
fk_business_id INT NOT NULL,
stars TINYINT NOT NULL,
comment VARCHAR(200) null,
created timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL
);

INSERT INTO ratings (fk_business_id, stars, comment, created)
VALUES (2, 4, '치떡이 진리. 순대는 별로', '2021-07-01 12:30:04'),
(16, 3, '그냥저냥 먹을만해요', '2021-07-01 17:16:07'),
(14, 5, '인생팥빵. 말이 필요없음', '2021-07-03 11:28:12'),
(5, 3, '육수는 괜찮은데 면은 그냥 시판면 쓴 것 같네요.', '2021-07-04 19:03:50'),
(11, 4, '나오는데 넘 오래걸림. 맛은 있어요', '2021-07-04 13:37:42'),
(9, 2, '빵집에서 파는 마카롱이랑 비슷하거나 못합니다.', '2021-07-06 15:19:23'),
(16, 5, '신림에서 먹던 맛 완벽재현', '2021-07-06 20:01:39');

Section 2. 쿼리 와 조인

1. 비상관/ 상관 서브 쿼리

우선 서브 쿼리란 () 으로 쿼리 안에 쿼리를 부르는 기능이다.

1
2
3
4
5
6
7
SELECT
CategoryID, CategoryName, Description
FROM Categories
WHERE
CategoryID = ANY
(SELECT CategoryID FROM Products
WHERE Price > 50);

이 예제에 IN, ALL, ANY 연산자가 있는데 ‘= ANY’ 은 IN 와 같은 효과 이고
서브 쿼리에 자주 쓰인는 연산자 이다.

한개 테이블에 대해서 쿼리 할때 비상관 이라 하고 안과 밖에 쿼리가 서로 관계 해서 쿼리 하는 걸 상관 쿼리 라고 한다. 아래 예제 처럼 table 2개를 연관 하는 경우다.

1
2
3
4
5
6
7
SELECT
ProductID, ProductName,
(
SELECT CategoryName FROM Categories C
WHERE C.CategoryID = P.CategoryID
) AS CategoryName
FROM Products P;

다수의 예제다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
SELECT
CategoryID, CategoryName,
(
SELECT MAX(Price) FROM Products P
WHERE P.CategoryID = C.CategoryID
) AS MaximumPrice,
(
SELECT AVG(Price) FROM Products P
WHERE P.CategoryID = C.CategoryID
) AS AveragePrice
FROM Categories C;

SELECT
ProductID, ProductName, CategoryID, Price
-- ,(SELECT AVG(Price) FROM Products P2
-- WHERE P2.CategoryID = P1.CategoryID)
FROM Products P1
WHERE Price < (
SELECT AVG(Price) FROM Products P2
WHERE P2.CategoryID = P1.CategoryID
);

SELECT
CategoryID, CategoryName
-- ,(SELECT MAX(P.Price) FROM Products P
-- WHERE P.CategoryID = C.CategoryID
-- ) AS MaxPrice
FROM Categories C
WHERE EXISTS (
SELECT * FROM Products P
WHERE P.CategoryID = C.CategoryID
AND P.Price > 80
);

2. JOIN - 여러 테이블 조립하기

2개 테이블을 연관 해서 가져온다. 구문이 JOIN, ON 들어간다.
제일 기본이 Inner Join이라고 하고 양쪽 모두에 값이 있는 행만 반환 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SELECT C.CategoryID, C.CategoryName, P.ProductName
FROM Categories C
JOIN Products P
ON C.CategoryID = P.CategoryID;
-- ambiguous 주의!

SELECT
CONCAT(
P.ProductName, ' by ', S.SupplierName
) AS Product,
S.Phone, P.Price
FROM Products P
JOIN Suppliers S
ON P.SupplierID = S.SupplierID
WHERE Price > 50
ORDER BY ProductName;

여러 테이블을 조인 할수 있고 GROUP BY 도 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
SELECT 
C.CategoryID, C.CategoryName,
P.ProductName,
O.OrderDate,
D.Quantity
FROM Categories C
JOIN Products P
ON C.CategoryID = P.CategoryID
JOIN OrderDetails D
ON P.ProductID = D.ProductID
JOIN Orders O
ON O.OrderID = D.OrderID;

SELECT
C.CategoryName, P.ProductName,
MIN(O.OrderDate) AS FirstOrder,
MAX(O.OrderDate) AS LastOrder,
SUM(D.Quantity) AS TotalQuantity
FROM Categories C
JOIN Products P
ON C.CategoryID = P.CategoryID
JOIN OrderDetails D
ON P.ProductID = D.ProductID
JOIN Orders O
ON O.OrderID = D.OrderID
GROUP BY C.CategoryID, P.ProductID;

SELF JOIN 이라고 한개의 테이블로도 가능 하다

1
2
3
4
5
6
7
8
SELECT
E1.EmployeeID, CONCAT_WS(' ', E1.FirstName, E1.LastName) AS Employee,
E2.EmployeeID, CONCAT_WS(' ', E2.FirstName, E2.LastName) AS NextEmployee
FROM Employees E1
JOIN Employees E2
ON E1.EmployeeID + 1 = E2.EmployeeID;

-- 1번의 전, 마지막 번호의 다음은?

값이 없는 행을 가져 오고 싶을 때는 쓰는 것이 외부 조인이고 LEFT/RIGHT OUTER JOIN
왼쪽 NULL 값도 보여줄때 LEFT, 오른쪽 은 RIGHT 이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
SELECT
C.CustomerName, S.SupplierName,
C.City, C.Country
FROM Customers C
LEFT JOIN Suppliers S
ON C.City = S.City AND C.Country = S.Country;
-- LEFT를 RIGHT로 바꿔서도 실행해 볼 것

SELECT
IFNULL(C.CustomerName, '-- NO CUSTOMER --'),
IFNULL(S.SupplierName, '-- NO SUPPLIER --'),
IFNULL(C.City, S.City),
IFNULL(C.Country, S.Country)
FROM Customers C
LEFT JOIN Suppliers S
ON C.City = S.City AND C.Country = S.Country;

-- LEFT를 RIGHT로 바꿔서도 실행해 볼 것

IFNULL 활용해서 없는 값에 원하는 구문 넣을수 있다.

조건 없이 모든 조합을 해 보는 것을 CROSS JOIN 이라고 한다.

1
2
3
4
5
SELECT
E1.LastName, E2.FirstName
FROM Employees E1
CROSS JOIN Employees E2
ORDER BY E1.EmployeeID;

3. UNION - 집합으로 다루기

합집합: UNION, UNION ALL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT CustomerName AS Name, City, Country, 'CUSTOMER'
FROM Customers
UNION
SELECT SupplierName AS Name, City, Country, 'SUPPLIER'
FROM Suppliers
ORDER BY Name;

SELECT CategoryID AS ID FROM Categories
WHERE CategoryID > 4
UNION
SELECT EmployeeID AS ID FROM Employees
WHERE EmployeeID % 2 = 0;

-- UNION ALL로 바꿔볼 것

교집합

1
2
3
4
5
6
SELECT CategoryID AS ID
FROM Categories C, Employees E
WHERE
C.CategoryID > 4
AND E.EmployeeID % 2 = 0
AND C.CategoryID = E.EmployeeID;

차집합

1
2
3
4
5
6
7
8
9
SELECT CategoryID AS ID
FROM Categories
WHERE
CategoryID > 4
AND CategoryID NOT IN (
SELECT EmployeeID
FROM Employees
WHERE EmployeeID % 2 = 0
);

대칭차집합: 교집합만 제외

1
2
3
4
5
6
7
8
SELECT ID FROM (
SELECT CategoryID AS ID FROM Categories
WHERE CategoryID > 4
UNION ALL
SELECT EmployeeID AS ID FROM Employees
WHERE EmployeeID % 2 = 0
) AS Temp
GROUP BY ID HAVING COUNT(*) = 1;

(오키) 자바의정석, 챕터 12 - Generics, Enum, Annotation

12-1 Generics 란?

  • 컴파일시 타입을 체크해 주는 기능 (compile-time type check) - JDK1.5
  • 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여줌

12-2 타입변수

  • 클래스를 작성 할때, Object 타입 대신 타입 변수(E)를 선언해서 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ArrayList extends AbstractList {
private transient Object[] elementData;
public boolean add(Object o) { }
public Object get(int index) { }
// ...
}

public class ArrayList<E> extends AbstractList<E> {
private transient E[] elementData;
public boolean add(E o) { }
public E get(int index) { }
// ...
}

12-3 타입 변수에 대입하기

  • 객체를 생성시, 타입 변수(E) 대신 실제 타입(Tv)을 지정(대입)
  • 타입 변수 대신 실제 타입이 지정되면, 형변환 생략 가능
1
ArrayList<Tv> tvList = new ArrayList<Tv>();

12-4 Generics 용어

1
2
3
Box<T>    지네릭 클래스 'T의 Box' 또는 'T Box' 라고 읽는다.
T 타입변수 또는 타입 매개 변수 (T는 타입 문자)
Box 원시 타입 (Raw type)

12-7 Iterator<E>

  • 클래스를 작성할 때, Object 타입 대신 T와 같은 타입 변수를 사용

12-8 HashMap <K,V>

  • 여러 개의 타입 변수가 필요한 경우, 콤마(,)를 구분자로 선언
1
2
HashMap<String, Student> map = new HashMap<String, Student>(); // 생성
map.put("자바왕", new Student("자바왕", ..));

12-9 제한 된 지네릭 클래스

  • extends 로 대입할수 있는 타입을 제한
1
2
3
4
class FruitBox<T extends Fruit> { // Fruit의 자손만 타입으로 지정 가능
ArrayList<T> list = new ArrayList<T>();
//...
}
  • 인터페이스인 경우에도 extends를 사용
1
2
3
4
interface Eatable {}
class FruitBox<T extends Eatable> {
// ...
}

12-11 지네릭스의 제약

  • 타입 변수에 대입은 인스턴스 별로 다르게 가능
1
2
Box<Apple> appleBox = new Box<Apple>();
Box<Grape> grapeBox = new Box<Grape>();
  • static 멤버에 타입 변수 사용 불가
1
2
3
4
5
6
class Box<T> {
static T item; // 에러
static int compare(T t1, T t2) { // 에러
// ...
}
}
  • 배열 생성 할때 타입 변수 사용 불가. 타입 변수로 배열 선언은 가능
1
2
3
4
5
6
class Box<T> {
T[] itemArr;
T[] toArray() {
T[] tmpArr = new T[itemArr.length]; // 에러
}
}

12-12 와일드 카드 <?>

  • 하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
와일드 카드의 상환 제한 T와 그 자손들만 가능 와일드 카드의 하한 제한 T와 그 조상들만 가능
       제한 없음  <? extends Object> 와 동일

12-14 Generic methods, 지네릭 메서드

  • 지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
1
static <T> void sort(List<T> list, Comparator<? super T> c);
1
2
3
4
5
6
7
8
- 클래스의 타입 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개

class FruitBox<T> {
//...
static <T> void sort(List<T> list, Comparator<? super T> c) {
// ...
}
}
  • 메서드를 호출 할때마다 타입을 대입해야(대부분 생략 가능)

12-15 지네릭 타입의 형변환

  • 지네릭 타입과 원시 타입 간의 형변환은 바람직 하지 않다. (경고 발생)
1
2
3
Box<Object> objBox = null;
Box box = (Box) objBox;
objBox = (Box<Object>) box;

12-16 지네릭 타입의 제거

  • 컴파일러는 지네릭 타입을 제거 하고, 필요한 곳에 형변환을 넣는다.
  1. 지네릭 타입의 경계(bound)를 제거
  2. 지네릭 타입 제거 후에 타입이 불일치하면, 형변환 추가
  3. 와일드 카드가 포함된 경우, 적절한 타입으로 형변환 추가

12-17 열거형 (Enum)

  • 관련된 상수들을 같이 묶어 놓은 것
    enum 열거형이름 { 상수명1, 상수명2, 상수명3, ... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Card {
static final int CLOVER =0;
static final int HEART =1;
static final int DIAMOND =2;

static final int TWO = 0;
static final int THREE =1;

final int kind;
final int num;
}
// 여기서 if (Card.CLOVER == Card.TWO) 하면 true 되지만 의미는 false 되어야 한다.

class Card {
enum Kind { CLOVER, HEART, DIAMOND, SPADE }
enum Value { TWO, THREE, FOUR }

final Kind kind;
final Value value;
}
// enum 경우 하면 컴파일 에러 발생, 왜 ? 값만 체크가 아닌 타입 또한 체크 한다.
// if(Card.Kind.CLOVER == Card.Value.TWO) // 컴파일 에러가 발생
1
2
3
4
5
6
7
8
class Unit {
int x, y;
Direction dir;

void init() {
dir = Direction.EAST;
}
}
  • 열거형 상수의 비교에 == 와 compareTo() 사용 가능
1
2
3
4
5
6
7
if(dir = DIRECTION.EAST) {
x++;
} else if( dir > Direction.WEST) { // 에러
// ..
} else if( dir.compareTo(Direction.WEST) > 0 ) {
// compareTo() 는 가능
}

12-19 열거형의 조상 - java.lang.Enum

  • 모든 열거형은 Enum의 자손, 아래 메서드를 상속 받는다
1
2
3
String name(); // 열거형 상수의 이름을 문자열로 반환
int ordinal(); // 열거형 상수가 정릐된 순서를 반환 (0부터 시작)
T valueOf(Class<T> enumType, String name); // name과 일치 하는 열거형 상수 반환

values(), valueOf()는 컴파일러가 자동으로 추가

1
2
3
4
5
6
7
8
9
10
11
12
static E[] values();
static E valueOf(String name);

enum Direction { EAST, SOUTH, WEST, NORTH }

Direction[] dArr = Direction.values();
for(Direction d : dArr)
System.out.printf("%s %d", d.name(), d.ordinal() );

Direction d1 = Direction.EAST; // 열거형타입.상수이름
Direction d2 = Direction.valueOf("WEST");
Direction d3 = Enum.valueOf(Direction.class, "EAST");

ch12-21,22 열거형에 멤버 추가하기

  • 불연속적인 열거형 상수, 괄호()안에 적을수 있다 이때 선언 이후 끝에 ; 필요 와 생성자가 필요 함
1
2
3
4
5
6
7
8
9
10
enum Direction { 
EAST(1), SOUTH(5), WEST(-1), NORTH(10);

private final int value;
Direction(int value)
{
this.value = value;
}

}

ch12-23 애너테이션이란?

  • 주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공

ch12-25 @Override

  • Overide 하는 함수에 적어주면 javac 에서 확인 체크 해줌

ch12-26 @Deprecated

  • 앞으로 사용 하지 않을 것을 권장 하는 필드나 메서드에 붙인다

ch12-27 @FunctionalInterface

  • 함수형 인터페이스에 붙이면, 컴파일로가 올바르게 작성 했는지 체크
  • 함수형 인터페이스에는 하나의 추상 메서드만 가져야 한다는 제약이 있음
1
2
3
4
5
@FunctionalInterface
public interface Runnable {
void test();
void check(); // 에러 발생
}

ch12-28 @SupressWarnings

  • 컴파일러의 경고 메시지가 나타나지 않게 억제 한다.
  • 괄호() 안에 억제 하고자 하는 경고의 종류를 문자열로 지정
1
2
3
@SuppressWarnings("unchecked")
ArrayList list = new ArrayList();
list.add(obj);
  • 둘 이상의 경고를 동시에 억제 하려면 다음과 같이 한다.
1
@SuppressWarnings ({"deprecation", "unchecked", "varargs"})

ch12-29 메타 애너테이션

  • 애너테이션 만들때 사용, java.lang.annotation 에 있음
  • @Target: 적용 대상 지정
  • @Retention: 유지 되는 기간 지정, SOURCE, CLASS, RUNTIME
  • @Documented: javadoc에 포함
1
2
3
4
5
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
  • @Inherited: 상속 하고자 할때 사용
1
2
3
4
5
6
7
@Inherited
@interface SuperAnno {}

@SuperAnno
class Parent {}

class child extends Parent {}
  • @Repeatable: 반복해서 붙일수 있음

ch12-34 애너테이션 타입 정의하기

1
2
3
4
@interface 애너테이션이름 {
타입 요소이름();
//..
}
  • 사용 시, 요소마다 값을 넣어 선언
  • default 값이 있는 경우도 생략 가능
  • 요소가 하나 이면 요소 이름 생략 가능
  • 요소의 타입이 배열 일 경우, 괄호 사용 {}
1
2
3
4
5
6
7
8
9
10
@interface TestInfo {
int count() default 1;
}

@TestInfo // @TestInfo (count=1) 과 동일
public class NewClass { ... }

@inteface TestInfo {
String[] testTools();
}

ch12-36 모든 애너테이션의 조상 - java.lang.annotation.Annotation

1
2
3
4
5
6
7
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();

Class<? extends Annotation> annotationType();
}

ch12-37 마커 애너테이션 - Marker Annotation

요소가 하나도 정의 되지 않는 애너테이션 예: @Test, @Deprecated

ch12-38 애너테이션 요소의 규칙

타입으로 기본형, String, enum, 애너테이션, Class만 허용됨
예외 선언 X, 괄호()안에 매개변수 선언 X, 타입 매개변수 X

1
2
3
4
5
6
@interface AnnoTest {
int id = 100;
String major (int i, int j); // 에러
String minor() throws Exception; // 에러
ArrayList<T> list(); // 에러
}

Annotation 선언 및 사용 예

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Retention(RetentionPolicy.RUNTIME)
@interface TestInfo {
int count() default 1;
String testedBy();
String[] testTools() default "JUnit";
TestType testType() default TestType.FIRST;
DateTime testDate();
}

@TestInfo(testedBy="mike", testTools={"JUnit", "JUnit5"},
testData=@DateTime(yymmdd="160101", hhmmss="235959"))
public static main(String args[]) {
Class<Ex12_8> cls = Ex12_8.class;
TestInfo anno = cls.getAnnotation(TestInfo.class);
anno.testedBy();
anno.testDate().yymmdd();
anno.testDate().hhmmss();

for(String str : anno.testTools())
System.out.println("testTools="+str);
}

Section 1. Select 기초 - 원하는 정보 가져오기

강좌 링크
https://www.yalco.kr/@sql/1-1/

실습 링크 (W3School)
https://www.w3schools.com/mysql/trymysql.asp?filename=trysql_select_all

1. SELECT 와 기본 구문

다 가져오기 SELECT * FROM Customers;
원하는 조건만 WHERE
정렬 ORDER BY xx ASC, 내림차순은 DESC
원하는 갯수 LIMIT
별명/alias AS

모두 활용 예제

1
2
3
4
5
6
7
8
9
10
SELECT
CustomerID AS '아이디',
CustomerName AS '고객명',
City AS '도시',
Country AS '국가'
FROM Customers
WHERE
City = 'London' OR Country = 'Mexico'
ORDER BY CustomerName 'ASC'
LIMIT 0, 5;
  1. 주석 달때는 ‘– ‘ 하면 된다
  2. LIMIT은 화면 페이지 구현 하는데 사용

LIMIT {가져올 갯수} 또는 LIMIT {건너뛸 갯수}, {가져올 갯수} 를 사용하여, 원하는 위치에서 원하는 만큼만 데이터를 가져올 수 있습니다.

2. 연산자

연산자 의미
+, -, *, / 더하기, 빼기, 곱하기, 나누기
%, MOD 나머지
IS 양쪽이 모두 TRUE 또는 FALSE
IS NOT 한쪽은 TRUE, 한쪽은 FALSE
AND, && 양쪽이 모두 TRUE일 때만 TRUE
OR, `
= 양쪽 값이 같음
!=, <> 양쪽 값이 다름
>, < (왼쪽, 오른쪽) 값이 더 큼
>=, <= (왼쪽, 오른쪽) 값이 같거나 더 큼
BETWEEN {MIN} AND {MAX} 두 값 사이에 있음
NOT BETWEEN {MIN} AND {MAX} 두 값 사이가 아닌 곳에 있음
IN (…) 괄호 안의 값들 가운데 있음
NOT IN (…) 괄호 안의 값들 가운데 없음
LIKE ‘… % …’ 0~N개 문자를 가진 패턴
LIKE ‘… _ …’ 갯수만큼의 문자를 가진 패턴

3. 숫자와 문자열 함수들

1.숫자 관련
ROUND, CEIL, FLOOR, ABS, GREATEST, LEAST
MAX, MIN, COUNT, SUM, AVG
제곱: POW(A,B), POWER(A,B)
제곱근: SQRT(A)
소숫점 짜르기: TRUNCATE(N,n)

https://dev.mysql.com/doc/refman/8.0/en/numeric-functions.html

2.문자열 관련

UCASE, UPPER, LCASE, LOWER

CONCAT(..), CONCAT_WS(S, ..)

SUBSTR, SUBSTRING, LEFT, RIGHT

LENGTH, CHAR_LENGTH, CHARACTER_LENGTH

TRIM, LTRIM, RTRIM

LPAD(S,N,P), RPAD(S,N,P) padding

REPLACE(S,A,B)

INSTR(S,s) // 위치 반환, 없을시 0

1
2
3
SELECT * FROM Customers
WHERE INSTR(CustomerName, ' ') BETWEEN 1 AND 6;
-- < 6으로 하면?

https://dev.mysql.com/doc/refman/8.0/en/string-functions.html

3.자료형 변환

|함수 |설명
|CAST(A, T) |A를 T 자료형으로 변환

1
2
3
4
5
6
SELECT
'01' = '1',
-- 문자열 비교로 0 False

CONVERT('01', DECIMAL) = CONVERT('1', DECIMAL);
-- 숫자로 변환후 비교로 1 True

4.A 시간/날짜 관련

현재 : CURDATE, CURTIME, NOW
문자열 인자로 : DATE, TIME

1
2
3
4
5
6
7
8
9
10
11
SELECT
'2021-6-1 1:2:3' = '2021-06-01 01:02:03',
DATE('2021-6-1 1:2:3') = DATE('2021-06-01 01:02:03'),
TIME('2021-6-1 1:2:3') = TIME('2021-06-01 01:02:03'),
DATE('2021-6-1 1:2:3') = TIME('2021-06-01 01:02:03'),
DATE('2021-6-1') = DATE('2021-06-01 01:02:03'),
TIME('2021-6-1 1:2:3') = TIME('01:02:03');

SELECT * FROM Orders
WHERE
OrderDate BETWEEN DATE('1997-1-1') AND DATE('1997-1-31');

(날짜) 필요한 부분만 추출: YEAR, MONTHNAME, MONTH, WEEKDAY, DAYNAME, DAYOFMONTH, DAY
주어진 DATETIME값의 요일값 반환(월요일: 0): WEEKDAY

(시간) 필요한 부분만 추출: HOUR, MINUTE, SECOND

(시간/날짜) 더하기, 빼기 : ADDDATE, DATE_ADD, SUBDATE, DATE_SUB

1
2
3
4
5
6
7
8
SELECT
OrderDate,
ADDDATE(OrderDate, INTERVAL 1 YEAR),
ADDDATE(OrderDate, INTERVAL -2 MONTH),
ADDDATE(OrderDate, INTERVAL 3 WEEK),
ADDDATE(OrderDate, INTERVAL -4 DAY),
ADDDATE(OrderDate, INTERVAL -5 MINUTE)
FROM Orders;

차이 구하기 : TIMEDIFF, DATEDIFF

해당 달의 마지막 날 가져오기 : LAST_DAY

1
2
3
4
5
6
SELECT
OrderDate,
LAST_DAY(OrderDate),
DAY(LAST_DAY(OrderDate)),
DATEDIFF(LAST_DAY(OrderDate), OrderDate)
FROM Orders;

시간/날짜 -> String으로 포멧 함수: DATE_FORMAT

1
2
3
4
5
6
7
8
9
10
11
12
SELECT
DATE_FORMAT(NOW(), '%M %D, %Y %T'),
DATE_FORMAT(NOW(), '%y-%m-%d %h:%i:%s %p'),
DATE_FORMAT(NOW(), '%Y년 %m월 %d일 %p %h시 %i분 %s초');

SELECT REPLACE(
REPLACE(
DATE_FORMAT(NOW(), '%Y년 %m월 %d일 %p %h시 %i분 %초'),
'AM', '오전'
),
'PM', '오후'
)

String -> 시간/날짜 포멧 함수: STR_TO_DATE

1
2
3
4
5
6
7
8
9
10
11
SELECT
OrderDate,
DATEDIFF(
STR_TO_DATE('1997-01-01 13:24:35', '%Y-%m-%d %T'),
OrderDate
),
TIMEDIFF(
STR_TO_DATE('1997-01-01 13:24:35', '%Y-%m-%d %T'),
STR_TO_DATE(CONCAT(OrderDate, ' ', '00:00:00'), '%Y-%m-%d %T')
)
FROM Orders;

4.B 기타 함수

IF(조건, T, F) 와 CASE 문

1
2
3
4
5
6
7
8
9
10
11
SELECT IF (1 > 2, '1는 2보다 크다.', '1은 2보다 작다.');

SELECT
Price,
IF (Price > 30, 'Expensive', 'Cheap'),
CASE
WHEN Price < 20 THEN '저가'
WHEN Price BETWEEN 20 AND 30 THEN '일반'
ELSE '고가'
END
FROM Products;

IFNULL(A,B) : A가 NULL 일 시 B 출력

1
2
3
SELECT
IFNULL('A', 'B'),
IFNULL(NULL, 'B');

5. 조건에 따라 그룹으로 묶기

GROUP BY : 특정 컬럼 별루 묶음

통상 MAX, MIN, COUNT, SUM, AVG 와 같이 쓰임
WITH ROLLUP 을 넣어주면 결과 마지막줄에 합계 추가

1
2
3
4
5
6
7
8
9
SELECT
CategoryID,
MAX(Price) AS MaxPrice,
MIN(Price) AS MinPrice,
TRUNCATE((MAX(Price) + MIN(Price)) / 2, 2) AS MedianPrice,
TRUNCATE(AVG(Price), 2) AS AveragePrice
FROM Products
GROUP BY CategoryID;
WITH ROLLUP

HAVING : 그룹된 결과를 필터링 하고 싶을때 사용
WHERE-> GROUP BY -> HAVING : 조합으로 많이 쓰임

1
2
3
4
5
6
7
8
9
10
11
12
SELECT
CategoryID,
MAX(Price) AS MaxPrice,
MIN(Price) AS MinPrice,
TRUNCATE((MAX(Price) + MIN(Price)) / 2, 2) AS MedianPrice,
TRUNCATE(AVG(Price), 2) AS AveragePrice
FROM Products
WHERE CategoryID > 2
GROUP BY CategoryID
HAVING
AveragePrice BETWEEN 20 AND 30
AND MedianPrice < 40;

DISTINCT : GROUP BY 와 달리 집계 함수 사용 X, 정렬 하지 않아 더 빠름, SELECT 부분에 들어감

1
2
3
4
5
6
7
8
SELECT DISTINCT CategoryID
from Products;

SELECT
Country,
COUNT(DISTINCT CITY)
FROM Customers
GROUP BY Country;

인프런 강좌 수강 ~

인강?, 책?, 스터디? 어떤 것으로 배움을 시작 할까 하는데 인프런 강좌 쿠폰을 받아서 여기 수강 신청을 했다.

안녕하세요, 코딩유튜버를 하는 얄코입니다.
인프런에서 18,700원에 제공하는 제 MySQL 강의를
천원에 수강하실 수 있는 쿠폰을 천 분께 뿌립니다.
쿠폰은 오는 5월 말일까지 유효하고 재고소진시 바로 마감됩니다.
https://www.inflearn.com/course/얄코-마이에스큐엘?inst=3e046db4
쿠폰번호: 5399-579e5041aadf
개인적으로 큰 일을 하나 무사히 끝내게 되어 기념으로 나눔합니다 😅
필요하신 분들 챙겨가세요! 감사합니다~!!

열심히 들어보자 :)