반응형

프로그램 동작 원리

  • 기본적으로 소프트웨어가 작성되어 CPU에서 실행되기까지의 과정은 다음과 같다.
    • 소스파일 작성 → 컴파일러나 인터프리터가 어셈블리어로 번역 → 어셈블러가 기계어로 번역 → 목적 파일 생성 → Linking → loader module 생성 → loader → CPU execute
      1. 우리가 C나 C++ 등의 고급언어로 소스코드를 작성한다.
      2. 언어에 맞는 컴파일러(혹은 인터프리터)가 어셈블리어로 번역해준다.
      3. 어셈블리어로 번역된 파일을 어셈블러가 기계어 코드(0,1)인 목적 파일로 번역한다.
      4. 규모가 어느정도 있는 프로그램이면 한 파일에 모든 소스코드가 있지 않다. 여러 파일로 나눠져 컴파일이 된 목적 파일들을 연결해야한다. 이 과정을 Linking이라고 한다.
      5. Linker에 의해 연결한 파일을 loader module이라고 한다.
      6. loader는 loader module을 메모리에 올린다.
      7. 메모리에 올라간 loader module을 CPU가 실행한다.

그럼 JVM은 어떻게 동작하는 것일까?

JVM의 동작 원리

  • Java 언어의 특징은 어떤 플랫폼, 운영체제에서도 동작하는 것이다. 앞에서 본 것처럼 목적 파일로 만들어져 바로 CPU에서 수행되는 것이 아니다.

JDK 구조

  • 우선 JDK의 구조부터 보자.
  • https://medium.com/@mannverma/the-secret-of-java-jdk-jre-jvm-difference-fa35201650ca
    • JDK > JRE > JVM
    • 이런 포함관계를 갖는다.
      • JDK(java development kit)
        • 컴파일러, 디버거, JRE가 있다.
          • JRE(java runtime environment)
            • JVM과 라이브러리가 있다.
          • JVM(java virtual machine)
            • https://ahea.wordpress.com/2017/05/25/자바개발자가-알아야-할-jvm과-garbage-collection/
            • JVM 내부에는 Class Loader, Runtime Data Areas, Execution Engine 등이 있다.

Class Loader

  • 클래스 로더는 바이트 코드(.class)를 받아서 필요한 클래스를 가져와 JVM의 메모리에 로드하고, 링킹하고 초기화 하는 과정을 수행한다.
  • 자바는 컴파일 타임에 모든 클래스를 로드하는 방식이 아닌, 런타임에 클래스가 필요하면(참조할 때) 클래스를 로드하고 링킹하는 동적로드를 한다. - JVM에서 동적로드를 담당한다.

Class Loader 특징

이제 JVM이 어떻게 class 파일을 기계어 코드로 변환하는지 알아보자.

  • 계층 구조 - JVM의 클래스 로더는 여러개가 있는데 이 클래스 로더끼리 부모-자식관계의 계층 구조를 이루고 있다.
  • 위임모델 - 게층 구조를 바탕으로 클래스 로더끼리 호출을 위임한다. 클래스를 로딩할 때, 최상위 클래스로더인 부트스트랩 클래스 로더를 확인하고 이 클래스 로더에 로딩하려는 클래스가 없다면 자식 클래스 로더로 책임을 넘긴다. - 위임 모델 다이어그램
  • https://d2.naver.com/helloworld/1230
    • 부트스트랩 클래스 로더
      • JVM이 처음 실행될 때 생성된다. 최상위 Object클래스와 Java api들을 로드한 - 익스텐션 클래스 로더(Extension Class Loader)
        • 기본 자바 API를 제외한 확장 클래스들을 로드한다.
          • 시스템 클래스 로더(System Class Loader)
            • 사용자가 작성한 클래스들(?), $CLASSPATH 내의 클래스들을 로드한다.
          • 사용자 정의 클래스 로더(User-Defined Class Loader)
            • 애플리케이션 사용자가 직접 코드 상에서 생성해서 사용하는 클래스 로더이다.
  •  
  • 가시성 제한 - 하위 클래스 로더에서는 상위 클래스로더의 클래스를 찾을 수 있다. - 반대는 안된다.
  • 언로드 불가 - 클래스 로더는 클래스를 로딩만 할 수 있다. - 이미 로드된 클래스를 언로드 할 수는 없다.

클래스 로딩 과정

  1. 로딩
    • 클래스 파일을 가져와서 JVM 메모리에 로드
  2. 링킹
    • 검증
      • 자바, JVM의 명세에 맞게 작성 되어 있는지 확인
    • 준비
      • 클래스가 필요로하는 메모리를 할당 (필드, 메소드 등)
    • 분석
      • 클래스의 상수 풀 내의 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경
        • 클래스 파일은 JVM이 프로그램을 실행할 때 필요한 API를 Link할 수 있도록 심볼릭 레퍼런스를 가진다. 심볼릭 레퍼런스를 런타임 시점에 메모리 상에서 실제로 존재하는 물리적인 주소로 대체하는 Linking 작업이 일어난다.
        • 심볼릭 레퍼런스는 참조하는 대상의 이름을 지칭하고, 클래스 파일이 JVM에 올라가게 되면 심볼릭 레펀선스는 실제 메모리 주소가 아닌 이름에 맞는 객체의 주소를 찾아서 연결하는 작업을 수행한다.
  3. 초기화
    • 클래스 변수들을 초기화한다. → static 필드들을 설정된 값으로 초기화 한다.

Runtime Data Areas

  • JVM이 OS위에서 실행되면서 할당받아 사용하는 메모리 영역이다. - 6개 영역으로 구분된다.
  • https://d2.naver.com/helloworld/1230
  • 쓰레드 마다 생성
    • PC Register
      • 현재 수행 중인 JVM의 명령어 주소
    • JVM Stack
      • 쓰레드가 시작될 때 생성
      • 스택 프레임을 저장하는 스택이다.
        • 메소드 스택
          • 지역변수, 매개변수, 반환 주소 등
    • Native Method Stack
      • 자바 외의 언어로 작성된 네이티브 코드를 위한 스택
  • 모든 쓰레드가 공유
    • Heap
      • 인스턴스를 저장하는 공간
      • 가비지 컬렉션 대상
    • Method Area
      • JVM이 시작될 때 생성된다.
      • JVM이 읽어 들인 각각의 클래스와 인터페이스에 대한 런타임 상수 풀, 필드와 메소드 정보, static 변수, 메소드의 바이트 코드 등이 포함된다.
    • Runtime Constant Pool
      • Method Area에 포함되는 영역이다.
      • JVM에서 가장 핵심적인 역할 수행
      • 클래스와 인터페이스의 상수, 메소드, 필드에 대한 모든 레퍼런스를 담고 있는 테이블
      • 메소드나 필드를 참조할 때, 이 테이블을 통해 실제 메모리상의 주소를 찾는다.

Execution Engine

  • JVM의 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 실행한다.
  • 바이트 코드(.class)를 JVM 내부에서 실행할 수 있는 형태(기계어?)로 바꾼다.
  • 바꾸는 방법이 2가지가 있다
    • 인터프리터
      • 바이트 코드 명령어를 하나씩 읽고 해석해서 실행한다.
      • 하나하나의 해석은 빠르지만 전체 실행 결과는 느리다.
      • 바이트 코드는 기본적으로 인터프리터 방식으로 동작한다.
    • JIT(Just In Time)
      • 인터프리터의 단점을 보완하기 위해 도입된 JIT 컴파일러 이다.
      • 바이트 코드 전체를 컴파일하여 네이티브 코드로 변경한다.
        • 전체를 컴파일하는 과정이 인터프리터 보다 느리다.
        • 따라서 한 번만 실행되는 코드라면 컴파일 하지 않는다.
        • JIT 컴파일러를 사용하는 JVM들은 내부적으로 컴파일하려는 메소드가 얼마나 자주 실행되는지 체크하고 일정 수준 이상일 때 컴파일을 한다.

정리

  1. 자바 소스코드를 작성한다.
  2. JDK의 자바 컴파일러가 자바 파일을 바이트 코드로 변환한다.
  3. JRE 안의 JVM의 클래스 로더가 바이트 코드를 받아서 JVM의 메모리에 올리고, 필요한 클래스들을 로딩한다.
  4. 실행 엔진이 메모리 상에 있는 바이트 코드를 JVM 내부에서 실행할 수 있는 기계어 형태로 바꿔서 실행한다.

참고자료

https://yeon-kr.tistory.com/112

https://steady-snail.tistory.com/67

https://ahea.wordpress.com/2017/05/25/자바개발자가-알아야-할-jvm과-garbage-collection/

https://medium.com/@mannverma/the-secret-of-java-jdk-jre-jvm-difference-fa35201650ca

https://d2.naver.com/helloworld/1230

https://lkhlkh23.tistory.com/100

 
728x90
반응형

가비지 컬렉터

뭐지?

C나 C++같은 언매니지드 언어는 OS 레벨의 메모리의 직접 접근해서 메모리를 관리한다.

자바는 OS위의 JVM위에서 돌아간다. 이 JVM이 알아서 메모리 상에 필요하지 않은 데이터를 해제하여 공간을 확보해준다.

  • JVM의 메모리 구조
    • 스택
      • 힙 영역에 생성된 객체를 참조하기 위한 값들이 할당된다.
      • 메서드 작업에 필요한 메모리 공간
        • 지역변수, 파라미터 등
      • 인스턴스가 생성된다.

예시

지역변수로 String 변수를 만들고 값을 넣으면, 참조변수는 스택에 할당되고 String 리터럴 값은 힙 영역에 할당되게 된다.

String str = "heap";

자바에서는 문자열에 어떤 다른 문자열을 더하면 원래 주소에 더해지는게 아니라, 새로운 인스턴스를 만들어 다른 주소를 참조하게 된다.

str += "123";

이처럼 더하게 되면 힙 영역에는 2개의 String 리터럴이 존재하는 것이다.

이때, 더 이상 참조하지 않는 "heap" 리터럴을 Garbage Collector가 삭제해주는 것이다.

이렇게 더 이상 참조하지 않는 객체를 Unreachable Object라고 한다.

동작

Mark → Sweep

  • Mark
    • GC가 스택의 모든 변수를 스캔하면서 참조하는 오브젝트를 찾는다. 참조한 오브젝트가 참조하는 오브젝트까지 다 마킹한다.
  • Sweep
    • Mark 되어있지 않은 힙의 오브젝트들을 지운다.

자바의 정석 예제 13-20

다중 쓰레드를 사용하여 가비지 컬렉터를 간단히 흉내내본 예제이다.

메모리 공간을 나누지 않았고, Unreachable Object 를 삭제하는게 아니라 시간에 따라 공간을 확보하는 식이다.

public class GarbageCollector extends Thread {
    final static int MAX_MEMORY = 1000;
    int usedMemory = 0;

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(10 * 1000);
            } catch (InterruptedException ie) {
                System.out.println("Awaken by interrupt()");
            }

            gc();
            System.out.println("Garbage Collected. Free Memory :"+freeMemory());
        }
    }

    public void gc() {
        usedMemory -= 300;
        if (usedMemory < 0) usedMemory = 0;
    }

    public int totalMemory() { return MAX_MEMORY; }
    public int freeMemory() { return MAX_MEMORY - usedMemory; }
}
  • 최대 메모리는 1000이라고 한다.
  • 10초를 sleep하고, gc()를 실행한다.
    • 사용중인 메모리를 300감소한다.
public class GarbageCollectorTest {
    public static void main(String[] args) {
        GarbageCollector gc = new GarbageCollector();
        gc.setDaemon(true);
        gc.start();

        int requiredMemory = 0;

        for (int i = 0; i < 20; i++) {
            requiredMemory = (int) (Math.random() * 10) * 20;

            if (gc.freeMemory() < requiredMemory || gc.freeMemory() < gc.totalMemory() * 0.4) {
                gc.interrupt();
                try {
                    gc.join(100);
                } catch (InterruptedException ie) { }
            }

            gc.usedMemory += requiredMemory;
            System.out.println("gc.usedMemory = " + gc.usedMemory);
        }
    }
}
  • gc 객체를 데몬 쓰레드로 만들었다.
    • 데몬 쓰레드는 일반 쓰레드가 모두 종료되면 자동으로 종료되는 쓰레드이다.
      • 데몬 쓰레드로 지정하지 않으면, for문을 다 돌고 메인 쓰레드가 종료되어도 gc는 다른 쓰레드에서 계속 실행되게 될 것이다.
  • 랜덤 값을 메모리 사용량으로 계속 넣는다.
  • 여유공간이 필요공간보다 적거나, 여유공간이 40% 미만이면 잠자고 있는 가비지 컬렉터를 깨운다.
    • 깨우지 않더라도 10초마다 작동한다.
  • 깨우는 부분을 보면 interrupt() 외에도 join() 메소드가 있다.
    • gc를 깨우고 가비지 컬렉션이 시작되기 전에 메인 메소드에서 또 추가를 할 수 있으므로 기다릴 시간을 주는 것이다.
    • join()에 지정된 시간동안 작업을 수행하고 호출장소로 돌아온다.
      • 지정된 시간동안은 메인 쓰레드가 수행되지 않는 것이다.
gc.usedMemory = 20
gc.usedMemory = 20
gc.usedMemory = 20
gc.usedMemory = 60
gc.usedMemory = 100
gc.usedMemory = 120
gc.usedMemory = 160
gc.usedMemory = 200
gc.usedMemory = 380
gc.usedMemory = 520
gc.usedMemory = 520
gc.usedMemory = 640
Awaken by interrupt()
Garbage Collected. Free Memory :660
gc.usedMemory = 340
gc.usedMemory = 360
gc.usedMemory = 460
gc.usedMemory = 520
gc.usedMemory = 640
Awaken by interrupt()
Garbage Collected. Free Memory :660
gc.usedMemory = 420
gc.usedMemory = 580
gc.usedMemory = 580

Process finished with exit code 0
  • 실행 결과는 이런식으로 나온다.

참고

https://yaboong.github.io/java/2018/06/09/java-garbage-collection/

728x90
반응형

자바를 기준으로 설명합니다. 하지만 객체지향언어에선 대부분 비슷할 것이라고 생각됩니다.

본인이 웹 개발을 공부하며 느끼고 이해한 내용에 대해 말합니다.


문법적으로 먼저 보면, 인터페이스는 상수와 추상메소드만 존재하는 추상클래스이다.

추상메소드라는 것은 메소드의 선언부만 있고, 몸통 부분은 없는 메소드이다.

(java8부터? 유지보수의 편의를 위해 default, static메소드 등도 포함되었다)

public abstract class MyInterface {
		public abstract void run();
}

// 실제로 인터페이스는 인터페이스 키워드를 사용한다.
public interface MyInterface {
		public void run(); // 컴파일러가 추상메소드로 바꿔준다.
}

이렇게 얘기해서는 감이 잘 안올 것이다.

먼저 추상화와 다형성에 대해 생각해보자.

추상화

  • 예를들어 일반적인 컴퓨터를 사용할 때는 윈도우와 Mac같은 GUI OS를 사용한다.
    • 이 OS를 뜯어보면 실제 로직은 커널을 조작하는 명령어가 있을 것이다.
    • 또 이 명령어는 전기 신호로 변환되어 cpu에서 동작할 것이다.
  • 이렇게 전기 신호를 명령어로 추상화하고, 명령어를 다시 GUI 환경으로 추상화했다.
  • 이런 과정을 추상화라고 한다. 추상화 단계의 최상단에 있는 사용자는 내부 로직이 바뀌더라도 이전과 동일하게 사용할 수 있다.
  • 애플의 인텔 맥과 ARM 맥은 사용자 입장에서 큰 변화 없이 동일하게 사용할 수 있다.

다형성

한 가지 타입으로 여러가지 구현체를 사용할 수 있는 것이다.

  • 예를들어 닌텐도 스위치를 쓴다고 하자.
    • 마리오 게임용 닌텐도 스위치, 젤다 게임용 닌텐도 스위치를 따로 사지 않아도 닌텐도 스위치 하나에서 모든 게임을 동작시킬 수 있다.
  • 브라우저도 마찬가지이다.
    • 네이버용 브라우저, 구글용 브라우저, 유튜브용 브라우저 따로 만들지 않는다. 한가지 브라우저로 모든 웹사이트를 이용할 수 있다.
  • 자동차 운전면허도 현대 운전면허, 포드 운전면허, 벤츠 운전면허가 따로 존재하지 않는다.
  • 사용자는 각 상황에 맞는 스위치, 브라우저, 운전면허를 알 필요가 없다. 대표적인 하나만 알고 있으면 되는거다.

결론

  • 그래서 인터페이스를 왜 쓰느냐?

많은 이유가 있겠지만 본인이 쓰면서 가장 몸소 느낀바는 다형성이다.

  • 그럼 다형성은 왜 쓰느냐?

유지보수의 편의를 위해서다. 기존의 코드의 로직이 변경될 때 변경되는 부분을 최소화 시키기 위해 한단계 추상화 하는 것이다.


인터페이스 사용 예시

인터페이스를 사용했을 때, 어떤 식으로 유지보수가 편해지는지를 알아보자.

인터페이스를 사용하지 않을 때

  • 사용자와, TV가 있다고 하자.
    • tv는 samsung tv와 lg tv가 있고 전원 on/off, 채널 up/down 기능이 있다.
class SamsungTv {
    private boolean power;
    private int channel;

    public void power() {
        power = !power;
    }

    public void channelUp() {
        channel++;
    }

    public void channelDown() {
        channel--;
    }
}
class Client{
    public static void main(String[] args){
        SamsungTv tv = new SamsungTv();
        
        //power on
        tv.power();

        tv.channelUp();
        tv.channelUp();
    }
}
  • 이렇게 클라이언트가 SamsungTv를 잘 사용하고 있었는데, 새로운 LG TV가 나와서 바꾸기로 하자.
class LgTv {
  private boolean power;
  private int channel;

  public void switchPower() {
      power = !power;
  }
    
  public void increseChannel() {
      channel++;
  }

  public void decreaseChannel() {
      channel--;
  }
}
  • 새로나온 LG TV를 보니, 기존 삼성 TV와 하는 역할은 같지만 작동 방식(메소드)가 완전히 달라졌다.
  • 따라서 클라이언트의 메소드를 사용하는 부분과 클래스를 선언하고 인스턴스를 생성한 부분을 모두 바꿔줘야한다.
class Client{
  public static void main(String[] args){
      LgTv tv = new LgTv();
    
      //power on
      tv.switchPower();

      tv.increaseChannel();
      tv.decreaseChannel();
  }
}
  • TV가 한번 바뀔 때마다. 선언부, 메소드 사용하는 코드를 전부 바꿔야 했다.
  • 여러사람이 작업하다보면 기존의 규칙을 무시하고 작업하는 경우도 있고, 코드가 몇천줄이 넘어가는 경우가 생길 수도 있다.
  • 최악의 상황에는 일일히 다 바꿔야한다.

인터페이스를 사용할 때

  • 인터페이스를 사용하게되면 위에서 겪었던 대부분의 문제를 해결할 수 있다.
  • 우선 TV라는 인터페이스를 만든다.
public interface Tv {
    public void power();
    public void channelUp();
    public void channelDown();
}
  • 이 인터페이스를 구현하는 삼성 TV 클래스를 만들자.
public class SamsungTv implements Tv {
    private boolean power;
    private int channel;
    
    public void power() {
        power = !power;
    }

    public void channelUp() {
        channel++;
    }

    public void channelDown() {
        channel--;
    }
}
  • 이제 클라이언트에서 TV를 사용할 때에는 Tv 인터페이스형(참조변수 타입)을 사용하면 된다.
public class Client {
    public static void main(String[] args) {
        Tv tv = new SamsungTv();
        
        tv.power();
        tv.channelUp();
        tv.channelDown();
    }
}
  • 새로운 TV를 만들어야한다면 이제 Tv 인터페이스를 구현하면 된다.
public class LgTv implements Tv {
  private boolean lgPower;
  private int lgChannel;

  public void power() {
      lgPower = !lgPower;
  }

  public void channelUp() {
      lgChannel++;
  }

  public void channelDown() {
      lgChannel--;
  }
}
  • 인터페이스를 쓰면 메소드 명이 변경될 일이 없기 때문에 사용자는 변경된 사용방법(메소드)를 새로 알아야 필요가 없어졌다.
public class Client {
  public static void main(String[] args) {
      Tv tv = new LgTv();
        
      tv.power();
      tv.channelUp();
      tv.channelDown();
  }
}
  • Tv 타입의 참조변수에 들어가는 인스턴스만 바꿔주면 다른 코드는 전혀 변경하지 않아도 된다.
  • 여기서는 아주 작고, 단순한 문제를 다뤘지만, 여러가지 클래스의 포함관계가 복잡하게 얽혀있을 때 다형성은 힘을 발휘한다.

Next step…

인터페이스를 사용하면, 구현체가 바뀌더라도 유연하게 대응할 수 있다.

또, 구현을 하는 클래스에 대해 어느정도의 가이드 라인을 제공해주는 역할도 한다.

하지만 여전히 코드를 바꿔야하는 부분이 존재한다.

제어의 역전(IoC)가 제대로 일어나지 않았고, SOLID원칙의 OCP, DIP 원칙에 위배된다.

이 문제를 해결하기 위해 의존성 주입(DI)을 사용할 수 있다.

 

https://docs.google.com/presentation/d/1KoGEpn3wO4cAXKkOQSARFJFMSlHalQdyBQ-XtjZyhhw/edit?usp=sharing

728x90
반응형

JDBC란?

  • 데이터 베이스를 자바기반 어플리케이션에서 사용하기 위한 라이브러리.
  • Oracle, MS SQL, MySQL 등 각 언어마다 쿼리는 다르지만, 기능은 동일하다.
    • DB에 관계없이 자바 코드로 데이터 베이스를 작성할 수 있는 인터페이스이다.
  • Java DataBase Connectivity
  • 사용하는 데이터베이스를 교체해도 자바 코드를 바꾸지 않아도 된다.
  • JDBC가 실제 데이터 베이스를 동작시키기 위해 각 제조사에서 만들어놓은 JDBC Driver를 사용한다.
    • 실제 구동은 드라이버가 한다.

실행 과정

  1. 드라이버 로드하기
  2. 연결 생성
  3. 문장 실행
  4. 결과집합 사용하기

DB와 Driver 설치

현재 랩탑에 설치돼있는 mysql 8.0.25을 사용하겠다.

 

MySQL :: Download Connector/J

MySQL Connector/J 8.0 is highly recommended for use with MySQL Server 8.0, 5.7 and 5.6. Please upgrade to MySQL Connector/J 8.0.

dev.mysql.com

실습

데이터 조회

기본 코드 이해

  • 연결 단계
    • 이러한 순서로 진행된다.
      • new 연산자로 객체를 만들지 않는다.
    1. Class.forName("com.mysql.cj.jdbc.Driver");
      • 1번이 실행되면, 드라이버가 메모리에 올라간다.
    2. Connection con = DriverManager.getConnection(...);
      • 2번이 실행되면, 연결이 이루어진다. 드라이버 객체를 얻는다.
    3. Statement st = con.createStatement();
      • 3번이 실행되면, 쿼리를 실행한다.
        • 결과 집합이 만들어진다.
        • 레코드 단위로 한줄 씩 받아온다.
    4. ResultSet rs = st.executeQuery(sql);
    5. rs.next();
    6. String title = rs.getString("title");
      • 순회하면서 데이터를 얻는다.
public class Program {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql://localhost:3306/connectdb?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC";
        String sql = "SELECT * FROM employee";

        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(url, "connectuser", "connect123!@#");
        Statement st = con.createStatement();
        ResultSet rs = st.executeQuery(sql);

        rs.next();
        String name = rs.getString("name");
        System.out.println(name);


        rs.close();
        st.close();
    }
}

데이터 추가

public class Program2 {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql://localhost:3306/connectdb?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC";
//        String sql = "INSERT INTO employee VALUES(1111, 'Choi', 'programmer', 7788, '2019-12-22', 9999.99, 300.00, 10)";
        String sql = "INSERT INTO employee VALUES(?,?,?,?,?,?,?,?)";

        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(url, "connectuser", "connect123!@#");
//        Statement st = con.createStatement();
        PreparedStatement st = con.prepareStatement(sql);
        st.setInt(1, 1111);
        st.setString(2, "Choi");
        st.setString(3, "Pro");
        st.setInt(4, 7788);
        st.setString(5, "2019-12-22");
        st.setBigDecimal(6, BigDecimal.valueOf(9999.99));
        st.setBigDecimal(7, BigDecimal.valueOf(300.00));
        st.setInt(8, 10);

        int result = st.executeUpdate();

        st.close();
        con.close();
    }
}

데이터 수정

public class Program3 {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql://localhost:3306/connectdb?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC";
        String sql = "UPDATE EMPLOYEE SET job = 'CTO' WHERE name = 'Choi'";

        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(url, "connectuser", "connect123!@#");
        PreparedStatement st = con.prepareStatement(sql);

        int result = st.executeUpdate();

        st.close();
        con.close();
    }
}

데이터 삭제

public class Program4 {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql://localhost:3306/connectdb?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC";
        String sql = "DELETE FROM employee WHERE name = 'Choi'";

        Class.forName("com.mysql.cj.jdbc.Driver");
        Connection con = DriverManager.getConnection(url, "connectuser", "connect123!@#");
        PreparedStatement st = con.prepareStatement(sql);

        int result = st.executeUpdate();

        st.close();
        con.close();
    }
}

쿼리문만 바꿔서 데이터 CRUD를 할 수 있다.

어떤 조건을 걸때는 자바 단에서 하는 게 아니라 쿼리문에서 해주는 것이 시간,공간을 절약할 수 있다.

728x90

'Programming > 언어' 카테고리의 다른 글

[Kotlin] 표현식과 명령문  (0) 2023.02.12
Java 코드가 실행되는 과정  (0) 2021.12.26
Garbage Collector 찍먹하기  (0) 2021.12.26
객체지향에서 인터페이스란?  (0) 2021.12.26
Java 자잘한 실수 모음  (0) 2020.07.06

+ Recent posts