SQL injection(SQL 인젝션)은 공격자가 애플리케이션의 보안 취약점을 이용해 악의적인 SQL코드를 데이터베이스에 삽입함으로써, 데이터베이스를 조작하거나 민감한 정보를 탈취하는 공격 기법이다. 이는 주로 애플리케이션에서 사용자 입력을 제대로 검증하지 않을 때 발생한다. 

 

 

작동원리

 

SQL 인젝션은 사용자가 입력한 값이 SQL 쿼리의 일부로 실행될 때, 이 입력 값에 포함된 악의적인 SQL 코드가 실행되어 공격이 발생합니다. 예를 들어, 아래와 같은 SQL쿼리가 있다고 가정하자.

 

 

SELECT * FROM users WHERE username = 'user' AND password = 'password';

 

만약 사용자 입력이 아래와 같이 쿼리에 삽입된다면

username: ' OR '1'='1
password: ''

 

쿼리는 다음과 같이 변환된다.

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '';

 

'1'='1'은 항상 참이므로, 데이터베이스는 모든 사용자의 정보를 반환하게 된다.

 

SQL Injection의 유형

 

1. Classic SQL Injection

기본적인 SQL 코드 조작방식

예: ' OR '1'='1' --

 

2. Blind SQL Injection

응답 메시지나 페이지가 직접적인 정보 대신 참/거짓 여부로 결과를 반환시킨다.

예: ' AND 1=1 -- , ' AND 1=2--

 

3. Union-Based SQL Injection

UNION 키워드를 사용하여 공격자가 원하는 데이터를 반환한다.

' UNION SELECT username, password FROM users --

 

4. Boolean-Based SQL Injection

조건문을 삽입하여 참/거짓을 통해 데이터베이스를 추측한다.

 

5. Time-Based SQL Injection

데이터베이스 쿼리의 실행 시간을 조작해 정보를 얻는다.

' OR IF(1=1, SLEEP(5), 0) --

 

피해

 

데이터 유출: 민감한 정보(사용자 이름, 암호, 금융 정보 등) 탈취

데이터베이스 손상: 데이터 삭제, 변경 또는 손상

권한 상승: 공격자가 데이터베이스 관리자 권한을 획득

서비스 장애: 데이터베이스를 과도하게 사용하거나 손상시켜 서비스 중단

 

방어 방법

 

1. 사용자 입력 검증 및 정규화

모든 입력값을 철저히 검증한다.

특정 문자들 '   ;    --  등을 제거하거나 제한하는 것.

 

2. Prepared Statement 및 Parameterzied Query 사용

SQL 쿼리를 실행할 때, 사용자 입력값과 쿼리를 분리한다.

 

예:

String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, password);

 

 

3. Stored Procedure 사용

SQL 쿼리를 미리 정의된 프로시저로 처리한다.

 

4. ORM (Object-Relational Mapping) 사용

Hibernate와 같은 ORM 툴은 기본적으로 SQL Injection 방지 기능 제공한다.

 

5. 최소 권한 원칙 적용

애플리케이션 계정에 최소한의 권한만 부여한다.

 

6. 에러 메시지 제한

 

데이터베이스 구조를 노출하지 않도록 에러 메시지를 제한한다.

 

7. WAF(Web Application Firewall) 

 

SQL Injection 공격을 탐지 및 차단하는 방화벽 사용한다.

 

결론 

 

SQL Injection은 웹 애플리케이션의 보안 취약점을 이용해 데이터베이스를 조작하거나 정보를 탈취하는 강력한 공격 방법이다. 이를 방지하기 위해서는 철저한 사용자 입력 검증과 보안 코딩, 그리고 강화 도구 사용이 필수적입니다.

Thread란?

 

운영체제에서 스레드는 프로세스 내부에서 실행되는 작은 작업 단위이다. 스레드는 프로세스의 실행 흐름을 구성하는 단위로, 하나의 프로세스 내부에 여러개의 스레드가 포함될 수 있다.

 

스레드의 특징

프로세스들이 서로의 데이터에 접근하는것이 직접적으로 불가능한데 반면, 스레드는 프로세스 내부에 존재하기에 프로세스의 데이터 영역에 접근이 가능하다. 그리고 스레드들끼리 서로의 데이터에 접근 가능하다. IPC 필요없이 프로세스의 데이터를 가져올 수 있다.

 

스레드도 일종의 작업 단위라서, 프로세스처럼 작업이 처리된다. 이 말은 즉, 스레드도 프로세스처럼 작업을 병렬로 처리해서 속도를 높일 수 있다는 것이다.

 

스레드는 일종의 함수로 구현된다. 스레드도 함수라서 데이터를 다루고, 데이터를 관리하기 위해 stack 메모리 영역을 가진다. 이 stack 공간은 프로세스가 가지는  stack 메모리 영역과는 별개이며, 스레드의 메모리 영역을 thread stack 이라고 부른다. 프로세스는 메모리 영역을 크게 4가지(code, data, stack, heap)으로 나눌 수 있지만, 스레드는 thread stack 메모리 공간만 갖게된다. 스레드 안에 포함된 데이터(지역 변수)는 thread stack에 저장된다. (단, 프로세스의 stack 영역에는 스레드의 지역변수는 포함하지 않는다.)

 

하나의 프로세스는 내부에 여러개의 스레드를 가질 수 있다.

 

멀티 스레드와 멀티 프로세스 

 

멀티 스레드는 하나의 프로세스 내부에서 여러 개의 스레드가 동시에 실행되는 것이다. 스레드끼리는 서로의 메모리 공간을 공유하고 접근할 수 있다. IPC 통신이 아닌 메모리 기반 통신을 사용하기에 통신속도가 빠르다. 각 스레드들은 여러 자원을 공유하기에, 하나의 스레드에 문제가 생기면 나머지 스레드들도 영향을 받을 수 있다. 프로세스 내에서 스레드의 작업을 여러개로 분할 병렬로 처리할 수 있다.

 

멀티 프로세스는 여러개의 독립적인 프로세스가 동시에 실행되는 것이다. 각 프로세스는 독립된 메모리 공간을 가지며, 서로에게 접근하려면 IPC 기법을 사용해야한다. 각 프로세스는 각각 고유한 자원을 관리하고 있어 서로에게 영향을 미치지 않는다. 하나의 프로세스 작업을 여러개로 분할 병렬로 처리할 수 있다. 이때, 프로세스는 스레드 단위로 작업을 분할한다.

 

스레드의 장점

 

응답성 향상

 

스레드간의 작업분할과 병렬 처리로 인해 사용자가 응용 프로그램을 원할하게 사용하는데 빠른 응답성를 제공할 수 있다.

 

자원공유 효율성 향상

 

스레드는 하나의 프로세스 내에서 실행되기 때문에, 프로세스의 자원을 공유하여 접근할 수 있다. 그리고 스레드는 프로세스 내부에 있기 때문에 별도의 메모리 공간을 할당할 필요없이, 프로세스 내부에서 데이터를 관리하면 된다. 스레드는 프로세스 내부에서 thread stack이라는 공간에 데이터를 관리한다. 따라서 스레드를 사용하면 자원 공유의 효율이 높다.

 

동시성

 

여러 개의 스레드가 동시에 실행될 수 있어서, 작업을 병렬로 처리할 수 있다.

 

간결성

 

작업을 분리할 수 있어서 코드가 간결해질 수 있다.

 

단점

 

스레드 간의 상호간섭

 

멀티 스레드가 실행 중인 상황에, 스레드 간의 상호간섭 문제가 발생할 수 있다. 프로세스는 한 개가 다운되면, 그 프로세스만 작업이 멈추고 다른 프로세스에는 영향이 가지 않는다. 하지만 스레드는 다른 스레드가 작업을 방해하거나, 스레드간의 우선순위 설정에 문제가 있을 경우, 서로에게 영향을 미치기 때문에 예상치 못한 이슈가 발생할 수 있다.

 

성능 저하

 

스레드를 많이 생성하면 성능 저하가 발생할 수 있다. 스레드를 많이 생성하면, 스레드 스케줄러에서 각각의 스레드들이 병렬로 실행되기 위해 컨텍스트 스위칭이 빈번하게 발생해야 하기 때문에 성능 저하가 발생할 수 있다.

 

동기화 이슈

 

여러 스레드가 공유 자원에 동시에 접근할 때, 동기화 문제가 발생할 수 있다. 경쟁상태 문제는 스레드 간의 실행순서나 타이밍에 따라 예측할 수 없는 결과가 발생할 수 있다.

 

자원소비 

 

스레드는 개별적인 실행 흐름을 가지기 때문에, 스레드마다 stack 및 레지스터 등의 메모리 자원을 소비한다. 따라서 스레드의 수가 증가하면 메모리 사용량도 증가하게 되어 시스템 자원이 한계에 도달할 수 있다.

 

public class Main {
    public static void main(String[] args) {

        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();

        thread1.start();
        thread2.start();
    }

}

 

 

public class Thread1 extends Thread {

    public void run() {
        while(true) {
            System.out.println("thread1");
        }
    }
}

 

public class Thread2 extends Thread {

    public void run() {
        while (true) {


            System.out.println("thread2");
        }
    }
}

 

 

각자 thread1, thread2를 스레드에서 무한히 출력하게 하는 간단한 예제이다. 

실행해보면 동시에 실행하는 것 같지만 사실 거의 동시처럼 실행하게 보일 정도로 빠르게 번갈아가며 실행되고 있다는 것을 알 수 있다.

 

 

이런식으로 extends Thread를 사용하거나 implements Runnable을 사용하고 

public void run()  메서드 안에 스레드에서 실행할 코드를 작성하고 실행하고자 하는 곳에서 해당 객체를 생성해 

start()를 호출하면 된다.  참고로 run()  메서드는 매개변수를 인자로 받을 수 없다.

'Java' 카테고리의 다른 글

[JAVA] Java란 무엇인가  (3) 2025.01.02

레이어드 아키텍처란?

 

소프트웨어를 여러 개의 계층으로 분리해서 설계하는 방법

각각 계층이 서로 독립적으로 구성되어 있어서 한 계층의 변경이 다른 계층에 영향을 주지 않게 설계할 수 있다.

외부의 요구사항이나 세부적인 구현이 변화하더라도 도메인의 로직을 변경하지 않도록 보호하기 위해서 계층화를 하게 된다.

 

 

레이어드 아키텍쳐의 구성

 

 

레이어드 아키텍처의 구성은 딱 하나로 정해져 있지 않고, 애플리케이션의 크기, 복잡도, 요구 사항 등에 따라 달라질 수 있다.  어떤 계층으로 정확히 나눴느냐보다도, 계층을 분리해 각 계층 사이의 의존성을 줄여서 외부 변화로부터 비즈니스 로직의 변화를 막고, 애플리케이션의 유지보수와 확장성을 높이려는 목적으로 만들어진 설계의 한 방법이라는 것을 알아야한다.

 

프레젠테이션 계층, 비즈니스 로직 계층, 데이터 저장소 계층의 세 가지 계층으로 구성된 아키텍쳐도 일반적이고 

레이어드 아키텍처를 Presentation Layer, Business Layer, Persistence Layer, Database Layer로 구성하는 경우도 있다.

계층의 개수와 무슨 계층으로 나눈다는 것에 집중하는 것보다는 각자 처리하는 역할을 나누어 코드의 유지보수를 쉽게 한다는 것을 중점으로 생각해야할 것 같다.

 

여기선 Presentation Layer, Application Layer, Domain Layer, Infrastructure Layer 로 분류할 수 있는 네가지 계층에 대해 정리할 것이다.

 

 

Presentation Layer 

사용자와 시스템 간의 상호작용을 처리한다.

사용자 인터페이스를 담당하며, 사용자의 입력값을 검증하고 비즈니스 로직에 따라 결과를 표시한다.

Presentation Layer에서 비즈니스 로직을 처리하지 않아야하며, 단순히 UI를 표현하는 역할만을 수행해야한다

 

Application Layer

 

Presentation Layer와 Domain Layer 사이에서 비즈니스 로직을 처리한다.

Presentation Layer로부터 전달받은 요청에 대해 Domain Layer와 데이터를 주고받으며, 요청에 대한 처리를 수행한다.

Application Layer에서는 데이터베이스와 직접적으로 상호작용하지 않아야하고, Domain Layer의 엔티티와 데이터를 처리하는 일만을 수행해야 한다.

프레젠테이션 계층, 비즈니스 로직 계층, 데이터 저장소 계층의 세가지 계층으로 나누는 분류에서는 비즈니스 로직 계층과 비슷한 역할을 한다고 볼 수 있다.

 

 

 

Domain Layer

 

비즈니스 로직을 처리하는 핵심 계층으로, 시스템의 핵심 로직이 담겨있다.

주요 역할은 데이터의 유효성 검증, 엔티티간의 관계 처리, 비즈니스 로직 수행 등이 있다.

Domain Layer에서는 Infrastructure Layer 계층을 직접적으로 참조하면 안되며, 해당 계층은 순수한 비즈니스 로직만 담당해야한다.

 

Infrastructure Layer 

 

시스템의 하부 기술적인 부분을 담당하며, 데이터베이스, 네트워크, 파일 시스템 등과 관련된 로직을 처리한다.

주요 역할은 시스템의 기술적인 문제 해결과 데이터의 영속성을 보장하는 것이다.

Infrastructure Layer에서는 도메인 계층과인 상호작용을 최소화해야한다.

 

 

중요한 부분

 

각 계층의 각자의 역할만 수행하도록 분리되어야 한다는 것!

계층 간의 의존성이 최소화되어야 하므로, 각 계층은 단방향으로 상위 계층의 기능만 사용할 수 있도록 구현해야한다!

 

 

 

예제에서는 controller, service, dao, entity로 나눠서 각자 http 요청 분기, 데이터처리, query, 정보저장의 역할로 나누어 해보았다

 

Java란?

 

1995년에 개발된 객체 지향 프로그래밍 언어이다.

또한 플랫폼 독립적이라는 특성도 가지고 있다.

 

객체지향은 뭐고 플랫폼 독립적이란건 뭘까...?

 

이것에 대해 알려면 일단 프로그래밍 언어의 동작 방식을 알아야한다.

 

프로그래밍언어는 인터프리터 언어, 컴파일 언어라는 두 개의 동작방식으로 구분할 수 있다.

인터프리터 언어는 코드를 인터프리터를 통해서 실행한다.

코드를 실행하려면 인터프리터가 os에 설치되어 있어야 한다.

대표적으로 python 등이 있다. 

 

컴파일 언어는 코드를 컴파일(실행파일로 변경)해서 실행한다.

대표적으로 C, C++ 등이 있다.

 

 

그렇다면 Java는?

 

Java는 컴파일 언어와 인터프리터 언어의 특징을 모두 가지고 있다.

아래 그림은 java 파일이 실행되는 과정이다.

 

 

 

 

 

소스 코드를 기계어로 직접 컴파일하여 링크하는 C/C++의 컴파일러와 달리 자바 컴파일러는 바이트코드인 클래스 파일(.class)을 생성하고, 이 파일의 바이트코드를 읽은 뒤 기계어로 바꾸어 실행하는 것은 자바 가상 머신이다.

 

 

왜 2가지 방식을 같이쓸까?

컴파일 언어의 단점인, 타 운영체제에서 실행이 되지 않는 문제를 보완하기 위함.

 

 

ex) 사용환경이 편리한 윈도우에서 프로그램을 작성하고, Linux나 Unix 서버에 올려서 실행한다.

각각의 컴퓨터에는 그 운영체제에 맞는 JRE(JVM이 포함되어있음)가 설치되어 있어야 한다.

 

예를 들어 플랫폼에 종속된 경우 윈도우 버전으로 빌드한 프로그램을 그대로 리눅스나 macOS에서 실행하는 것은 불가능하다. 반면 Java로 작성된 프로그램은 플랫폼에 맞는 자바 가상 머신만 설치되어 있다면 대체로 문제없이 동작한다. 이는 바이트코드가 플랫폼이 아닌 자바 가상 머신에서 실행 가능하며, 프로그램 실행의 주체가 운영 체제가 아닌 자바 가상 머신이기 때문이다. 이러한 점을 일컬어 플랫폼에 독립적이라고 한다.

 

그래서 Java 코드는 다시 작성하지 않고도 Windows, Linux, iOS 또는 Android와 같은 기본 플랫폼에서 실행할 수 있다는 장점을 가져서 많은 사랑을 받고 있다.

 

 

객체지향 언어란?

 

소프트웨어를 개발할 때 부품에 해당하는 객체들을 먼저 만들고, 이 객체들을 하나씩 조립해서 완성된 프로그램을 만드는 기법을 객체지향 프로그래밍 Object Oriented Programming, OOP이라고 한다.

 

객체 object란 물리적으로 존재하거나 개념적인 것 중에서 다른 것과 식별 가능한 것을 말한다. 예를 들어 물리적으로 존재하는 자동차, 자전거, 책, 사람은 물론, 개념적인 학과나 강의, 주문 등도 모두 객체가 될 수 있다.

 
객체는 속성과 동작으로 구성된다. 사람은 이름, 나이 등의 속성과 웃다, 걷다 등의 동작이 있고, 자동차는 색상, 모델명 등의 속성과 달린다, 멈춘다 등의 동작이 있다. 자바는 이러한 속성과 동작을 각각 필드 field와 메소드 method라고 부른다.

 

객체지향 프로그램의 특징은 캡슐화, 상속, 다형성이다. 

 

 

☑️캡슐화

캡슐화 Encapsulation란 객체의 데이터(필드), 동작(메소드)을 하나로 묶고 실제 구현 내용을 외부에 감추는 것을 말한다. 외부 객체는 객체 내부의 구조를 알지 못하며 객체가 노출해서 제공하는 필드와 메소드만 이용할 수 있다.

 

 

 

 

필드와 메소드를 캡슐화하여 보호하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하는 데 있다. 자바 언어는 캡슐화된 멤버를 노출시킬 것인지 숨길 것인지를 결정하기 위해 접근 제한자 Access Modifier를 사용한다.

 

 

 

☑️상속

객체지향 프로그래밍에서는 부모 역할의 상위 객체와 자식 역할의 하위 객체가 있다. 부모 객체는 자기가 가지고 있는 필드와 메소드를 자식 객체에게 물려주어 자식 객체가 사용할 수 있도록 한다. 이것이 상속이다. 상속을 하는 이유는 다음과 같다.

 

• 코드의 재사용성을 높여 준다.

잘 개발된 부모 객체의 필드와 메소드를 자식이 그대로 사용할 수 있어 자식 객체에서 중복 코딩을 하지 않아도 된다.

 

• 유지 보수 시간을 최소화시켜 준다.

 부모 객체의 필드와 메소드를 수정하면 모든 자식 객체들은 수정된 필드와 메소드를 사용할 수 있다.

 

 

 

☑️다형성

다형성이란 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질을 말한다. 자동차의 부품을 교환하면 성능이 다르게 나오듯이 프로그램을 구성하는 객체(부품)를 바꾸면 프로그램의 실행 성능이 다르게 나올 수 있다.

 

 

'Java' 카테고리의 다른 글

[JAVA] Thread  (0) 2025.01.08

 

 

데이터베이스센터가 하나만 있다면 어떨까?

쓰긴 편하겠지만 예전 카카오 화재의 경우처럼 재난상황시 모든 데이터를 사용할 수 없게 될 것이다.

 

그래서 우리는 재해복구시스템(DRS)를 갖추고 있어야한다.

방법들은 아래와 같다.

 

1) Mirror Site(미러 사이트)  
주 센터와 동일한 수준의 데이터와 시스템을 원격지에 구축하고 Active 상태로 실시간 동시 서비스를 제공하는 방식 

  2) Hot Site(핫 사이트)  
주 센터와 동일한 수준의 데이터와 시스템을 원격지에 구축하여 Stand-by 상태로 유지하며 재난 발생시 Active 상태로 전환하여 서비스 제공

  3) Warm Site(웜 사이트) 
데이터만 원격지에 보관하고 서비스를 위한 시스템은 확보하지 않거나 최소한으로만 구성하고 재난 발생시에 필요한 시스템을 구성하여 복구

  4) Cold Site( 콜드 사이트) 
최소한의 준비만 해두는 것

 

그럼 각 데이터베이스를 어떻게 동기화 시킬까?

바로 Replication을 사용해 변경사항이 발생하면 실시간 동기화를 함으로써 데이터무결성을 유지하는 것이다.

 

DB 서버 Replication 설정

 

아래 예제는 ubuntu 24버전, mariadb 15.1 환경해서 진행함

mariadb가 양쪽 서버에 깔려있는 상태를 전제


1. Master
  
  1) master 설정
vi /etc/mysql/mariadb.conf.d/50-server.cnf
log-bin=mysql-bin         
server_id=1                   # server의 id 번호 설정 자유롭게 입력가능

systemctl restart mariadb         // 서버 세팅을 바꿧으니 재시작

  2) master 확인
mariadb -u root -p                 
show master status;                  //  master의 정보 확인

  3) master 서버에 slave용 사용자 추가 및 권한 설정
CREATE USER '아이디'@'%' IDENTIFIED BY '비밀번호';    
GRANT REPLICATION SLAVE ON *.* TO '아이디'@'%';
FLUSH PRIVILEGES;

2. Slave
  1) DB 서버 설정
vi /etc/mysql/mariadb.conf.d/50-server.cnf
server_id=2

systemctl restart mariadb

  2) Master 지정


mariadb -u root -p
CHANGE MASTER TO
  MASTER_HOST='[Master 서버 IP]',
  MASTER_USER='아이디',
  MASTER_PASSWORD='비밀번호',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='[마스터에서 show master status 했을 때 File 이름]',
  MASTER_LOG_POS=[마스터에서 show master status 했을 때 position 번호],
  MASTER_CONNECT_RETRY=10;


START SLAVE;


  3) Slave 확인

 

slave 서버


SHOW SLAVE STATUS\G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

 

master 서버

 

show processlist\G;

 

slave 서버에서 master 서버를 slave로 지정하는 것도 가능 -> 미러사이트, 양방향 동기화

 

'DB' 카테고리의 다른 글

[SQL] SQL QUERY 기본 문법  (1) 2024.11.29
[DB] SQL  (1) 2024.11.27
[DB] 데이터베이스(DB)란??  (0) 2024.11.27
[DB] 가상환경에서 DB 초기설정  (0) 2024.11.27

 

🚩 SELECT - 조회할 데이터 COLUMN(컬럼) 지정

--SELECT COLUMN FROM TABLE;
SELECT NAME FROM PIZZA;

--여러개도 입력가능, *로 전체 COLUMN 조회가
SELECT NAME,PRICE FROM PIZZA;
SELECT * FROM PIZZA;

 

 

🚩 WHERE - 특정 조건만 조회

 

--PIZZA 테이블에서 별이 3점 이상인 COLUMN을 조회

SELECT * 
FROM PIZZA 
WHERE STAR > 3;

--AND, OR, XOR 사용가능

SELECT * 
FROM PIZZA 
WHERE TASTE = GOOD AND STAR > 3;

--LIKE %는 다중문자 매치, _는 한글자 매치

SELECT * 
FROM PIZZA 
WHERE NAME LIKE "CHESSE%";

--NOT, COLUMN이 NULL이 아닌 경우를 조회할때

SELECT * 
FROM PIZZA 
WHERE SOLD_OUT IS NOT NULL;

--BETWEEN 값과 값 사이의 범위

SELECT * 
FROM PIZZA 
WHERE PRICE BETWEEN 20000 AND 30000;

--IN 여러값 매칭

SELECT * 
FROM PIZZA 
WHERE NAME IN ('PEPE%','CHEESE%','MUSHROOM%');

 

 

🚩 ORDER BY - 조회된 데이터를 정렬

--COLUMN을 기준으로 정렬, 기본 오름차순

SELECT * 
FROM PIZZA 
ORDER BY NAME;

--내림차순

SELECT * 
FROM PIZZA 
ORDER BY NAME DESC;

--기준을 여러개로도 가능, 1번째가 같을때 2번째 기준으로 정렬, 각각 오름차, 내림차 설정도 가능

SELECT * 
FROM PIZZA 
ORDER BY NAME DESC, PRICE ASC;

 

 

 

🚩 LIMIT - 출력 개수 제한

--조회된 데이터 중 몇개가 출력될지 설정

SELECT * 
FROM PIZZA 
WHERE STAR > 3
LIMIT 10;

-- OFFSET 몇번째부터 출력할지 설정

SELECT * 
FROM PIZZA 
WHERE STAR > 3
LIMIT 10 OFFSET 3; 	-- 3번째부터 10번째까지 출력

 

 

🚩 JOIN - 테이블 합병

--JOIN 테이블 합치기

SELECT *
FROM PIZZA
JOIN TOPPING ON PIZZA.ID = TOPPING.ID  -- PRIMARY_KEY와 FOREIGN_KEY로 JOIN;

 

 

🚩 GROUP BY - 데이터 그룹화

--GROUP BY 데이터 그룹화, 주로 집계함수와 같이 쓰임
--SUM, AVG, MAX, MIN, COUNT

SELECT *, SUM(SALES) 
FROM SALES
GROUP BY SALES_AMOUNT;

 

 

🚩 DISTINCT - 중복 데이터 제거

--DISTINCT 중복 데이터 제거

SELECT *, COUNT(DISTINCT SALES_AMOUNT)
FROM SALES
GROUP BY SALES_AMOUNT;

 

 

🚩 HAVING

 

--HAVING 집계함수의 조건 검색

SELECT *, COUNT(DISTINCT SALES_AMOUNT) AS AMOUNT_COUNT
FROM SALES
GROUP BY SALES_AMOUNT
HAVING AMOUNT_COUNT > 3;

 

 

 

 

'DB' 카테고리의 다른 글

[DB] Replication으로 데이터베이스 동기화 (DRS)  (0) 2024.12.03
[DB] SQL  (1) 2024.11.27
[DB] 데이터베이스(DB)란??  (0) 2024.11.27
[DB] 가상환경에서 DB 초기설정  (0) 2024.11.27

스택(Stack)의 특징

  1. LIFO 구조
    • 후입선출(Last In, First Out) 방식으로 동작한다.
    • 나중에 삽입된 데이터가 가장 먼저 제거된다.
  2. 단일 접근점
    • 데이터의 삽입과 제거는 한쪽 끝에서만 이루어집니다(보통 top 또는 head라 부릅니다).
  3. 주요 용어
    • push: 데이터를 스택의 맨 위에 삽입.
    • pop: 스택의 맨 위 데이터를 제거.
    • peek: 스택의 맨 위 데이터를 제거하지 않고 확인.
    • isEmpty: 스택이 비어 있는지 확인.

 

스택의 장점

  1. 간단한 구현
    • 자바에서는 단순히 메서드만 사용하면 금방 구현이 가능하다.
  2. 재귀 문제 해결에 유용
    • 함수 호출 기록을 저장하고 복원하는 데 사용된다.
    • DFS(깊이 우선 탐색) 같은 알고리즘에 필수적이다.
  3. 일시적인 데이터 저장
    • 데이터를 임시 저장하고 나중에 처리하는 데 적합하다.
    • ex) 괄호 검사, 문자열 뒤집기.
  4. 빠른 데이터 접근
    • 스택의 맨 위 데이터에 대한 접근이 시간복잡도 O(1)로 빠르고 효율적이다.

 

스택의 단점

  1. 제한된 데이터 접근
    • 스택은 맨 위(top) 외의 데이터에 직접 접근할 수 없다.
    • 중간 데이터를 읽으려면 다른 자료구조가 필요하다.
  2. 고정 크기(배열 기반 스택)
    • 배열을 사용해 구현할 경우 스택 크기를 미리 정의해야 하며, 크기를 초과하면 Stack Overflow가 발생한다.
  3. 메모리 사용 문제
    • 재귀 호출에서 깊이가 너무 깊으면 스택 메모리가 부족해 Stack Overflow Error가 발생할 수 있다.

 

스택 사용 사례

  1. 알고리즘과 문제 해결
    • DFS(깊이 우선 탐색)
    • 괄호 짝 검사
    • 문자열 뒤집기
    • 이진 트리 순회 (후위/전위 순회)
  2. 시스템 프로세스 관리
    • 함수 호출 및 복귀를 관리하는 콜 스택.
  3. 문서 편집기
    • 실행 취소(Undo) 및 재실행(Redo) 기능 구현.
  4. 수식 계산기
    • 중위(Infix), 후위(Postfix), 전위(Prefix) 표기법의 변환과 계산.

 

 

 

JAVA에서 스택 구현 예제

 

import java.util.Stack;

public class StackExample {
    public static void main(String[] args) {
        // Stack 생성
        Stack<Integer> stack = new Stack<>();

        // push 연산: 데이터 삽입
        stack.push(10);
        stack.push(20);
        stack.push(30);

        // 현재 스택 상태 출력
        System.out.println("Stack after pushes: " + stack);

        // peek 연산: 맨 위 데이터 확인
        System.out.println("Top element: " + stack.peek());

        // pop 연산: 맨 위 데이터 제거
        int removedElement = stack.pop();
        System.out.println("Removed element: " + removedElement);

        // 현재 스택 상태 출력
        System.out.println("Stack after pop: " + stack);

        // isEmpty 연산: 스택 비어있는지 확인
        System.out.println("Is stack empty? " + stack.isEmpty());
    }
}

 

실행결과

 

Stack after pushes: [10, 20, 30]
Top element: 30
Removed element: 30
Stack after pop: [10, 20]
Is stack empty? false

'알고리즘공부' 카테고리의 다른 글

[자료구조] 큐(Queue)  (0) 2024.11.28
1. 알고리즘이란  (0) 2024.11.24
 

컴파일 언어인터프리터 언어는 소스 코드를 어떻게 실행하는지에 따라 구분됩니다. 각각의 특징과 차이점은 아래와 같습니다


컴파일 언어

컴파일러를 사용해 소스 코드를 한 번에 기계어로 변환한 후 실행하는 방식입니다.

  • 특징:
    1. 컴파일 과정 필요: 소스 코드를 기계어로 변환한 실행 파일(바이너리)을 생성.
    2. 실행 속도가 빠름: 한 번 변환된 기계어 파일은 별도의 변환 없이 바로 실행 가능.
    3. 디버깅이 상대적으로 어렵다: 에러가 컴파일 시점에만 감지됨.
    4. 플랫폼 의존성 있음: 생성된 실행 파일은 특정 운영 체제와 하드웨어에 종속적.
  • :
    • C, C++
    • Go
    • Rust
  • 작동 과정:
    1. 소스 코드 작성 (.c 파일 등).
    2. 컴파일러로 기계어 파일(.exe, .out) 생성.
    3. 실행 파일을 실행.

인터프리터 언어

소스 코드를 실행 시 한 줄씩 해석하며 실행하는 방식입니다.

  • 특징:
    1. 실행 시마다 소스 코드를 해석함 → 실행 속도가 느림.
    2. 디버깅이 쉽다: 에러가 코드 실행 중에 발견되기 때문.
    3. 플랫폼 독립적일 수 있음: 인터프리터만 해당 플랫폼에서 실행 가능하면 됨.
    4. 추가 변환 없이 소스 코드를 바로 실행 가능.
  • :
    • Python
    • JavaScript
    • Ruby
    • PHP
  • 작동 과정:
    1. 소스 코드 작성 (.py 파일 등).
    2. 인터프리터가 한 줄씩 읽고 실행.

주요 차이점 비교:

특징컴파일 언어인터프리터 언어
실행 과정 사전 컴파일 후 실행 실행 시 해석하며 실행
속도 빠름 느림
에러 발견 시점 컴파일 단계에서 발견 실행 단계에서 발견
결과물 기계어 실행 파일 생성 별도의 실행 파일 없음
플랫폼 독립성 플랫폼 의존적 플랫폼 독립적일 가능성 높음
사용 사례 시스템, 고성능 응용 프로그램 스크립트, 웹, 데이터 처리

자바

  • 자바는 컴파일 언어와 인터프리터 언어의 혼합입니다.
    1. 먼저 컴파일러(javac)로 바이트코드로 변환 (컴파일 언어 방식).
    2. JVM이 바이트코드를 실행 시점에 해석 및 최적화 (인터프리터 방식).

이런 방식 덕분에 자바는 플랫폼 독립성과 실행 성능을 모두 확보합니다.

+ Recent posts