JDBC

2023. 12. 20. 16:12
728x90

JDBC (Java DataBase Connectivity)

: 데이터베이스는 파일의 형태로 데이터를 효율적으로 저장하기 위한 프로그램

> Java Application에서 데이터베이스를 사용하기 위해 데이터베이스와 소통해야 하는데, 이걸 가능하게 하는 API

 

1. Gradle

1) Build 

>> JDK (Java Development Kit) : Java 언어를 Java Bytecode로 변환하는 컴파일러(javac)

 

* High Level Language를 Low Level Language로 >> 컴파일(Compile)한다.

* 프로젝트 소스코드를 실행 가능한 프로그램으로 >> "빌드(Build)"한다.

 

2) Build Automation Tool

- Maven & Gradle

- Java 프로젝트를 빌드하는데 사용되는 대표적인 도구. 

- 소스코드 컴파일, 단위 테스트, 버전관리, JAR 생성 (배포를 위해 Java Class를 부수 정보와 함께 압축하는 형태)...

 

3) Dependency Management

: 프레임워크나 라이브러리(의존성)을 사용한다.

- 다른 개발자가 이미 만들어 놓은 것을 활용하는 것

- 해당 라이브러리 코드도 우리가 가져와서 설정해야 하는데, Maven&Gradle은 인터넷에 연결되어 있으면 라이브러리를 자동으로 가져온다! 

build.gradle에서 의존성 추가

 

>> 어떻게 가져오냐면? 

Maven Repository에서 ! 검색 후 복사/붙여넣기~

https://mvnrepository.com/

 

2. Statement & ResultSet

1) JDBC

: Java에서 직접적으로 사용하는 것은 JDBC API.

- 데이터베이스와 소통하기 위한 드라이버가 필요하다 >> 드라이버를 관리해주는 클래스가 DriverManager!

(* 드라이버란? : GPU 같은 하드웨어, 또는 Low-Level Software와 소통하기 위한 소프트웨어 부품)

 

 

2) DriverManager

: DriverManager를 이용해 데이터베이스에 접근하기 위한 연결 형성

- 먼저 어디에 있는 데이터베이스인지 작성한다. (= JDBC URL)
(url은 데이터베이스 properties에서 찾을 수 있다)

String connectionString = "jdbc:sqlite:db.sqlite";

- 이 문자열을 DriverManager.getConnection에 인자로 전달하면 데이터베이스와 연결된다.
String connectionString = "jdbc:sqlite:db.sqlite";
try (Connection connection = DriverManager.getConnection(connectionString)) {
	System.out.println("Connection Success!");
} catch (SQLException e) {
	System.out.println(e.getErrorCode());
    System.out.println(e.getMessage());
    throw new RuntimeException(e);
}​


cf) 이전 버전의 JDBC에서는 클래스를 따로 가져왔어야 하지만, 이제는 할필요가 없다.

try {
    Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
    throw new RuntimeException(e);
}

 

3) Statement

: SQL을 전달하는데 사용할 수 있는 Statement 

> DriverManager한테 받은 Connection 객체를 활용. 

> execute() 메서드로 SQL 쿼리를 실행.

        try (Connection connection = DriverManager.getConnection(connectionString)) {
            System.out.println("connection success!!");
            // 데이터베이스 연결 객체로부터 Statement 객체를 받는다.
            Statement statement = connection.createStatement();
            // execute를 이용해 간단한 SQL 문을 사용한다.
            statement.execute("drop table if exists user;");
            statement.execute("""
                create table user(
                    id INTEGER primary key AUTOINCREMENT,
                    username TEXT,
                    password TEXT,
                    first_name TEXT,
                    last_name TEXT,
                    email TEXT
                );
            """);
            // 서로 다른 사용자 계정 3개 입력
            statement.execute("""
                    insert into user (username, password, first_name, last_name, email)
                    values ("kim", "kim", "ys", "kim", "s@naver.com"),
                            ("kang", "kang", "ym", "kang", "y@naver.com"),
                            ("jo","jo", "sh", "jo", "j@naver.com");
                    """);
        } catch (SQLException e) {
            System.out.println(e.getErrorCode());
            System.out.println(e.getMessage());
            throw new RuntimeException(e);
        }

> 한 execute() 메서드 안에는 하나의 SQL 쿼리만을 실행할 수 있다. (난 여러개 넣었다가 안됐다 ㅎㅎ.)

  • executeQuery() : SELECT를 이용할 때 사용 >> ResultSet이 필요함. 
  • executeUpdate() : 데이터의 구조를 바꿀 때 사용 (update할때....) >> 내가 실행한 SQL문의 결과로 바뀐 줄의 갯수를 반환해줌. 
  • execute() : 결과를 정확히 알지 못할 때 대신 사용
            String updateSql = """
                    update user
                    set first_name = 'Alexander'
                    where id = 1;
                    """;
            int rows = statement.executeUpdate(updateSql);
            System.out.println(rows);

 

4) ResultSet

- SELECT의 결과는 ResultSet 객체로 반환된다.

  • next() : 결과 테이블의 다음 줄로/ 다음에 더이상 데이터가 없을 때 false 반환!
  • get{type}() : type형으로 컬럼 데이터를 회수하기 위해 사용.

public class Main {
    public static void main(String[] args) {
        //1. 어떤 데이터베이스에 연결할지를 String으로 작성
        String connectionString = "jdbc:sqlite:db.sqlite";

        //2 . 해당 데이터베이스에 연결
        try (Connection connection = DriverManager.getConnection(connectionString)) {
            System.out.println("connection success!!");
            // 3. 데이터베이스 연결 객체로부터 Statement 객체를 받는다.
            Statement statement = connection.createStatement();

            String selectSql = """
                    SELECT * FROM user;
                    """;
                    
            // 조회하는 쿼리는 ResultSet으로 데이터를 받는다.
            // ResultSet은 결과 테이블을 살펴볼 수 잇게 도와주는 인터페이스
            ResultSet resultSet = statement.executeQuery(selectSql);
            while (resultSet.next()) {
                System.out.println(resultSet.getString("username"));
                System.out.println(resultSet.getString("first_name"));
                System.out.println(resultSet.getString("email"));
            }
        } catch (SQLException e) {
            System.out.println(e.getErrorCode());
            System.out.println(e.getMessage());
            throw new RuntimeException(e);
        }

    }

}

 

3. PreparedStatement

1) SQL Injection 

: 사용자가 입력하는 데이터를 바탕으로 조회를 하고 싶을 수 있다....

ex.

Scanner sc = new Scanner(System.in);
String input = sc.nextLine(); //사용자의 입력 받음.
String injectSql = "SELECT * FROM user WHERE id=";
injectSql += input;
injectSql += ";";

>> 근데 이 때 사용자가 1 OR 1=1;을 입력한다면? 

결과 Sql은 

SELECT * FROM user WHERE id = 1 OR 1=1;

>> 그럼 id값과 상관없이 모든 user의 정보가 노출되게 된다....!!!!! OMG

이게 SQL Injection..

** 매우 매우 위험한 행동이다!! 보안적으로 문제가 생김.**

 

2) PreparedStatement

: SQL 쿼리문에 빈칸을 만들어 값을 대입하여 사용할 수 있다.

  • SQL문을 먼저 준비!! 
  • ?로 값을 넣을 곳 작성.
  • set{Type} 메서드로 몇번째 빈칸에 어떤 데이터가 들어갈지 지정.
  • 단, 테이블 이름은 변수로 사용 불가. (값만 넣을 수 있다!!)
// updateArticle
    public boolean updateArticle(int id, String change, String changedInput) {
        String targetSql = "UPDATE article SET "+change+" = ? WHERE id = ?;";
        try (PreparedStatement statement = connection.prepareStatement(targetSql)) {
            statement.setString(1, changedInput); //첫번째 물음표에 changedInput을 넣겠다.
            statement.setInt(2, id); // 두번째 물음표에 id를 넣겠다. 
            statement.execute(); // PreparedStatement 실행
            return true;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

 

728x90

'Programming > Database' 카테고리의 다른 글

Redis  (1) 2024.02.14
Transaction  (0) 2024.02.02
정규화 Normalization와 조인 Join  (1) 2023.12.19
[연습문제 모음]  (0) 2023.12.18
Database 기초  (0) 2023.12.18

BELATED ARTICLES

more