✏️ Docker란? (참고:https://greenring.tistory.com/46)

✏️ Docker을 활용하여 MySQL에 접속하는 이유 :

새로운 환경마다 MySQL을 설치 안해줘도됨. MySQL 이미지를 내려받아 컨테이너를 구성하면 효율적.

✏️ 도커 설치

https://www.docker.com/products/docker-desktop/

 

Download Docker Desktop | Docker

Docker Desktop is available to download for free on Mac, Windows, or Linux operating systems. Get started with Docker today!

www.docker.com

명령어 통해 도커 설치 확인 : cmd > docker -v

아래와 같이 확인 가능하다면 설치 정상적으로 완료.

✏️MySQL 도커 이미지 다운로드

https://hub.docker.com/ > MySQL 검색 > MySQL 클릭 >

아래 그림 부분에서 우측 클릭하여 복사 > cmd > docker pull mysql:latest (*최신버전 다운위해 latest적음)

🙋 위 부분에서 에러발생 시 할 것.

1. 도커가 실행중인지 확인

2. Windows PowerShell(관리자실행) > wsl --update 

 

✏️ MySQL 도커 컨테이너 생성 및 실행

cmd > docker run --name <컨테이너이름> -e MYSQL_ROOT_PASSWORD=<패스워드> -d -p 3306:3306 mysql:latest

<컨테이너이름> : 컨테이너 이름 지정하기

<패스워드> : 패스워드 지정하기

 

✏️ MySQL 도커 컨테이너 접속

docker exec -it <도커 컨테이너 이름> bash

 

✏️MySQL 접속

mysql -u root -p

* 패스워드가 입력이 안되는 현상? : cmd창에 보이지 않을뿐 입력은 되는 중. 글자 안떠도 패스워드 입력하고 엔터 누르면 됨

✏️ 가상화 기술 등장 이전

하나의 서버에 하나의 애플리케이션만 구동 가능. (하나의 서버에 하나의 OS, 프로그램 운영)

안정적이라는 장점이 있었지만, 남는 서버 공간이 방치됐음(비효율적)

 

✏️ 하이퍼바이저 기반의 가상화(OS 가상화)

남는 서버 방치되는 비효율적 운영 극복위해 하이퍼바이저 가상화 기술 등장.

논리적으로 분할된 공간에서 독립된 가상환경(VM)을 만들고, 호스트시스템에서 VM에 깔린 다수의 게스트 OS를 구동화할 수 있음.

서버의 자원을 효율적으로 사용할 수 있지만, VM을 띄우고 자원을 할당해 게스트OS를 부팅해서 구동해야하므로 시간 및 리소스 소모가 큼

 

✏️ 컨테이너 기반의 가상화(도커 : 가장 유명한 오픈소스)

컨테이너는 VM과 유사하지만 고유의 OS 필요없음

모든 컨테이너는 호스트의 OS 공유함(CPU, RAM등 막대한 양의 시스템 리소스 확보 가능)

애플리케이션 구동을 위한 패키지(이미지)만 있으면 구동 가능

*Docker compose(도커 컴포즈) : 다중 컨테이너를 관리할 수 있음. yaml파일에 명령어를 적어서 컨테이너를 정의하고 관리.

도커의 설정값들을 yaml파일에 저장해서 간단한 명령어로 실행되게 해줌.

 

🙋 단일 OS 에서 여러 애플리케이션 실행컨테이너 기반의 가상화 기술이 더 적합하고,

서로 다른 OS 환경에서 실행해야하는 경우에는 VM이 적합하다.

1. 의존성 설정 : buil.gradle > dependencies에 embedded tomcat 의존성 추가

추가하는 방법 : 메이븐저장소(https://mvnrepository.com/) - embedded tomcat 검색 - Tomcat Embed Core 클릭 - 최신 버전 클릭 - 탭 중에서 Gradle클릭 - implementation부분부터 끝까지 복사 - buil.gradle파일의 dependencies{} 내부에 추가

 

2. WebApplicationServer.java 코드 추가

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

	// 톰캣의 루트 디렉토리가 webapps이며 톰캣을 8080포트로 실행할것이다.
        String webappDirLocation = "webapps/";
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(8080);

	// 경로로 접근했을때 해당 디렉토리(webapps) 안에서 톰캣이 파일을 찾는다
        tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());
        log.info("configuring app with basedir: {}", new File("./" + webappDirLocation).getAbsolutePath());

        tomcat.start();
        tomcat.getServer().await();
    }

 

✏️참고 1

wepapps 안에는 아무것도 없는데 어떻게 찾아서 실행하나? (현재 webapps 비워져있는상태라면) :

ctrl+alt+shift+s(Project Structure 창 오픈) > Modules > 프로젝트 - main 클릭 > Output path에서 out 부분을 wepapps\WEB-INF로 변경 (produc~부분은 지움)

*main밑에 test도 클릭해서 Test output path 해당 부분 똑같이 변경

 

✏️참고 2

위 설정을 마치면, 톰캣이 해당 클래스를 실행할 수 있다. 

* 구글에 application developer's guide - deployment - apache tomcat 8.5.42 검색(build.gradle 추가한거보면 8.~ 버전 사용했으므로) > Application Developer's Guide 페이지의 Standard Directory Layout 부분에서 (루트디렉토리 생략)/WEB-INF/classes/ 부분 확인하면 'This directory contains any Java class files' 라고 써있음을 확인 가능

 

✏️참고 3

위 설정을 마치면, 

프로젝트-src-main-java-org.example-WebApplicationServer에서 org.example-WebApplicationServer 이 부분을 webapps/WEB-INF/classes밑에 들어가게 해줌. 따라서 톰캣이 실행될때 classes밑에서 자바 클래스 찾아 실행하게 되는것.

'Java' 카테고리의 다른 글

[Java] Reflection API  (0) 2024.02.18
[Java] Iterator, Enumeration  (0) 2023.10.17
[Java] Optional이란? Optional 개념 및 사용  (0) 2023.10.05
[Java] import static 사용하는 이유  (0) 2023.08.09
[Java] Static - 정적 변수와 메서드  (0) 2023.06.13

💻 웹서버(Web Server) 

정적 컨텐츠(html, css, js)를 제공하는 서버. (ex. Apache, Nginx)

HTTP 프로토콜을 기반으로 클라이언트가 웹 브라우저에 요청을 하면 그 요청을 받아 정적 컨텐츠로 제공함.

동적 컨텐츠를 요청받으면 WAS에게 요청 넘겨줌, WAS에서 처리한 결과 클라이언트에 전달

💻 WAS(Web Application Server)

동적 컨텐츠를 제공하는 서버. (ex. Tomcat(=Apache Tomcat, JBoss, WebSphere)

DB조회 또는 비즈니스 로직을 처리하는 동적 컨텐츠 구동이 가능한 서버.

WAS는 JSP, Servlet 구동환경을 제공해주기 때문에 서블릿 컨테이너, 웹 컨테이너로 불린다.

WAS는 Web Server와 Web Container 역할 모두 가능.

🙋 그렇다면 WAS가 웹서버 기능까지 수행하는데, 분리해서 연동하는 이유는?

  • 처리 속도 : WAS는 독립적인 웹서버보다 처리속도 느림 > 서비스 품질저하 될 수 있음
  • 서버 부하 방지 : 분리해서 서버의 부하를 방지함. 정적 컨텐츠까지 WAS가 한다면 부하가 커지고, 수행속도 느려질 것.
  • 보안 강화 :  SSL(Secure Sockets Layer - 보안 소켓 계층 : 웹 사이트와 브라우저 사이 혹은 두 서버 사이에 전송되는 데이터를 암호화하여 인터넷 연결 보호하기위한 표준 기술)에 대한 암호화, 복호화 처리에 웹서버 사용 가능
  • 여러 WAS 연결 가능 : 로드밸런싱(여러 서버들로 대규모의 네트워크 트래픽을 분산 처리하는 기술/로드=부하,밸런싱=분산, 즉 네트워크나 서버에 가해지는 부하를 분산해주는 기술)을 위해 웹서버 사용할 수 있음. 여러 개의 서버를 사용하는 대용량 웹어플리케이션의 경우 웹 서버와 WAS를 분리하여 무중단 운영을 위한 장애 극복(작동 중지된 WAS가 있다면 대신해 다른 WAS를 사용하여 장애를 극복함)에 쉽게 대응할 수 있음

 

 

✏️ 문제 설명
n개의 음이 아닌 정수들이 있습니다. 이 정수들을 순서를 바꾸지 않고 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다.

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
사용할 수 있는 숫자가 담긴 배열 numbers, 타겟 넘버 target이 매개변수로 주어질 때 숫자를 적절히 더하고 빼서 타겟 넘버를 만드는 방법의 수를 return 하도록 solution 함수를 작성해주세요.

✏️ 제한사항
주어지는 숫자의 개수는 2개 이상 20개 이하입니다.
각 숫자는 1 이상 50 이하인 자연수입니다.
타겟 넘버는 1 이상 1000 이하인 자연수입니다.
입출력 예
numbers target return
[1, 1, 1, 1, 1] 3 5
[4, 1, 2, 1] 4 2
✏️ 입출력 예 설명
입출력 예 #1

문제 예시와 같습니다.

입출력 예 #2

+4+1-2+1 = 4
+4-1+2-1 = 4
총 2가지 방법이 있으므로, 2를 return 합니다.

 

✏️ 내가 작성한 코드 - BFS

from collections import deque

def solution(numbers, target):

    # bfs
    answer = 0
    queue = deque()
    queue.append([numbers[0],0]) # numbers 첫번째 원소 +,-해서 큐에 넣어줌
    queue.append([-(numbers[0]),0])

    while queue:

        pop_number = queue.popleft()

        idx = pop_number[1]  
        number = pop_number[0] 
        idx += 1

        if idx < len(numbers):
            queue.append([number + numbers[idx], idx])
            queue.append([number - numbers[idx], idx])
        else: # 배열의 끝까지 덧셈해줬을때 카운팅해줌
            if number == target:
                answer += 1

    return answer
 

2606번: 바이러스

첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어

www.acmicpc.net

 

✏️ 내가 작성한 코드 (BFS 사용)

# 조건 : 1번 컴퓨터가 바이러스에 걸림

def bfs(start):
    visit = 0 # 바이러스 걸린 컴퓨터를 셀 변수
    need_visit= [] # 큐 대신 리스트 사용
    need_visit.append(start) # 시작 컴퓨터 처음에 넣어줌

    while need_visit: # 리스트에 있는 값 모두 없어질때까지 while 돌아감
        node = need_visit.pop(0) # 큐 특성 이용 -> 맨 앞값 가져옴 *pop() : 맨뒷값 가져옴
        if not visited[node]:
            visited[node]=True
            if node != 1: # 1번 제외하고 횟수 세야함
                visit +=1
            for e in abj[node]: # 해당 컴퓨터에 연결된 컴퓨터들 돌아가면서 가져오고 리스트에 넣어줌
                if not visited[e]:
                    need_visit.append(e)

    return visit


start = 1 # 시작 컴퓨터 번호
computer = int(input()) # 컴퓨터의 수
connec = int(input()) # 연결되어 있는 컴퓨터 쌍의 수
abj = [[] for _ in range(computer+1)] # 연결된 컴퓨터 쌍 담을 리스트
visited = [False]*(computer+1)

for _ in range(connec):
    a,b = map(int,input().split()) # 한 쌍씩 연결되어 있는 컴퓨터 번호 주어짐
    abj[a].append(b) # 양방향이므로 각각 append해줌줌    abj[b].append(a)
    abj[b].append(a)

print(bfs(start))

 

✏️ 참고

'from collections import deque' 사용하여 큐를 이용하는 대신

리스트를 이용. pop(0) 써서 맨 앞값 가져옴

✏️ 문제 설명
전화번호부에 적힌 전화번호 중, 한 번호가 다른 번호의 접두어인 경우가 있는지 확인하려 합니다.
전화번호가 다음과 같을 경우, 구조대 전화번호는 영석이의 전화번호의 접두사입니다.

구조대 : 119
박준영 : 97 674 223
지영석 : 11 9552 4421
전화번호부에 적힌 전화번호를 담은 배열 phone_book 이 solution 함수의 매개변수로 주어질 때, 어떤 번호가 다른 번호의 접두어인 경우가 있으면 false를 그렇지 않으면 true를 return 하도록 solution 함수를 작성해주세요.

✏️ 제한 사항
phone_book의 길이는 1 이상 1,000,000 이하입니다.
각 전화번호의 길이는 1 이상 20 이하입니다.
같은 전화번호가 중복해서 들어있지 않습니다.


✏️ 입출력 예제

phone_book  return
["119", "97674223", "1195524421"]  false
["123","456","789"] true
["12","123","1235","567","88"]  false

 

✏️ 입출력 예 설명
입출력 예 #1
앞에서 설명한 예와 같습니다.

입출력 예 #2
한 번호가 다른 번호의 접두사인 경우가 없으므로, 답은 true입니다.

입출력 예 #3
첫 번째 전화번호, “12”가 두 번째 전화번호 “123”의 접두사입니다. 따라서 답은 false입니다.

✏️ 내가 작성한 코드 - 1 (효율성 테스트 3,4 시간초과로 통과 X >> 이유 : for문 2개)

def solution(phone_book):
    phone_book.sort(key=lambda x:len(x))
    answer = True

    for i in range(len(phone_book)):

        phone_len = len(phone_book[i])

        if phone_book[i] in [i[:phone_len] for i in phone_book[i+1:]]:
            answer = False
            break

    return answer

✏️ 내가 작성한 코드 - 2 (통과 O)

def solution(phone_book):
    phone_book.sort() # 배열 정렬 : 번호는 문자열로 들어가있으므로, 문자열 기준으로 정렬됨
    answer = True

    for i,phone in enumerate(phone_book):
        if i+1 == len(phone_book): # 배열의 끝까지 순회했음에도 불구하고 한번호가 다른번호의 접두어인 경우가 없을때는 break해줘야함
            break

        # int정렬이 아닌 str정렬이므로 바로 다음 번호에서 앞 번호가 포함되어있는지 확인하면됨
        if phone_book[i+1].startswith(phone): # startswith() : 괄호안의 문자열이 포함되어 있는지 확인할 수 있음
            answer = False
            break

    return answer

 

✏️ 참고

 

arr1 = ["12","123","1235","567","88"]
arr2 = [12, 123, 1235, 567, 88]
arr1.sort() # ['12', '123', '1235', '567', '88']
arr2.sort() # [12, 88, 123, 567, 1235]

phone_book의 원소들은 '문자열'이다.

위에 보다시피 정수일때 sort()는 숫자 크기에 따라 정렬되지만,

문자열일때 sort()는 아스키코드 숫자로 변환돼서 맨앞자리부터 비교되면서 정렬된다.

따라서 다른 번호를 접두어로 가지고 있는 번호는 다른번호의 바로 다음 위치에 존재할 수 있게된다.

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

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

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


✏️ 입출력 예

participant  completion return
["leo", "kiki", "eden"] ["eden", "kiki"]   "leo"
["marina", "josipa", "nikola", "vinko", "filipa"]  ["josipa", "filipa", "marina", "nikola"]  "vinko"
["mislav", "stanko", "mislav", "ana"]  ["stanko", "ana", "mislav"] "mislav"

 


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

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

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

✏️ 내가 작성한 코드

 

def solution(participant,completion):

    participant.sort() # 차례대로 비교하기위해 두 배열 다 sort해줌
    completion.sort()
    completion.append("") # completion 배열은 항상 크기 1 작음. 아래 for문에서 list 길이 에러 대비해 빈값 하나 추가해줌

    for i in range(len(participant)):
        if participant[i] != completion[i]:
            break

    return participant[i]

 

✏️ 참고

remove() 방법을 쓰면 테스트코드는 통과하지만 효율성 통과 못함.

remove()는 O(N)시간이 걸리는데 for문을 돌면서 O(n*n)시간이 걸려 통과 못한다고함.

+ Recent posts