Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
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
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[SQL] 예제 소스 정리 - JDBC 본문

네이버클라우드 AIaaS 개발자 양성과정 1기/DBMS, SQL, JDBC, Servlet

[SQL] 예제 소스 정리 - JDBC

끈기JK 2023. 2. 9. 17:33

com/eomcs/jdbc/ex0~5

 

 

예제 소스 정리

 

 

데이터 준비

 

/* eomcs/jdbc/jdbc-programming-ddl.sql */

-- 게시판 테이블 삭제
drop table if exists x_board restrict;

-- 게시물 첨부파일 테이블 삭제
drop table if exists x_board_file restrict;


-- 게시판 테이블 생성
create table x_board (
  board_id int not null primary key auto_increment,
  title varchar(255) not null,
  contents text null,
  created_date datetime null default now(),
  view_count int null default 0
);

-- 게시물 첨부파일 테이블 생성
create table x_board_file (
  board_file_id int not null primary key auto_increment,
  file_path varchar(255) not null,
  board_id int not null,
  constraint fk_board_file foreign key (board_id) references x_board(board_id) /* on delete cascade */
);

-- 게시물 데이터 입력 
insert into x_board(board_id, title, contents)
values(1, '제목1', '내용');

insert into x_board(board_id, title, contents)
values(2, '제목2', '내용');

insert into x_board(board_id, title, contents)
values(3, '제목3', '내용');

insert into x_board(board_id, title, contents)
values(4, '제목4', '내용');

insert into x_board(board_id, title, contents)
values(5, '제목5', '내용');

insert into x_board(board_id, title, contents)
values(6, '제목6', '내용');

-- 게시물 첨부파일 데이터 입력
insert into x_board_file(board_file_id, file_path, board_id) 
values(101, 'a1.gif', 1);
insert into x_board_file(board_file_id, file_path, board_id) 
values(102, 'a2.gif', 1);
insert into x_board_file(board_file_id, file_path, board_id) 
values(103, 'a3.gif', 1);

insert into x_board_file(board_file_id, file_path, board_id) 
values(104, 'b1.gif', 2);
insert into x_board_file(board_file_id, file_path, board_id) 
values(105, 'b2.gif', 2);


insert into x_board_file(board_file_id, file_path, board_id) 
values(106, 'c1.gif', 3);
insert into x_board_file(board_file_id, file_path, board_id) 
values(107, 'c2.gif', 3);
insert into x_board_file(board_file_id, file_path, board_id) 
values(108, 'c3.gif', 3);

insert into x_board_file(board_file_id, file_path, board_id) 
values(109, 'd1.gif', 4);

insert into x_board_file(board_file_id, file_path, board_id) 
values(110, 'e1.gif', 5);

 

 

 

com/eomcs/jdbc/ex0

 

 

package com.eomcs.jdbc.ex0.app;

import com.eomcs.jdbc.ex0.api.Statement;
import com.eomcs.jdbc.ex0.jre.driver.Type1Statement;
import com.eomcs.jdbc.ex0.microsoft.typ2.MSType2Statement;
import com.eomcs.jdbc.ex0.oracle.type2driver.OracleType2Statement;
import com.eomcs.jdbc.ex0.oracle.type4driver.OracleType4Statement;

public class Exam01 {

  public static void main(String[] args) throws Exception {
    // Statement 객체를 사용하여 SQL 을 실행해 보자.
    String sql = "insert into board values('제목...', '내용...', '홍길동')";

    // Statement 객체 만들기

    // Statement 는 SQL을 실행하는 객체의 사용 규칙을 정의한 인터페이스다.
    // 직접 객체를 만들어 사용할 수 없다.
    // 해결책?
    // - Statement 규칙에 따라 정의한 클래스(드라이버)의 객체를 만들어야 한다.
    // Statement stmt = new Statement();

    // [Oracle DBMS를 사용하여 SQL을 실행하기]
    // 
    // 방법1: JRE에서 기본으로 제공하는 type1 드라이버 사용하기
    // - 단 이 드라이버는 실행될 때 ODBC Driver를 사용하기 때문에
    //   반드시 로컬에 ODBC 드라이버가 설치되어 있어야 한다.
    Statement stmt = new Type1Statement(/* 어느 DBMS의 ODBC 드라이버를 사용할 지 파라미터로 넘긴다*/);
    stmt.executeUpdate(sql);

    // 방법2: Oracle에서 제공하는 type2 드라이버 사용하기
    // - 단 이 드라이버는 Oracle vendor api를 사용하기 때문에 
    //   반드시 로컬에 오라클 벤더 API 가 설치되어 있어야 한다.
    Statement stmt2 = new OracleType2Statement();
    stmt2.executeUpdate(sql);
    // 집중!
    // - 드라이버를 교체하더라도 SQL을 실행시키는 메서드 사용법은 같다!!!
    // 

    // 방법3: Oracle에서 제공하는 type4 드라이버 사용하기
    // - 이 드라이버는 내부적으로 직접 오라클 DBMS에 접속하기 때문에 
    //   로컬에 따로 C/C++ 드라이버를 설치할 필요가 없다.
    Statement stmt3 = new OracleType4Statement();
    stmt3.executeUpdate(sql);
    // 집중!
    // - 드라이버를 교체하더라도 SQL을 실행시키는 메서드 사용법은 같다!!!
    //

    // [MS-SQL DBMS로 교체하기]
    // 
    // 방법4: Microsoft에서 제공하는 MS-SQL type2 드라이버 사용하기
    // - 단 이 드라이버는 MS-SQL vendor api를 사용하기 때문에 
    //   반드시 로컬에 MS-SQL 벤더 API 가 설치되어 있어야 한다.
    Statement stmt4 = new MSType2Statement();
    stmt2.executeUpdate(sql);
    // 집중!
    // - 드라이버를 교체하더라도 SQL을 실행시키는 메서드 사용법은 같다!!!
    // 

  }

}

 

package com.eomcs.jdbc.ex0.api;

// JDBC API
// - 개발자가 DBMS에 SQL을 보내기 위해 호출하는 메서드의 시그너처를 정의한 것. 
// 
public interface Statement {
  int executeUpdate(String sql) throws Exception;
}

 

package com.eomcs.jdbc.ex0.jre.driver;

import com.eomcs.jdbc.ex0.api.Statement;

public class Type1Statement implements Statement {

  @Override
  public int executeUpdate(String sql) throws Exception {
    // 자바 개발자가 이 메서드를 호출하면 
    // 내부적으로 C/C++ 로 만든 ODBC Driver의 함수를 호출한다.
    return 0;
  }

}

 

package com.eomcs.jdbc.ex0.oracle.type2driver;

import com.eomcs.jdbc.ex0.api.Statement;

public class OracleType2Statement implements Statement {

  @Override
  public int executeUpdate(String sql) throws Exception {
    // 자바 개발자가 이 메서드를 호출하면
    // 로컬에 설치된 C/C++ Oracle Vendor API의 함수를 호출한다.
    return 0;
  }

}

 

package com.eomcs.jdbc.ex0.oracle.type4driver;

import com.eomcs.jdbc.ex0.api.Statement;

public class OracleType4Statement implements Statement {

  @Override
  public int executeUpdate(String sql) throws Exception {
    // 개발자가 이 메서드를 호출하면 
    // 네트워크를 통해 오라클 DBMS에 직접 SQL을 보낸다.
    return 0;
  }

}

 

package com.eomcs.jdbc.ex0.microsoft.typ2;

import com.eomcs.jdbc.ex0.api.Statement;

public class MSType2Statement implements Statement {

  @Override
  public int executeUpdate(String sql) throws Exception {
    // 개발자 이 메서드를 호출하면
    // 로컬에 설치된 C/C++ MS-SQL Vendor API 를 호출한다.
    return 0;
  }

}

 

package com.eomcs.jdbc.ex0.thirdparty.type3driver;

import com.eomcs.jdbc.ex0.api.Statement;

public class Type3Statement implements Statement {

  @Override
  public int executeUpdate(String sql) throws Exception {
    // 자바 개발자가 이 메서드를 호출하면 
    // 원격의 중계서버에 SQL을 보내는 일을 한다.
    return 0;
  }

}

 

 

 

com/eomcs/jdbc/ex1

 

 

JDBC 드라이버 준비 - 드라이버 다운로드 및 로딩
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;
import java.sql.SQLException;

// DBMS에 연결하기
// => MariaDB에 연결을 대행하는 클래스를 사용한다.
// => 이 클래스는 JDBC API 규칙에 따라 작성되었다.
// => 이 클래스는 JDBC Driver 파일(*.jar)에 들어 있다.
// => 이 클래스를 사용하려면 먼저 이 JDBC Driver 파일을 다운로드 받아
//    프로젝트의 CLASSPATH에 등록해야 한다.
// => 절차
// 1) mvnrepository.com 또는 search.maven.org에서 mariadb jdbc driver를 검색한다.
// 2) 라이브러리 정보를 build.gradle 파일에 설정한다.
// 3) gradle을 이용하여 eclipse 설정 파일을 갱신한다.
//    > gradle eclipse
//    - 다운로드 받지 않은 라이브러리가 있다면 자동으로 서버에서 받을 것이다.
//    - 라이브러리 정보가 변경되었다면 해당 라이브러리를 서버에서 받을 것이다.
//    - .classpath(이클립스 자바 프로젝트의 classpath 정보를 담고 있는 파일) 파일에 
//      다운로드 받은 JDBC Driver 파일의 경로를 추가할 것이다.
// 4) 이클립스 프로젝트를 리프래시 한다.
//    - 프로젝트에 mariadb jdbc driver 라이브러리가 추가되었는지 확인한다.
//
public class Exam0110 {

  public static void main(String[] args) {

    // JDBC 드라이버 등록
    // => java.sql.Driver 규칙에 따라 정의된 클래스를 로딩한다.
    // => Driver 구현체는 JDBC에 대한 정보를 제공한다.
    // => 또한 DBMS에 연결작업을 수행한다.
    // => Driver 구현체는 DriverManager가 관리한다.
    // => 따라서 접속할 DBMS의 Driver 구현체를 생성하여 DriverManager에게 등록해야 한다.
    //
    // DriverManager
    // => java.sql.Driver 구현 객체를 관리하는 일을 한다.
    // => DBMS 연결 요청이 들어오면 해당 DBMS의 Driver 구현체를 찾아 작업을 위임한다.
    //
    //
    // JDBC 드라이버 등록 방법1: 직접 Driver 구현 객체를 생성하고 직접 등록하기
    // => java.sql.Driver 구현체를 생성하여 JDBC 드라이버 관리자에 등록한다.
    // => MariaDB의 JDBC 드라이버에는 org.mariadb.jdbc.Driver 클래스가 이 구현체이다.
    try {

      // 1) java.sql.Driver 구현체의 인스턴스를 생성한다.
      java.sql.Driver mariadbDriver = new org.mariadb.jdbc.Driver();
      java.sql.Driver oracleDriver = new oracle.jdbc.OracleDriver();
      java.sql.Driver mssqlDriver = new com.microsoft.sqlserver.jdbc.SQLServerDriver();

      // 2) java.sql.Driver 구현체의 인스턴스를 드라이버 관리자에 등록한다.
      DriverManager.registerDriver(mariadbDriver);
      DriverManager.registerDriver(oracleDriver);
      DriverManager.registerDriver(mssqlDriver);

      System.out.println("JDBC 드라이버 로딩 및 등록 완료!");

      // DriverManager에 등록된 Driver 인스턴스를 확인해보자!
      // => DriverManager.getDriver(jdbcUrl);
      // => jdbcUrl
      // jdbc:[DBMS]://서버주소:포트번호/데이터베이스명
      java.sql.Driver driver = DriverManager.getDriver("jdbc:mariadb://");
      System.out.println(driver);

      java.sql.Driver driver2 = DriverManager.getDriver("jdbc:oracle:thin://");
      System.out.println(driver2);

      java.sql.Driver driver3 = DriverManager.getDriver("jdbc:sqlserver://");
      System.out.println(driver3);

    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
}

 

 

JDBC 드라이버 준비 - 드라이버 다운로드 및 로딩
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Exam0111 {

  public static void main(String[] args) {

    try {
      java.sql.Driver mariadbDriver = new org.mariadb.jdbc.Driver(); 
      DriverManager.registerDriver(mariadbDriver);
      System.out.println("JDBC 드라이버 로딩 및 등록 완료!");

      // 등록되지 않은 드라이버를 찾을 경우 예외 발생!
      java.sql.Driver driver = DriverManager.getDriver("jdbc:db2://");
      System.out.println(driver);

    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
}

 

 

JDBC 드라이버 준비 - Driver 객체 생성 및 자동 등록
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Exam0120 {

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

    // JDBC 드라이버 등록 방법2: Driver 구현 객체 생성과 자동 등록
    // => Driver 객체를 생성하면 자동으로 DriverManager에 등록된다.
    // => 어떻게?
    // Driver 구현체가 로딩될 때 static 블록에서 인스턴스를 만들어 등록하기 때문이다.

    try {
      // 1) Driver 구현체의 인스턴스 생성
      // => Driver 구현체가 로딩될 때 인스턴스가 생성되기 때문에
      //    굳이 다음과 같이 인스턴스를 생성할 필요가 없다.
      new org.mariadb.jdbc.Driver();

      // 2) DriverManager에 등록 안함!

      // DriverManager에 자동으로 등록됐는지 확인해보자!
      java.sql.Driver driver = DriverManager.getDriver("jdbc:mariadb://");
      System.out.println(driver);
      // 해당 드라이버가 등록되지 않았으면 예외가 발생할 것이다.

    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
}

 

 

JDBC 드라이버 준비 - 드라이버 클래스 로딩과 등록
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0130 {

  public static void main(String[] args) {

    // JDBC 드라이버 등록 방법3: Driver 구현 클래스 로딩과 자동 등록
    // => java.sql.Driver 인터페이스를 구현한 클래스를 로딩하면
    // 해당 클래스에서 자신을 자동으로 DriverManager에게 등록할 것이다.
    // org.mariadb.jdbc.Driver 클래스의 소스를 확인해 보라!
    // static 블록에서 Driver 객체를 만들어 DriverManager에게 등록한다.
    //
    // => 이 방식의 장점은 소스 코드에 클래스를 지정하는 대신
    //    클래스 이름을 지정하기 때문에 실행할 때 다른 클래스로 쉽게 바꿀 수 있다.
    // => 따라서 특정한 Driver 구현체에 종속되지 않게 만들 수 있다.
    try {
      // Class.forName("fully-qualified class name(패키지명을 포함한 클래스명)")
      // => 문자열 파라미터로 주어진 클래스를 찾아 메모리(Method Area)에 로딩한다.
      // => 이 과정에서 static {} 블록이 실행될 것이고,
      //    결국 Driver 인스턴스가 생성되어 DriverManager에게 등록될 것이다.
      // => 확인!
      //    한 번 로딩된 클래스는 중복해서 로딩되지 않는다.
      //    따라서 static {} 블록도 중복해서 실행되지 않는다.
      //    그러니 Driver 인스턴스가 여러 개 생성될까 걱정하지 말라!
      //    DriverManager에 같은 Driver 인스턴스가 여러 개 등록될까 걱정하지 말라!
      //
      Class.forName("org.mariadb.jdbc.Driver");

      // DriverManager에 자동 등록된 것을 확인해보자!
      java.sql.Driver driver = DriverManager.getDriver("jdbc:mariadb://");
      System.out.println(driver);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

JDBC 드라이버 준비 - 드라이버 클래스 로딩과 등록
package com.eomcs.jdbc.ex1;

import java.io.FileReader;
import java.sql.DriverManager;
import java.util.Properties;

public class Exam0131 {

  public static void main(String[] args) {
    try {
      Properties props = new Properties();
      props.load(new FileReader("./jdbc-driver.properties"));
      System.out.println(props.getProperty("jdbc.driverClassName"));
      System.out.println(props.getProperty("jdbc.url"));

      // 위의 방식을 사용하면 다음과 같이, 
      // Driver 구현체를 소스 파일에 직접 명시할 필요가 없다.
      Class.forName(props.getProperty("jdbc.driverClassName"));
      java.sql.Driver driver = DriverManager.getDriver(props.getProperty("jdbc.url"));
      System.out.println(driver);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

JDBC 드라이버 준비 - DriverManager가 Driver 구현체를 자동 로딩
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0140 {

  public static void main(String[] args) {

    // JDBC 드라이버 등록 방법4: Driver 구현체 자동 로딩
    // => DriverManager를 사용할 때,
    //    DriverManager 는 다음 절차에 따라 Driver 구현체를 찾아서 자동으로 로딩한다.
    //
    // 1) jdbc.drivers 시스템 프로퍼티에 지정된 구현체를 찾아 로딩한다.
    // => jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver
    // => 이때 각 Driver 구현체는 'system class loader'를 통해 로딩된다.
    // => 시스템 프로퍼티? JVM에 설정된 "key=value" 이다.
    // => 시스템 프로퍼티를 꺼내는 방법? 다음과 같다.
    System.out.printf("java.home=%s\n", System.getProperty("java.home"));
    System.out.printf("user.home=%s\n", System.getProperty("user.home"));
    System.out.printf("jdbc.drivers=%s\n", System.getProperty("jdbc.drivers"));

    // => 시스템 프로퍼티 설정 방법
    // 예1) JVM을 실행할 때 JVM 옵션을 지정하는 방법
    // - java -Djdbc.drivers=클래스명:클래스명:클래스명 Exam0140
    //
    // 예2) 프로그램 코드에서 설정하는 방법
    // - System.setProperty("jdbc.drivers", "com.eomcs.jdbc.ex1.MyDriver");
    //
    //    System.setProperty("jdbc.drivers", "com.eomcs.jdbc.ex1.MyDriver");
    //    System.out.printf("jdbc.drivers=%s\n", System.getProperty("jdbc.drivers"));

    try {
      // Driver 구현체를 로딩하지 않는다!

      // DriverManager에 자동 등록된 것을 확인해보자!
      // => DriverManager의 getDriver()를 호출하여 java.sql.Driver 구현체를 달라고 요구할 때,
      //    1) JDBC 드라이버 초기화 절차를 수행하지 않았으면,
      //       - CLASSPATH 경로에 설정된 모든 *.jar 파일에 대해 
      //         서비스 로더 규칙(META-INF/services/java.sql.Driver 파일)에 따라 Driver 구현체를 찾아 로딩한다.
      //       - JVM 프로퍼티 "jdbc.drivers" 이름으로 등록된 Driver 구현체가 있다면 그 클래스를 로딩한다. 
      //    2) 등록된 Driver 구현체 목록에서 해당 드라이버를 찾아 리턴한다.
      //    
      java.sql.Driver driver = DriverManager.getDriver("jdbc:mariadb://");
      System.out.println(driver);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

JDBC 드라이버 준비 - DriverManager가 Driver 구현체를 자동 로딩 II
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0141 {

  public static void main(String[] args) {

    // JDBC 드라이버 로딩 방법4: Driver 구현체 자동 로딩
    // => DriverManager를 사용할 때,
    //    JVM은 'service-provider loading' 절차에 따라 
    //    Driver 구현체를 자동으로 로딩한다.
    //
    // 2) java.sql.Driver 클래스의 서비스 제공자를 찾아 로딩한다.
    // => jar 파일 안에 META-INF/services/java.sql.Driver 파일을 찾는다.
    // => 이때 JVM은 'service-provider loading' 절차에 따라 이 파일에 등록된 클래스를 로딩한다.
    // => jar 파일에 해당 정보가 있다면,
    //    앞의 예제처럼 개발자가 따로 java.sql.Driver 구현체를 명시적으로 등록하지 않아도 된다.
    // => mariadb JDBC 드라이버 jar 파일은 이 정보가 들어 있다.
    //    따라서 java.sql.Driver를 구현한 클래스를 로딩하거나 생성할 필요가 없다.
    //

    // 현재 jdbc.drivers 에 등록된 클래스 이름이 없다.
    System.out.printf("jdbc.drivers=%s\n", System.getProperty("jdbc.drivers"));

    try {
      // Driver 구현체를 명시적으로 로딩하지 않는다!

      // DriverManager에 자동 등록된 것을 확인해보자!
      java.sql.Driver driver = DriverManager.getDriver("jdbc:mariadb://");
      System.out.println(driver);

      // 그럼에도 MariaDB Driver를 찾을 수 있다!
      // 왜?
      // - JVM은 프로그램을 실행할 때 
      //   'service-provider loading' 절차에 따라
      //   .jar 파일에 있는 특정 클래스를 찾아 로딩하거나 객체를 자동으로 생성한다.
      // - JDBC의 경우도 이 규칙을 따른다.
      //   DriverManager의 getDriver()를 호출할 때 
      //   'service-provider loading' 규칙에 따라 .jar 파일에서 
      //   Driver 구현체를 찾아 자동으로 로딩한다.

      // 이 프로젝트에 Oracle JDBC 드라이버와 MSSQL Server의 JDBC 드라이버도 있다.
      // 이들 드라이버도 'service-provider loading' 규칙에 따라 만들어졌기 때문에
      // 따로 Driver 구현체를 생성한다거나 등록한다거나 클래스를 로딩하는 일을 하지 않아도
      // 드라이버를 찾을 수 있을 것이다.
      java.sql.Driver driver2 = DriverManager.getDriver("jdbc:oracle:thin://");
      System.out.println(driver2);

      java.sql.Driver driver3 = DriverManager.getDriver("jdbc:sqlserver://");
      System.out.println(driver3);

      System.out.println("테스트!");

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

JDBC 프로그래밍 - DBMS에 연결하기
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0210 {

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

    java.sql.Connection con = null;

    try {
      // JVM에서 jdbc driver 파일(.jar/META-INF/services/java.sql.Driver 파일)을 뒤져서 
      // java.sql.Driver 를 구현한 클래스를 알아내어 자동으로 로딩하기 때문에,
      // 다음과 같이 명시적으로 로딩할 필요가 없다.
      //      Class.forName("org.mariadb.jdbc.Driver");

      // DBMS에 연결하기
      // => Driver 객체를 직접 사용하여 DBMS에 연결하지 않고 대신 DriverManager를 통해 연결한다.
      // => DriverManager에게 연결할 DBMS의 정보(jdbc URL)를 주면 
      //    해당 DBMS의 Driver 객체를 찾아 connect()를 호출한다.
      // jdbc url : DBMS 서버 정보. 
      //  예) jdbc:DBMS://서버주소:포트/데이터베이스명
      //      (포트번호를 지정하지 않으면 mysql인 경우 3306번이 포트번호로 사용된다.)
      // username : DBMS 사용자 아이디
      // password : DBMS 사용자 암호
      //
      con = DriverManager.getConnection(
          "jdbc:mariadb://localhost:3306/studydb", // jdbcURL
          "study", // username
          "1111" // password
          );
      // => DriverManager는 등록된 java.sql.Driver 구현체 중에서
      //    jdbc url에 지정된 DBMS의 Driver 객체를 찾는다.
      //    예) MariaDB: org.mariadb.jdbc.Driver 클래스의 객체
      // => DB 연결을 Driver 구현체에게 위임한다.
      //    즉, Driver 객체의 connect()를 호출한다.
      // => Driver 구현체(org.mariadb.jdbc.Driver 객체)는 DBMS와 연결한 후
      //    소켓 정보를 갖고 있는 java.sql.Connection 구현체를 리턴한다.
      //
      // [App]...................[DriverManager].............[Driver 구현체]
      // ..| getConnection()............|............................|
      // ..|--------------------------->|............................|
      // ..|............................|......connect().............|
      // ..|............................|--------------------------->|
      // ..|............................|............................|-> new MariaDbConnection()
      // ..|............................|..........return............|
      // ..|........return..............|<---------------------------|
      // ..|<---------------------------|............................|
      //
      System.out.println("DBMS와 연결됨!");

      // MariaDB의 Driver 구현체가 리턴한 Connection 객체는
      // 어떤 클래스일까?
      System.out.println(con.getClass().getName());

    } finally {
      // 자원해제
      // => 파일과 마찬가지로 DBMS에 연결한 후 더이상 사용하지 않으면 연결을 해제해야 한다.
      try {
        con.close();
      } catch (Exception e) {
        // 연결 해제하다가 발생된 예외는 무시한다.
        // 왜? 이런 오류는 애플리케이션에서 처리할 방법이 없다.
        // 처리할 필요도 없다.
      }
      System.out.println("DBMS와 연결 해제됨!");
    }
  }
}

 

 

JDBC 프로그래밍 - DBMS에 연결하기
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0220 {

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

    // try-with-resources 문법을 사용하면
    // try 블록을 벗어날 때 close()가 자동 호출된다.
    //
    try (java.sql.Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb", // jdbcURL
        "study", // username
        "1111" // password
        );) {

      System.out.println("DBMS와 연결됨!");

    }
    System.out.println("DBMS와 연결 해제됨!");
  }
}

 

 

JDBC 프로그래밍 - DBMS에 SQL문 보내기 : insert
package com.eomcs.jdbc.ex1;

public class Exam0310 {

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

    try (java.sql.Connection con = java.sql.DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");

        // java.sql.Statement 구현 객체를 얻는다.
        // - SQL문을 DBMS의 형식에 따라 인코딩하여 서버에 전달하는 일을 하는 객체.
        java.sql.Statement stmt = con.createStatement();) {

      // MariaDB의 Connection 객체가 리턴하는 Statement 구현체의 클래스 이름은?
      System.out.println(stmt.getClass().getName());

      // Statement 객체 사용법:
      //
      // 1) INSERT/UPDATE/DELETE 등 DML 관련 SQL문 전송
      // => executeUpdate()
      // => 리턴값: 변경(insert/update/delete)된 데이터의 개수
      //
      // 2) SELECT 등 DQL 관련 SQL문 전송
      // => executeQuery()
      // => 리턴값: 서버에서 데이터를 가져오는 일을 할 객체
      //
      // 용어정리
      // "DML(Data Manipulation Language)"
      // => insert, update, delete 처럼 데이터를 조작하는 sql 명령을 말한다.
      // "DQL(Data Query Language)"
      // => select처럼 data를 조회하는 sql 명령을 말한다.
      //
      int count = stmt.executeUpdate(
          "insert into x_board(title,contents) values('제목10','내용'),('제목11','내용')");
      System.out.printf("%d 개 입력 성공!", count);
    }
  }
}

 

 

JDBC 프로그래밍 - DBMS에 SQL문 보내기 : select
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0320 {

  public static void main(String[] args) throws Exception {
    try (
        java.sql.Connection con = DriverManager.getConnection(
            "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        java.sql.Statement stmt = con.createStatement();

        // executeQuery()
        // => DBMS 서버에 select 문을 보낸다.
        // => 리턴 값: java.sql.ResultSet 구현 객체
        //
        // ResultSet?
        // => 결과가 아니다! 서버에서 결과를 가져오는 일을 할 객체이다.
        // => 즉 서버의 select 실행 결과를 가져올 때 사용하는 도구이다.
        //
        java.sql.ResultSet rs = stmt.executeQuery(
            "select * from x_board order by board_id desc");
        ) {

      System.out.println(rs.getClass().getName());

      // ResultSet 객체를 사용하여 
      // select의 실행 결과 중에서 한 레코드(row)를 서버에서 가져온다.
      //
      boolean isReceived = rs.next(); // 가져왔으면 true, 가져올 게 없다면 false
      // 용어정리
      // "레코드(record)"
      // => select를 실행한 후 생성된 결과이다.
      //

      if (isReceived) {
        // 서버에서 한 개 가져온 결과를 출력한다.
        System.out.printf("%s, %s, %s, %s, %s\n", //
            rs.getString(1), // board_id
            rs.getString(2), // title
            rs.getString(3), // contents
            rs.getString(4), // created_date
            rs.getString(5)); // view_count

        // getString(컬럼번호):
        // => DBMS에 설정된 컬럼의 값을 문자열로 리턴한다.
        // => select 문에 나열한 컬럼의 순서를 지정한다.
        //    단 번호는 0부터가 아니라 1부터 지정한다.
        // => select 문에 wildcard(*)를 사용했다면,
        //    테이블을 정의할 때 선언한 컬럼의 순서이다.
      } else {
        System.out.println("서버에서 한 개의 레코드를 가져오지 못했다!");
      }
    }
  }
}

 

 

JDBC 프로그래밍 - DBMS에 SQL문 보내기 : getXxx()
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0321 {

  public static void main(String[] args) throws Exception {
    try (
        java.sql.Connection con = DriverManager.getConnection(
            "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        java.sql.Statement stmt = con.createStatement();
        java.sql.ResultSet rs = stmt.executeQuery(//
            "select * from x_board order by board_id desc");
        ) {

      boolean isReceived = rs.next();
      if (isReceived) {
        System.out.printf("%d, %s, %s, %s, %s, %d\n", 
            rs.getInt(1), // board_id
            rs.getString(2), // title
            rs.getString(3), // contents
            rs.getDate(4), // created_date
            rs.getTime(4), // created_date
            rs.getInt(5)); // view_count

        // getXxx(컬럼번호):
        // => DBMS에 설정된 컬럼의 타입에 따라 값을 변환해서 받고 싶다면,
        //    다음과 같이 해당 타입의 값을 리턴하는 getXxx()를 호출한다.
        // => int, number: getInt()
        // => char, varchar, text: getString()
        // => date, time, datetime: getDate(), getTime()
        // => float: getFloat()
        //

      } else {
        System.out.println("서버에서 한 개의 레코드를 가져오지 못했다!");
      }
    }
  }
}

 

 

JDBC 프로그래밍 - DBMS에 SQL문 보내기 : select
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0330 {

  public static void main(String[] args) throws Exception {
    try (
        java.sql.Connection con = DriverManager
        .getConnection("jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        java.sql.Statement stmt = con.createStatement();
        java.sql.ResultSet rs = stmt.executeQuery(//
            "select * from x_board order by board_id desc");
        ) {

      boolean isReceived = rs.next();

      if (isReceived) {
        System.out.printf("%d, %s, %s, %s, %d\n", 
            rs.getInt("board_id"), 
            rs.getString("title"), 
            rs.getString("contents"), 
            rs.getDate("created_date"), 
            rs.getInt("view_count")); 

        // getXxx(컬럼명):
        // => 컬럼의 번호를 지정하는 방식은 소스 코드를 읽을 때 매우 불편하다.
        // => 해당 번호가 어떤 컬럼을 가리키는지 알려면
        //    select 문을 살펴봐야 하는 번거로움이 있다.
        // => 그래서 실무에서는 가능한 번호 대신 컬럼의 이름을 사용한다.

      } else {
        System.out.println("서버에서 한 개의 레코드를 가져오지 못했다!");
      }
    }
  }
}

 

 

package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0340 {

  public static void main(String[] args) throws Exception {
    try (
        java.sql.Connection con = DriverManager.getConnection(
            "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        java.sql.Statement stmt = con.createStatement();
        java.sql.ResultSet rs = stmt.executeQuery(
            "select * from x_board order by board_id desc");
        ) {

      // 반복문을 사용하면 서버에서 여러 개의 데이터를 가져올 수 있다.
      // - next()는 서버에서 레코드 1개를 가져온다.
      while (rs.next()) {
        System.out.printf("%d, %s, %s, %s, %d\n", 
            rs.getInt("board_id"), 
            rs.getString("title"), 
            rs.getString("contents"), 
            rs.getDate("created_date"), 
            rs.getInt("view_count")); 
      }
    }
  }
}

 

 

package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0341 {

  public static void main(String[] args) throws Exception {
    try (
        java.sql.Connection con = DriverManager.getConnection(
            "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        java.sql.Statement stmt = con.createStatement();
        java.sql.ResultSet rs = stmt.executeQuery("select * from x_board order by board_id desc");

        ) {

      while (rs.next()) {
        // 컬럼 타입에 상관없이 getString()으로 값을 꺼낼 수 있다.
        System.out.printf("%s, %s, %s, %s, %s\n", //
            rs.getString("board_id"), //
            rs.getString("title"), //
            rs.getString("contents"), //
            rs.getString("created_date"), // 시간까지 꺼낸다.
            rs.getString("view_count")); //
      }
    }
  }
}

 

 

JDBC 프로그래밍 - DBMS에 SQL문 보내기 : update
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0350 {

  public static void main(String[] args) throws Exception {
    try (
        java.sql.Connection con = DriverManager.getConnection(
            "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        java.sql.Statement stmt = con.createStatement();
        ) {

      // executeUpdate()
      // => DBMS 서버에 update 문을 보낸다.
      // => 리턴 값: 변경된 레코드의 개수이다.
      int count = stmt.executeUpdate( 
          "update x_board set"
              + " view_count = view_count + 1"
              + " where board_id = 4");
      System.out.printf("%d 개 변경 성공!", count);
    }
  }
}

 

 

JDBC 프로그래밍 - DBMS에 SQL문 보내기 : delete
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0360 {

  public static void main(String[] args) throws Exception {
    try (
        java.sql.Connection con = DriverManager.getConnection(
            "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        java.sql.Statement stmt = con.createStatement();

        ) {

      // executeUpdate()
      // => DBMS 서버에 delete 문을 보낸다.
      // => 리턴 값: 삭제된 레코드의 개수이다.
      int count = stmt.executeUpdate(
          "delete from x_board where board_id = 7");
      System.out.printf("%d 개 삭제 성공!", count);
    }
  }
}

 

 

JDBC 프로그래밍 - DBMS에 SQL문 보내기 : delete, FK 가 참조하는 데이터 지우기
package com.eomcs.jdbc.ex1;

import java.sql.DriverManager;

public class Exam0361 {

  public static void main(String[] args) throws Exception {
    try (
        java.sql.Connection con = DriverManager.getConnection(
            "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        java.sql.Statement stmt = con.createStatement();

        ) {

      // 부모 테이블의 데이터를 지우려면,
      // 부모 테이블의 데이터를 참조하는 자식 테이블의 데이터를 먼저 지워야 한다.
      //
      // => 게시글을 참조하는 첨부 파일 데이터를 먼저 지운다.
      int count = stmt.executeUpdate(
          "delete from x_board_file where board_id = 1");
      System.out.printf("x_board_file 테이블 : %d 개 삭제 성공!\n", count);

      // => 부모 테이블의 데이터를 지운다.
      int count2 = stmt.executeUpdate(
          "delete from x_board where board_id = 1");
      System.out.printf("x_board 테이블 : %d 개 삭제 성공!\n", count2);
    }
  }
}

 

 

 

com/eomcs/jdbc/ex2

 

 

DAO와 서비스 객체 사이에서 데이터를 실어나르는 용도로 사용한다.
package com.eomcs.jdbc.ex2;

import java.io.Serializable;
import java.sql.Date;

// 외부 저장소로 객체를 내보낼 수 있도록 serial 기능을 활성화시킨다.
public class Board implements Serializable {
  private static final long serialVersionUID = 1L;

  // DB 테이블의 컬럼 값을 저장할 인스턴스 변수를 준비한다.
  // => 보통 컬럼이름은 DB 관례에 따라 약자로 기술한다.
  // => 그러나 자바에서는 자바의 관례에 따라 변수명을 만들라!
  //    DB 컬럼명과 같게 하지 말라!
  int no;
  String title;
  String content;
  Date registeredDate;
  int viewCount;

  // 개발하는 동안 객체의 값을 확인할 수 있도록 toString()을 오버라이딩 한다.
  @Override
  public String toString() {
    return "Board [no=" + no + ", title=" + title + ", content=" + content + ", registeredDate="
        + registeredDate + ", viewCount=" + viewCount + "]";
  }

  // 셋터와 겟터 생성
  public int getNo() {
    return no;
  }

  public void setNo(int no) {
    this.no = no;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getContent() {
    return content;
  }

  public void setContent(String content) {
    this.content = content;
  }

  public Date getRegisteredDate() {
    return registeredDate;
  }

  public void setRegisteredDate(Date registeredDate) {
    this.registeredDate = registeredDate;
  }

  public int getViewCount() {
    return viewCount;
  }

  public void setViewCount(int viewCount) {
    this.viewCount = viewCount;
  }

}

 

 

데이터를 처리하는 코드를 별도의 클래스로 캡슐화시킨다.
package com.eomcs.jdbc.ex2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class BoardDao {
  public int delete(int no) throws Exception {
    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement()) {

      // 첨부파일 삭제
      stmt.executeUpdate("delete from x_board_file where board_id = " + no);

      // 게시글 삭제
      return stmt.executeUpdate("delete from x_board where board_id=" + no);
    }
  }

  public List<Board> findAll() throws Exception {
    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("select * from x_board order by board_id desc")) {

      ArrayList<Board> list = new ArrayList<>();
      while (rs.next()) {
        Board board = new Board();
        board.setNo(rs.getInt("board_id"));
        board.setTitle(rs.getString("title"));
        board.setContent(rs.getString("contents"));
        board.setRegisteredDate(rs.getDate("created_date"));
        board.setViewCount(rs.getInt("view_count"));
        list.add(board);
      }
      return list;
    }
  }

  public int insert(Board board) throws Exception {
    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement();) {

      String sql = String.format(
          "insert into x_board(title,contents) values('%s','%s')", 
          board.getTitle(),
          board.getContent());

      return stmt.executeUpdate(sql);
    }
  }

  public int update(Board board) throws Exception {
    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement()) {

      String sql = String.format(
          "update x_board set title='%s', contents='%s' where board_id=%d", 
          board.getTitle(),
          board.getContent(),
          board.getNo());

      return stmt.executeUpdate(sql);
    }
  }

  public Board findBy(String no) throws Exception {
    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery("select * from x_board where board_id = " + no)) {

      if (rs.next()) {
        Board board = new Board();
        board.setNo(rs.getInt("board_id"));
        board.setTitle(rs.getString("title"));
        board.setContent(rs.getString("contents"));
        board.setRegisteredDate(rs.getDate("created_date"));
        board.setViewCount(rs.getInt("view_count"));
        return board;

      } else {
        return null;
      }
    }
  }
}

 

 

게시판 관리 - 등록
package com.eomcs.jdbc.ex2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Scanner;

// 다음과 같이 게시물을 등록하는 프로그램을 작성하라!
// ----------------------------
// 제목? aaa
// 내용? bbb
// 등록하시겠습니까?(Y/n) y
// 등록하였습니다.
// 등록하시겠습니까?(Y/n) n
// 등록을 취소 하였습니다.
// ----------------------------
public class Exam0110 {

  public static void main(String[] args) throws Exception {
    String title = null;
    String contents = null;

    try (Scanner keyScan = new Scanner(System.in)) {

      // 사용자로부터 제목, 내용을 입력 받는다.
      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();

      System.out.print("입력하시겠습니까?(Y/n) ");
      String input = keyScan.nextLine();

      if (!input.equalsIgnoreCase("y") && input.length() != 0) {
        System.out.println("등록을 취소 하였습니다.");
        return;
      }
    }

    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement();) {

      String sql = String.format(
          "insert into x_board(title,contents) values('%s','%s')",
          title, contents);
      int count = stmt.executeUpdate(sql);
      System.out.printf("%d 개 입력 성공!", count);
    }
  }
}

 

 

게시물 관리 - 목록
package com.eomcs.jdbc.ex2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

// 다음과 같이 게시물 목록을 출력하라!
// 게시물 번호를 내림차순으로 정렬하라.
// ----------------------------
// 번호, 제목, 등록일, 조회수
// 2, aaa, 2019-1-1, 2
// 1, bbb, 2018-12-31, 3
// ----------------------------
public class Exam0120 {

  public static void main(String[] args) throws Exception {
    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery(
            "select board_id, title, created_date, view_count from x_board order by board_id desc")) {

      System.out.println("번호, 제목, 등록일, 조회수");
      while (rs.next()) {
        // 레코드에서 컬럼 값을 꺼낼 때 컬럼 번호를 지정하는 것 보다
        // 컬럼의 이름을 지정하는 것이 유지보수에 더 좋다.
        //
        System.out.printf("%d, %s, %s, %d\n", //
            rs.getInt("board_id"),
            rs.getString("title"),
            rs.getDate("created_date"),
            rs.getInt("view_count"));
      }
    }
  }
}

 

 

게시물 관리 - 조회
package com.eomcs.jdbc.ex2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

// 다음과 같이 게시물을 조회하는 프로그램을 작성하라!
// ----------------------------
// 번호? 1
// 제목: aaa
// 내용: aaaaa
// 등록일: 2019-1-1
// 조회수: 2
//
// 번호? 100
// 해당 번호의 게시물이 존재하지 않습니다.
// ----------------------------
public class Exam0130 {

  public static void main(String[] args) throws Exception {
    String no = null;
    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();
    }

    try (Connection con = DriverManager.getConnection( 
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement();
        ResultSet rs = stmt.executeQuery( 
            "select * from x_board where board_id = " + no)) {

      if (rs.next()) {
        // 레코드에서 컬럼 값을 꺼낼 때 컬럼 번호를 지정하는 것 보다
        // 컬럼의 이름을 지정하는 것이 유지보수에 더 좋다.
        //
        System.out.printf("제목: %s\n", rs.getString("title"));
        System.out.printf("내용: %s\n", rs.getString("contents"));
        System.out.printf("등록일: %s\n", rs.getDate("created_date"));
        System.out.printf("조회수: %d\n", rs.getInt("view_count"));
      } else {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      }
    }
  }
}

 

 

게시판 관리 - 변경
package com.eomcs.jdbc.ex2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Scanner;

// 다음과 같이 게시물을 변경하는 프로그램을 작성하라!
// ----------------------------
// 번호? 1
// 제목? xxx
// 내용? xxxxx
// 변경하였습니다.
// (또는)
// 해당 번호의 게시물이 존재하지 않습니다.
// ----------------------------
public class Exam0140 {

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

    String no = null;
    String title = null;
    String contents = null;

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();

      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();
    }

    try (Connection con = DriverManager.getConnection( //
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement()) {

      // update 문장은 executeUpdate()를 사용하여 서버에 전달한다.
      String sql = String.format(
          "update x_board set title='%s',contents='%s' where board_id=%s",
          title, contents, no);
      int count = stmt.executeUpdate(sql);

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("변경하였습니다.");
      }
    }
  }
}

 

 

게시판 관리 - 삭제
package com.eomcs.jdbc.ex2;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Scanner;

// 다음과 같이 게시물을 삭제하는 프로그램을 작성하라!
// ----------------------------
// 번호? 1
// 삭제하였습니다.
// (또는)
// 해당 번호의 게시물이 존재하지 않습니다.
// ----------------------------
public class Exam0150 {

  public static void main(String[] args) throws Exception {
    String no = null;

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();
    }

    try (Connection con = DriverManager.getConnection( //
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement()) {

      // delete 문장은 executeUpdate()를 사용하여 서버에 전달한다.
      // => 게시글 첨부 파일 삭제
      //      stmt.executeUpdate(
      //          "delete from x_board_file where board_id = " + no);

      // => 게시글 삭제
      int count = stmt.executeUpdate(
          "delete from x_board where board_id = " + no);

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("삭제하였습니다.");
      }
    }
  }
}

 

 

게시판 관리 - JDBC 코드를 별도의 클래스로 캡슐화시킴. DAO 적용.
package com.eomcs.jdbc.ex2;

import java.util.Scanner;

public class Exam0210 {

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

    Board board = new Board();

    try (Scanner keyScan = new Scanner(System.in)) {

      // 사용자로부터 제목, 내용을 입력 받는다.
      System.out.print("제목? ");
      board.setTitle(keyScan.nextLine());

      System.out.print("내용? ");
      board.setContent(keyScan.nextLine());

      System.out.print("입력하시겠습니까?(Y/n) ");
      String input = keyScan.nextLine();

      if (!input.equalsIgnoreCase("y") && input.length() != 0) {
        System.out.println("등록을 취소 하였습니다.");
        return;
      }
    }

    try {
      BoardDao boardDao = new BoardDao();
      int count = boardDao.insert(board);
      System.out.printf("%d 개 입력 성공!", count);

      // 이렇게 DBMS 작업을 별도의 클래스로 분리하여 캡슐화하면
      // 데이터 처리를 요구하는 쪽에서는
      // 데이터의 구체적인 처리 방식을 몰라도 되기 때문에
      // 코드가 간결해진다.
      // 또한 데이터 처리 방식이 바뀌더라도 영향을 받지 않는다.
      //
      // [데이터처리를 사용하는 측]......[데이터를 처리하는 측(DAO)]
      // .........|.....................................|
      // .........|..생성...............................|
      // .........|------> [도메인 객체]................|
      // .........|.....................................|
      // .........|........메서드 호출..................|
      // .........|------------------------------------>|
      // .........|.....................................|
      //
      // 도메인 객체(예: Board)
      // => 두 객체 사이에 데이터를 실어 나르는 역할을 한다고 해서
      //    "DTO(Data Transfer Object)"라고도 부른다.
      // => 두 객체 사이에 전달되는 값을 표현한다고 해서
      //    "VO(Value Object)"라고도 부른다.
      //
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex2;

import java.util.List;

public class Exam0220 {

  public static void main(String[] args) throws Exception {
    try {
      BoardDao boardDao = new BoardDao();
      List<Board> list = boardDao.findAll();
      System.out.println("번호, 제목, 등록일, 조회수");
      for (Board b : list) {
        System.out.printf("%d, %s, %s, %s, %d\n", 
            b.getNo(), 
            b.getTitle(), 
            b.getContent(), 
            b.getRegisteredDate(), 
            b.getViewCount());
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex2;

import java.util.Scanner;

public class Exam0230 {

  public static void main(String[] args) throws Exception {
    String no = null;
    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();
    }

    try {
      BoardDao boardDao = new BoardDao();
      Board board = boardDao.findBy(no);

      if (board != null) {
        System.out.printf("제목: %s\n", board.getTitle());
        System.out.printf("내용: %s\n", board.getContent());
        System.out.printf("등록일: %s\n", board.getRegisteredDate());
        System.out.printf("조회수: %d\n", board.getViewCount());
      } else {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex2;

import java.util.Scanner;

public class Exam0240 {

  public static void main(String[] args) throws Exception {
    Board board = new Board();

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      board.setNo(Integer.parseInt(keyScan.nextLine()));

      System.out.print("제목? ");
      board.setTitle(keyScan.nextLine());

      System.out.print("내용? ");
      board.setContent(keyScan.nextLine());
    }

    try {
      BoardDao boardDao = new BoardDao();
      int count = boardDao.update(board);

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("변경하였습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex2;

import java.util.Scanner;

public class Exam0250 {

  public static void main(String[] args) throws Exception {
    int no = 0;

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = Integer.parseInt(keyScan.nextLine());
    }

    try {
      BoardDao boardDao = new BoardDao();
      int count = boardDao.delete(no);

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("삭제하였습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

 

com/eomcs/jdbc/ex3

 

 

Statement 와 SQL 삽입 공격
package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Scanner;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    String title = null;
    String contents = null;

    try (Scanner keyboard = new Scanner(System.in)) {
      System.out.print("제목? ");
      title = keyboard.nextLine();

      System.out.print("내용? ");
      contents = keyboard.nextLine();
    }

    try (Connection con = DriverManager.getConnection( //
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement()) {

      // SQL 삽입 공격
      // => 입력 문자열에 SQL 명령을 삽입하여 프로그램의 의도와 다르게 데이터를 조작하는 행위.
      // => 사용자가 입력한 값을 가지고 SQL 문장을 만들 때 이런 문제가 발생한다.
      // => 예를 들어 이 예제를 실행할 때 다음과 같이 입력해 보라!
      // 제목? aaaa
      // 내용? bbbb'), ('haha', 'hoho'), ('hehe', 'puhul
      //
      int count = stmt.executeUpdate( 
          "insert into x_board(title, contents) values('" + title + "','" + contents + "')");

      // 위에서 사용자가 입력한 값을 가지고 SQL 문장을 만들면 다음과 같다.
      //
      // insert into x_board(title, contents) values('aaaa','bbbb'), ('haha', 'hoho'), ('hehe', 'puhul')
      //

      System.out.println(count + " 개를 입력하였습니다.");
    }
  }
}

 

 

package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Scanner;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    String no = null;
    String title = null;
    String contents = null;

    try (Scanner keyboard = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyboard.nextLine();

      System.out.print("제목? ");
      title = keyboard.nextLine();

      System.out.print("내용? ");
      contents = keyboard.nextLine();
    }

    try (Connection con = DriverManager.getConnection( //
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        Statement stmt = con.createStatement()) {

      // SQL 삽입 공격
      // => 입력 문자열에 SQL 명령을 삽입하여 프로그램의 의도와 다르게 데이터를 조작하는 행위.
      // => 사용자가 입력한 값을 가지고 SQL 문장을 만들 때 이런 문제가 발생한다.
      // => 예를 들어 이 예제를 실행할 때 다음과 같이 입력해 보라!
      // 번호? 1
      // 제목? okok
      // 내용? test', view_count = 300, created_date = '2019-3-3
      //
      int count = stmt.executeUpdate( 
          "update x_board set title = '" + title + 
          "', contents = '" + contents + 
          "' where board_id = " + no);

      // 위에서 사용자가 입력한 값을 가지고 SQL 문장을 만들면 다음과 같다.
      //
      // update x_board set title = 'okok',
      // contents = 'test', view_count = 300, created_date = '2019-3-3'
      // where board_id = 1
      //

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("변경하였습니다.");
      }
    }
  }
}

 

 

PreparedStatement를 이용하여 SQL 삽입 공격 차단하기
package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Scanner;

public class Exam0210 {

  public static void main(String[] args) throws Exception {
    String title = null;
    String contents = null;

    try (Scanner keyboard = new Scanner(System.in)) {
      System.out.print("제목? ");
      title = keyboard.nextLine();

      System.out.print("내용? ");
      contents = keyboard.nextLine();
    }

    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        PreparedStatement stmt = con.prepareStatement(
            "insert into x_board(title,contents) values(?,?)")) {

      // SQL 삽입 공격
      // => 입력 문자열에 SQL 명령을 삽입하여 프로그램의 의도와 다르게 데이터를 조작하는 행위.
      // => 사용자가 입력한 값을 가지고 SQL 문장을 만들 때 이런 문제가 발생한다.
      // => 예를 들어 이 예제를 실행할 때 다음과 같이 입력해 보라!
      // 제목? aaaa
      // 내용? bbbb'), ('haha', 'hoho'), ('hehe', 'puhul
      //

      // 위에서 준비한 SQL 문에 값을 설정한다.
      // => ? : 값이 놓일 자리를 의미한다. 'in-parameter' 라 부른다.
      // => in-parameter 에 들어갈 값의 타입에 따라 적절한 setXxx() 메서드를 호출한다.
      //
      stmt.setString(1, title);
      stmt.setString(2, contents);

      // => 이미 SQL 을 준비한 상태이기 때문에 실행할 때는 SQL를 줄 필요가 없다.
      // => setXxx()로 설정된 값은 단순한 텍스트로 처리한 후
      //    SQL을 실행할 때 파라미터로 전달되기 때문에 
      //    SQL 삽입 공격이 불가능 하다. 
      int count = stmt.executeUpdate();

      System.out.println(count + " 개를 입력하였습니다.");
    }
  }
}

 

 

package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Scanner;

public class Exam0220 {

  public static void main(String[] args) throws Exception {
    String no = null;
    String title = null;
    String contents = null;

    try (Scanner keyboard = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyboard.nextLine();

      System.out.print("제목? ");
      title = keyboard.nextLine();

      System.out.print("내용? ");
      contents = keyboard.nextLine();
    }

    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");

        // PreparedStatement는 미리 SQL 문장을 준비하여 값을 삽입하는 기법이다.
        PreparedStatement stmt = con.prepareStatement(
            "update x_board set title = ?, contents = ? where board_id = ?")) {

      // SQL 문장을 준비할 때, 값이 들어 갈 자리에 ? 로 표시한다.
      // ? 를 "in-parameter"라 부른다.
      //
      // SQL을 서버에 전달하기 전에 in-parameter 자리에 값을 넣는다.
      // => PreparedStatement.setXxx(in-parameter 인덱스, 값);
      // - setXxx : 컬럼의 타입에 따라 setInt(), setString(), setDate() 등을 사용할 수 있다.
      // - in-parameter 인덱스
      //   - ? 문자가 등장하는 순서대로 1부터 번호를 부여한다.
      // - 값
      //   - SQL 문장에 삽입될 값이다.
      //   - 설정되는 값은 단순 텍스트로 간주되기 때문에
      //     작은 따옴표를 그냥 일반 문자로 취급한다.
      //     즉 'SQL 삽입 공격'이 100% 불가능하다.
      // => in-parameter 값을 설정할 때 순서대로 할 필요는 없다.
      //
      stmt.setString(1, title); // int 컬럼의 값을 setString() 으로 설정할 수 있다.
      stmt.setString(2, contents);
      stmt.setString(3, no);

      // PreparedStatement에서는 SQL 문을 서버에 보내기 위해
      // executeUpdate()를 호출할 때 파라미터로 전달하지 않는다.
      // 이미 객체를 생성할 때 SQL 문을 준비했기 때문이다.
      int count = stmt.executeUpdate();

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("변경하였습니다.");
      }
      // Statement vs PreparedStatement
      // 1) SQL 문장의 간결함
      // [Statement]
      // - 값을 가지고 문자열로 직접 SQL 문을 만들기 때문에 작성하거나 읽기 힘들다.
      // [PreparedStatement]
      // - SQL 문장과 값이 분리되어 있기 때문에 작성하거나 읽기 쉽다.
      //
      // 2) SQL 삽입 공격
      // [Statement]
      // - 사용자가 입력한 값을 가지고 SQL 문장을 만들기 때문에 해킹되기 쉽다.
      // [PreparedStatement]
      // - SQL 문장과 값이 분리되어 다뤄지기 때문에 해킹할 수 없다.
      //
      // 3) 바이너리 데이터 다루기
      // [Statement]
      // - 문자열로 SQL 문장을 만들기 때문에
      //   바이너리 타입의 컬럼 값을 설정할 수 없다.
      // [PreparedStatement]
      // - setXxx() 메서드를 호출하여 값을 설정하기 때문에
      //   바이너리 타입의 컬럼 값을 설정할 수 있다.
      //
      // 4) 실행 속도
      // [Statement]
      // - executeUpdate()를 실행할 때 SQL 문을 파라미터로 전달한다.
      // - 호출될 때마다 SQL 문법을 분석하기 때문에 반복 실행하는 경우
      //   SQL 문법도 반복 분석하므로 실행 속도가 느리다.
      // [PreparedStatement]
      // - 미리 SQL 문을 작성한 다음 DBMS 프로토콜에 맞게 파싱해 놓은 후,
      //   executeUpdate() 호출한다.
      // - 따라서 executeUpdate()를 호출할 때 마다 SQL 문법을
      //   분석하기 않으므로 반복해서 실행하는 경우, 
      //   Statement 보다 실행 속도가 빠르다.
      //
    }
  }
}

 

 

게시판 관리 - 등록 + PreparedStatement 사용
package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Scanner;

public class Exam0310 {

  public static void main(String[] args) throws Exception {
    String title = null;
    String contents = null;

    try (Scanner keyScan = new Scanner(System.in)) {

      // 사용자로부터 제목, 내용을 입력 받는다.
      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();

      System.out.print("입력하시겠습니까?(Y/n) ");
      String input = keyScan.nextLine();

      if (!input.equalsIgnoreCase("y") && input.length() != 0) {
        System.out.println("등록을 취소 하였습니다.");
        return;
      }
    }

    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");

        // 값이 들어갈 자리에 in-parameter(?)를 지정한다.
        // => 데이터 타입에 상관없이 ?를 넣는다.
        PreparedStatement stmt =
            con.prepareStatement("insert into x_board(title,contents) values(?,?)");) {

      // in-parameter에 값을 설정한다.
      // => 설정하는 순서는 상관없다. 하지만 유지보수를 위해 순서대로 나열하라!
      stmt.setString(1, title);
      stmt.setString(2, contents);

      // 실행할 때는 SQL문을 파라미터로 넘길 필요가 없다.
      int count = stmt.executeUpdate();
      System.out.printf("%d 개 입력 성공!", count);
    }
  }
}

 

 

게시물 관리 - 목록 + PreparedStatement
package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class Exam0320 {

  public static void main(String[] args) throws Exception {
    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        // 당장 select 할 때 파라미터 값을 넣지 않는다 하더라도,
        // 나중에 넣을 것을 대비해서 그냥 PreparedStatement를 사용하라!
        PreparedStatement stmt = con.prepareStatement(
            "select * from x_board order by board_id desc");
        ResultSet rs = stmt.executeQuery()) {

      System.out.println("번호, 제목, 등록일, 조회수");
      while (rs.next()) {
        System.out.printf("%d, %s, %s, %s, %d\n", //
            rs.getInt("board_id"), //
            rs.getString("title"), //
            rs.getString("contents"), //
            rs.getDate("created_date"), //
            rs.getInt("view_count"));
      }
    }
  }
}

 

 

게시물 관리 - 조회 + PreparedStatement 적용
package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;

public class Exam0330 {

  public static void main(String[] args) throws Exception {
    String no = null;
    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();
    }

    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        PreparedStatement stmt = con.prepareStatement(
            "select * from x_board where board_id = ?")) {

      stmt.setString(1, no);

      try (ResultSet rs = stmt.executeQuery()) {
        if (rs.next()) {
          System.out.printf("제목: %s\n", rs.getString("title"));
          System.out.printf("내용: %s\n", rs.getString("contents"));
          System.out.printf("등록일: %s\n", rs.getInt("board_id"));
          System.out.printf("조회수: %d\n", rs.getInt("view_count"));
        } else {
          System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
        }
      }
    }
  }
}

 

 

게시판 관리 - 변경 + PreparedStatement 적용
package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Scanner;

public class Exam0340 {

  public static void main(String[] args) throws Exception {
    String no = null;
    String title = null;
    String contents = null;

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();

      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();
    }

    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        PreparedStatement stmt = con.prepareStatement(
            "update x_board set title = ?, contents = ? where board_id = ?")) {

      stmt.setString(1, title);
      stmt.setString(2, contents);
      stmt.setString(3, no);
      stmt.executeUpdate();

      int count = stmt.executeUpdate();

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("변경하였습니다.");
      }
    }
  }
}

 

 

게시판 관리 - 삭제 + PreparedStatement 적용
package com.eomcs.jdbc.ex3;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Scanner;

public class Exam0350 {

  public static void main(String[] args) throws Exception {
    String no = null;

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();
    }

    try (Connection con = DriverManager.getConnection(
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");
        PreparedStatement stmt = con.prepareStatement(
            "delete from x_board where board_id=?")) {

      stmt.setString(1, no);
      int count = stmt.executeUpdate();

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("삭제하였습니다.");
      }
    }
  }
}

 

 

게시판 관리 - JDBC 코드를 별도의 클래스로 캡슐화시킴. DAO 적용.
package com.eomcs.jdbc.ex3;

import java.util.Scanner;

public class Exam0410 {

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

    Board board = new Board();

    try (Scanner keyScan = new Scanner(System.in)) {

      // 사용자로부터 제목, 내용을 입력 받는다.
      System.out.print("제목? ");
      board.setTitle(keyScan.nextLine());

      System.out.print("내용? ");
      board.setContent(keyScan.nextLine());

      System.out.print("입력하시겠습니까?(Y/n) ");
      String input = keyScan.nextLine();

      if (!input.equalsIgnoreCase("y") && input.length() != 0) {
        System.out.println("등록을 취소 하였습니다.");
        return;
      }
    }

    try {
      BoardDao boardDao = new BoardDao();
      int count = boardDao.insert(board);
      System.out.printf("%d 개 입력 성공!", count);

      // 이렇게 DBMS 작업을 별도의 클래스로 분리하여 캡슐화하면
      // 데이터 처리를 요구하는 쪽에서는
      // 데이터의 구체적인 처리 방식을 몰라도 되기 때문에
      // 코드가 간결해진다.
      // 또한 데이터 처리 방식이 바뀌더라도 영향을 받지 않는다.
      //
      // [데이터처리를 사용하는 측]......[데이터를 처리하는 측(DAO)]
      // .........|.....................................|
      // .........|..생성...............................|
      // .........|------> [도메인 객체]................|
      // .........|.....................................|
      // .........|........메서드 호출..................|
      // .........|------------------------------------>|
      // .........|.....................................|
      //
      // 도메인 객체(예: Board)
      // => 두 객체 사이에 데이터를 실어 나르는 역할을 한다고 해서
      // "DTO(Data Transfer Object)"라고도 부른다.
      // => 두 객체 사이에 전달되는 값을 표현한다고 해서
      // "VO(Value Object)"라고도 부른다.
      //
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex3;

import java.util.List;

public class Exam0420 {

  public static void main(String[] args) throws Exception {
    try {
      BoardDao boardDao = new BoardDao();
      List<Board> list = boardDao.findAll();
      System.out.println("번호, 제목, 등록일, 조회수");
      for (Board b : list) {
        System.out.printf("%d, %s, %s, %s, %d\n", //
            b.getNo(), //
            b.getTitle(), //
            b.getContent(), //
            b.getRegisteredDate(), //
            b.getViewCount());
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex3;

import java.util.Scanner;

public class Exam0430 {

  public static void main(String[] args) throws Exception {
    String no = null;
    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();
    }

    try {
      BoardDao boardDao = new BoardDao();
      Board board = boardDao.findBy(no);

      if (board != null) {
        System.out.printf("제목: %s\n", board.getTitle());
        System.out.printf("내용: %s\n", board.getContent());
        System.out.printf("등록일: %s\n", board.getRegisteredDate());
        System.out.printf("조회수: %d\n", board.getViewCount());
      } else {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex3;

import java.util.Scanner;

public class Exam0440 {

  public static void main(String[] args) throws Exception {
    Board board = new Board();

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      board.setNo(Integer.parseInt(keyScan.nextLine()));

      System.out.print("제목? ");
      board.setTitle(keyScan.nextLine());

      System.out.print("내용? ");
      board.setContent(keyScan.nextLine());
    }

    try {
      BoardDao boardDao = new BoardDao();
      int count = boardDao.update(board);

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("변경하였습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex3;

import java.util.Scanner;

public class Exam0450 {

  public static void main(String[] args) throws Exception {
    int no = 0;

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = Integer.parseInt(keyScan.nextLine());
    }

    try {
      BoardDao boardDao = new BoardDao();
      int count = boardDao.delete(no);

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("삭제하였습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

 

com/eomcs/jdbc/ex4

 

 

자식 테이블의 데이터를 함께 입력할 때 문제점
package com.eomcs.jdbc.ex4;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.Scanner;

public class Exam0110 {

  public static void main(String[] args) throws Exception {
    String title = null;
    String contents = null;
    ArrayList<String> files = new ArrayList<>();

    try (Scanner keyScan = new Scanner(System.in)) {

      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();

      // 사용자로부터 첨부파일 입력 받기
      while (true) {
        System.out.print("첨부파일:(완료는 그냥 엔터!) ");
        String filename = keyScan.nextLine();
        if (filename.length() == 0) {
          break;
        }
        files.add(filename);
      }
    }

    try (Connection con = DriverManager.getConnection( //
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");

        // 게시글 입력 처리 객체
        PreparedStatement boardStmt = con.prepareStatement(
            "insert into x_board(title,contents) values(?,?)");

        // 첨부파일 입력 처리 객체
        PreparedStatement fileStmt = con.prepareStatement(
            "insert into x_board_file(file_path,board_id) values(?,?)")) {

      // 게시글 입력
      boardStmt.setString(1, title);
      boardStmt.setString(2, contents);
      int count = boardStmt.executeUpdate();
      System.out.printf("%d 개 게시글 입력 성공!\n", count);

      // 첨부파일 입력
      int fileCount = 0;
      for (String filename : files) {
        fileStmt.setString(1, filename);
        fileStmt.setInt(2, /* 어? 앞에서 입력한 게시글의 번호가 뭐지? */ 0);
        // 첨부파일 테이블에 데이터를 입력하려면,
        // 게시글 테이블의 게시글 번호를 알아야 한다.
        // 문제는 바로 위에서 입력한 게시글의 PK 값이 자동 생성되는 컬럼이기 때문에
        // 입력한 후 그 PK 값이 뭔지 알 수가 없다는 것이다.
        // 그래서 첨부파일 테이블에 데이터를 입력할 수 없다!
        //
        // 해결책!
        // - 데이터를 입력할 때 자동 생성된 PK 값을 알 수 있다면
        //   이 문제를 해결할 수 있다.
        // - 다음 예제를 확인해보라!
        //
        fileStmt.executeUpdate();
        fileCount++;
      }
      System.out.printf("%d 개 첨부파일 입력 성공!", fileCount);
    }
  }
}

 

 

insert 한 후 auto increment PK 값 리턴 받기
package com.eomcs.jdbc.ex4;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

public class Exam0111 {

  public static void main(String[] args) throws Exception {
    String title = null;
    String contents = null;

    try (Scanner keyScan = new Scanner(System.in)) {

      // 사용자로부터 제목, 내용을 입력 받는다.
      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();
    }

    try (Connection con = DriverManager.getConnection( 
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");

        // 입력 후 PK 값을 리턴 받고 싶다면,
        // PreparedStatement 객체를 얻을 때 다음과 같은 옵션을 지정하라!
        // => prepareStatement(sql, 자동생성된 PK 값 리턴 여부)
        //
        PreparedStatement stmt = con.prepareStatement( 
            "insert into x_board(title,contents) values(?,?)", 
            Statement.RETURN_GENERATED_KEYS);) {

      stmt.setString(1, title);
      stmt.setString(2, contents);
      int count = stmt.executeUpdate();
      System.out.printf("%d 개 입력 성공!\n", count);

      // insert 수행 후 자동 생성된 PK 값은 따로 요구해야 한다.
      try (ResultSet rs = stmt.getGeneratedKeys()) {
        // insert를 한 개만 했기 때문에 PK도 한 개만 생성되었다.
        // 따라서 ResultSet에 대해 여러 번 반복을 할 필요가 없다.
        rs.next();

        // 자동 생성된 PK 값을 꺼낼 때는 컬럼 이름이나 PK 컬럼의 인덱스로 꺼낸다.
        //        int no = rs.getInt("board_id"); // MariaDB JDBC Driver에서는 오류 발생!
        int no2 = rs.getInt(1);
        System.out.printf("입력된 게시글 번호: %d\n", no2);
      }
    }
  }
}

 

 

auto_increment PK 값을 알아내어 자식 테이블의 데이터를 입력할 때 사용하기
package com.eomcs.jdbc.ex4;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Scanner;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    String title = null;
    String contents = null;
    ArrayList<String> files = new ArrayList<>();

    try (Scanner keyScan = new Scanner(System.in)) {

      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();

      while (true) {
        System.out.print("첨부파일:(완료는 그냥 엔터!) ");
        String filename = keyScan.nextLine();
        if (filename.length() == 0) {
          break;
        }
        files.add(filename);
      }
    }

    try (Connection con = DriverManager.getConnection( //
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");

        // => 게시글을 입력할 때 자동 생성된 PK 값을 받겠다고 설정한다.
        PreparedStatement boardStmt = con.prepareStatement(
            "insert into x_board(title,contents) values(?,?)",
            Statement.RETURN_GENERATED_KEYS);

        PreparedStatement fileStmt = con.prepareStatement(
            "insert into x_board_file(file_path,board_id) values(?,?)")) {

      // 게시글 입력
      boardStmt.setString(1, title);
      boardStmt.setString(2, contents);
      int count = boardStmt.executeUpdate();
      System.out.printf("%d 개 게시글 입력 성공!\n", count);

      // 위에서 입력한 게시글의 PK 값을 알아내기
      ResultSet keyRS = boardStmt.getGeneratedKeys();
      keyRS.next(); // PK가 들어있는 레코드를 한 개 가져온다.
      //      int boardId = keyRS.getInt("board_id"); // PK 값이 들어있는 레코드에서 컬럼 값을 꺼낸다. MariaDB에서 오류 발생!
      int boardId = keyRS.getInt(1); 

      // 첨부파일 입력
      int fileCount = 0;
      for (String filename : files) {
        fileStmt.setString(1, filename);

        // 위에서 게시글 입력 후에 자동 생성된 PK 값을 사용한다.
        fileStmt.setInt(2, boardId);

        fileStmt.executeUpdate();
        fileCount++;
      }
      System.out.printf("%d 개 첨부파일 입력 성공!\n", fileCount);
    }
  }
}

 

 

auto commit 의 문제점
package com.eomcs.jdbc.ex4;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Scanner;

public class Exam0210 {

  public static void main(String[] args) throws Exception {
    String title = null;
    String contents = null;
    ArrayList<String> files = new ArrayList<>();

    try (Scanner keyScan = new Scanner(System.in)) {

      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();

      while (true) {
        System.out.print("첨부파일:(완료는 그냥 엔터!) ");
        String filename = keyScan.nextLine();
        if (filename.length() == 0) {
          break;
        }
        files.add(filename);
      }
    }

    try (Connection con = DriverManager.getConnection( //
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");

        // => 게시글을 입력할 때 자동 생성된 PK 값을 받겠다고 설정한다.
        PreparedStatement boardStmt = con.prepareStatement(
            "insert into x_board(title,contents) values(?,?)",
            Statement.RETURN_GENERATED_KEYS);

        PreparedStatement fileStmt = con.prepareStatement(
            "insert into x_board_file(file_path,board_id) values(?,?)")) {

      // 게시글 입력
      boardStmt.setString(1, title);
      boardStmt.setString(2, contents);
      int count = boardStmt.executeUpdate();
      System.out.printf("%d 개 게시글 입력 성공!\n", count);

      // DriverManager가 리턴한 커넥션은
      // Auto Commit의 기본 상태가 true로 설정되어 있다.
      // Auto Commit?
      // => insert, update, delete을 실행한 후
      //    그 결과를 즉시 실제 테이블에 적용하는 것.

      // Auto commit의 문제점
      // - insert/update/delete 할 때 바로 실제 테이블에 적용하기 때문에
      //   다음에 수행하는 insert/update/delete 작업이 실패하더라도
      //   이전에 수행한 작업은 그대로 유효한 것이 문제다!
      // 왜?
      // - 여러 개의 insert/update/delete 작업이 한 작업 단위로
      //   묶이는 경우에는 이런 방식이 옳지 않다.
      // - 예를 들면, 제품을 주문하는 경우를 생각해보자.
      //   주문 정보를 주문 테이블에 입력한 후
      //   결제 정보를 결제 테이블에 입력할 때 실패한다면,
      //   이전에 입력한 주문 정보는 무효하게 된다.
      // - 이런 경우에는 결제 정보까지 완전하게 입력되어야만
      //   주문 정보도 유효한 것이 바람직하다.
      // - 물론 이어지는 작업에 상관없이 먼저 수행한 작업을
      //   실제 테이블에 적용해도 되는 경우에는
      //   무조건 실제 테이블에 적용하는 auto commit 이 맞다.
      //
      // 연속적으로 수행하는 여러 개 insert/update/delete 작업을
      // 한 단위의 작업으로 묶는 방법?
      // - 작업을 수행하기 전에 auto commit 을 false로 설정한다.
      // - 모든 작업이 끝났을 때 commit()을 요청한다.
      // - 중간에 한 작업이라도 실패한다면,
      //   rollback()을 요청하여 작업 전 상태(마지막 commit 상태)로 되돌린다.
      // - 여러 개의 작업을 한 단위로 묶은 것을
      //   "트랜잭션(transaction)" 이라 부른다.
      //
      // "트랜잭션"을 다룰 때 auto commit 을 수동 상태로 만든다.
      // => 여러 개의 작업을 한 단위로 다룰 때 auto commit 을 수동 상태로 만든다.

      ResultSet keyRS = boardStmt.getGeneratedKeys();
      keyRS.next(); // PK가 들어있는 레코드를 한 개 가져온다.
      int boardId = keyRS.getInt(1); // 레코드에서 컬럼 값을 꺼낸다.

      // 첨부파일 입력
      int fileCount = 0;
      for (String filename : files) {
        fileStmt.setString(1, filename);

        // 위에서 게시글 입력 후에 자동 생성된 PK 값을 사용한다.
        fileStmt.setInt(2, boardId);

        fileStmt.executeUpdate();
        fileCount++;
      }
      System.out.printf("%d 개 첨부파일 입력 성공!\n", fileCount);
    }
  }
}

 

 

트랜잭션 다루기 - commit & rollback
package com.eomcs.jdbc.ex4;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Scanner;

public class Exam0220 {

  public static void main(String[] args) {
    String title = null;
    String contents = null;
    ArrayList<String> files = new ArrayList<>();

    try (Scanner keyScan = new Scanner(System.in)) {

      System.out.print("제목? ");
      title = keyScan.nextLine();

      System.out.print("내용? ");
      contents = keyScan.nextLine();

      while (true) {
        System.out.print("첨부파일:(완료는 그냥 엔터!) ");
        String filename = keyScan.nextLine();
        if (filename.length() == 0) {
          break;
        }
        files.add(filename);
      }
    }

    try (Connection con = DriverManager.getConnection( //
        "jdbc:mariadb://localhost:3306/studydb?user=study&password=1111");

        // => 게시글을 입력할 때 자동 생성된 PK 값을 받겠다고 설정한다.
        PreparedStatement boardStmt = con.prepareStatement(
            "insert into x_board(title,contents) values(?,?)",
            Statement.RETURN_GENERATED_KEYS);

        PreparedStatement fileStmt = con.prepareStatement(
            "insert into x_board_file(file_path,board_id) values(?,?)")) {

      // 여러 개의 데이터 변경 작업을 한 단위로 묶어 수행해야 한다면,
      // commit 할 때까지 실제 테이블에 적용하지 않도록
      // auto commit을 취소하고 수동 커밋 상태로 만든다.
      //
      // 트랜잭션(transaction)?
      // => 여러 개의 데이터 변경 작업을 한 단위로 묶은 것.
      // => 한 단위로 묶인 모든 작업이 성공 했을 때 그 작업 결과를 저장한다.
      // => 묶인 작업 중에 한 개라도 실패하면 이전에 성공한 모든 작업을 취소한다.
      //
      // 여러 작업을 트랜잭션으로 묶는 방법?
      // => autocommit을 수동으로 전환한다.
      // => 모든 작업이 성공했을 때 저장한다. - commit
      // => 한 작업이라도 실패하면 기존에 작업한 결과를 취소한다. - rollback
      //
      // 1) 트랜잭션 시작 - 커넥션 객체의 오토커밋을 false로 지정한다.
      // 이후부터 이 커넥션으로 실행하는 모든 SQL은
      // commit을 요청하기 전에는 테이블에 그 결과를 적용하지 않고 
      // 임시 데이터베이스에 따로 보관한다.
      con.setAutoCommit(false);

      // 게시글 입력
      boardStmt.setString(1, title);
      boardStmt.setString(2, contents);
      int count = boardStmt.executeUpdate();
      System.out.printf("%d 개 게시글 입력 성공!\n", count);

      ResultSet keyRS = boardStmt.getGeneratedKeys();
      keyRS.next(); // PK가 들어있는 레코드를 한 개 가져온다.
      int boardId = keyRS.getInt(1); // 레코드에서 컬럼 값을 꺼낸다.

      // 첨부파일 입력
      int fileCount = 0;
      for (String filename : files) {
        fileStmt.setString(1, filename);

        // 위에서 게시글 입력 후에 자동 생성된 PK 값을 사용한다.
        fileStmt.setInt(2, boardId);

        fileStmt.executeUpdate();
        fileCount++;
      }
      System.out.printf("%d 개 첨부파일 입력 성공!\n", fileCount);

      // 자식 테이블의 데이터까지 정상적으로 입력했다면,
      // DBMS에게 작업 결과를 실제 테이블에 적용하라고 요청한다.
      con.commit();
      // 데이터를 변경하는 모든 작업은(insert|update|delete)
      // 클라이언트의 요청을 처리하는 스레드가 임시 데이터베이스에 따로 보관한다.
      // 클라이언트와의 연결이 끊어지면 스레드는 임시 데이터베이스에 보관된 데이터를 버린다.
      // 따라서 연결을 끊기 전에 작업한 내용을 적용하고 싶다면,
      // 반드시 commit을 요청해야 한다.
      // 클라이언트로부터 commit 요청이 들어오면 
      // 그 클라이언트와 연결된 스레드는 임시 데이터베이스에 보관된 데이터 변경 결과를 
      // 실제 테이블에 적용한다.

    } catch (Exception e) {
      System.out.println("게시글 입력 중 오류 발생!");

      // 만약에 입력 도중에 실패했다면,
      // 현재까지 작업한 결과를 모두 취소하라고 DBMS에게 통보한다.
      // => commit()을 호출하지 않고 커넥션 객체를 닫으면,
      //    DBMS는 그 커넥션을 통해 수행했던 모든 작업 결과를 취소한다.
      // => 따라서 따로 커넥션 객체에 대해 rollback() 을 호출할 필요는 없다.
      //
      // => 만약 커넥션을 공유하는 상황이라면,
      //    명시적으로 작업 취소(rollback)를 명령해야 한다.
      // => 왜냐하면 같은 커넥션으로 다른 작업을 처리하는 경우에
      //    이전에 수행한 작업이 취소되지 않고 남아 있어서
      //    새 작업에 영향을 주기 때문이다.
      // 결론,
      // => 예외가 발생하면 rollback()을 명시적으로 호출하라!!!!!!
    }
  }
}

 

 

 

com/eomcs/jdbc/ex5

 

 

DB 커넥션 객체를 관리하는 역할의 규칙 정의
// => 빌려주는 역할을 수행한다.
package com.eomcs.jdbc.ex5;

import java.sql.Connection;

public interface DataSource {
  Connection getConnection() throws Exception;
  void returnConnection(Connection con);
}

 

 

DB 커넥션 객체를 관리하는 역할
package com.eomcs.jdbc.ex5;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ArrayList;
import java.util.Properties;

public class DefaultDataSource implements DataSource {
  String driver;
  String jdbcUrl;
  String user;
  String password;

  ArrayList<Connection> conPool = new ArrayList<>();

  // 생성자를 호출할 때 DB 관련 정보를 주지 않는다면,
  // JVM 프로퍼티에서 찾는다.
  public DefaultDataSource() throws Exception {
    Properties props = new Properties();
    props.load(new FileInputStream("jdbc.properties"));
    this.driver = props.getProperty("jdbc.driver");
    this.jdbcUrl = props.getProperty("jdbc.url");
    this.user = props.getProperty("jdbc.username");
    this.password = props.getProperty("jdbc.password");

    // JDBC 드라이버 로딩 및 DriverManager에 등록
    Class.forName(driver); 
    // Driver 클래스가 로딩될 때 스스로 객체를 자동 생성하여 DriverManager에 등록한다.
  }


  public DefaultDataSource(String driver, String jdbcUrl, 
      String user, String password) throws Exception {
    this.driver = driver;
    this.jdbcUrl = jdbcUrl;
    this.user = user;
    this.password = password;

    // JDBC 드라이버 로딩 및 DriverManager에 등록
    Class.forName(driver); 
    // Driver 클래스가 로딩될 때 스스로 객체를 자동 생성하여 DriverManager에 등록한다. 
  }

  public Connection getConnection() throws Exception {
    if (conPool.size() == 0) {
      // 저장된 커넥션 객체가 없다면, 새로 생성한다.
      System.out.println("새 연결 객체를 만든다.");
      return new ConnectionProxy(
          this,
          DriverManager.getConnection(jdbcUrl, user, password));
    }

    Connection con = conPool.remove(0);
    if (con.isClosed() || // 보관소에서 꺼낸 커넥션 객체가 닫혀있거나,
        !con.isValid(1)) { // 그 연결이 유효하지 않다면, 
      System.out.println("새 연결 객체를 만든다.");
      return new ConnectionProxy(
          this,
          DriverManager.getConnection(jdbcUrl, user, password));
      // isValid(초)
      // 그 연결이 유효한지 검사하기 위해 DBMS에 간단한 메시지를 보낸다.
      // DBMS 서버에서 1초 이내에 응답이 온다면 유효한 것으로 판단한다.
    }

    System.out.println("기존 연결 객체를 사용한다.");
    return con;
  }

  public void returnConnection(Connection con) {
    conPool.add(con);
  }
}

 

 

실제 커넥션 객체를 대행하는 역할을 수행한다.
package com.eomcs.jdbc.ex5;

import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

// proxy를 만든 이유?
// => close()를 호출할 때 DB 연결을 끊는 대신,
//    DataSource에 커넥션을 반납하기 위해!
public class ConnectionProxy implements Connection {
  DataSource dataSource;
  Connection con;

  public ConnectionProxy(DataSource dataSource, Connection con) {
    this.dataSource = dataSource;
    this.con = con;
  }

  public <T> T unwrap(Class<T> iface) throws SQLException {
    return con.unwrap(iface);
  }

  public boolean isWrapperFor(Class<?> iface) throws SQLException {
    return con.isWrapperFor(iface);
  }

  public Statement createStatement() throws SQLException {
    return con.createStatement();
  }

  public PreparedStatement prepareStatement(String sql) throws SQLException {
    return con.prepareStatement(sql);
  }

  public CallableStatement prepareCall(String sql) throws SQLException {
    return con.prepareCall(sql);
  }

  public String nativeSQL(String sql) throws SQLException {
    return con.nativeSQL(sql);
  }

  public void setAutoCommit(boolean autoCommit) throws SQLException {
    con.setAutoCommit(autoCommit);
  }

  public boolean getAutoCommit() throws SQLException {
    return con.getAutoCommit();
  }

  public void commit() throws SQLException {
    con.commit();
  }

  public void rollback() throws SQLException {
    con.rollback();
  }

  public void close() throws SQLException {
    dataSource.returnConnection(this);
  }

  public boolean isClosed() throws SQLException {
    return con.isClosed();
  }

  public DatabaseMetaData getMetaData() throws SQLException {
    return con.getMetaData();
  }

  public void setReadOnly(boolean readOnly) throws SQLException {
    con.setReadOnly(readOnly);
  }

  public boolean isReadOnly() throws SQLException {
    return con.isReadOnly();
  }

  public void setCatalog(String catalog) throws SQLException {
    con.setCatalog(catalog);
  }

  public String getCatalog() throws SQLException {
    return con.getCatalog();
  }

  public void setTransactionIsolation(int level) throws SQLException {
    con.setTransactionIsolation(level);
  }

  public int getTransactionIsolation() throws SQLException {
    return con.getTransactionIsolation();
  }

  public SQLWarning getWarnings() throws SQLException {
    return con.getWarnings();
  }

  public void clearWarnings() throws SQLException {
    con.clearWarnings();
  }

  public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
    return con.createStatement(resultSetType, resultSetConcurrency);
  }

  public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
      throws SQLException {
    return con.prepareStatement(sql, resultSetType, resultSetConcurrency);
  }

  public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
    return con.prepareCall(sql, resultSetType, resultSetConcurrency);
  }

  public Map<String, Class<?>> getTypeMap() throws SQLException {
    return con.getTypeMap();
  }

  public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
    con.setTypeMap(map);
  }

  public void setHoldability(int holdability) throws SQLException {
    con.setHoldability(holdability);
  }

  public int getHoldability() throws SQLException {
    return con.getHoldability();
  }

  public Savepoint setSavepoint() throws SQLException {
    return con.setSavepoint();
  }

  public Savepoint setSavepoint(String name) throws SQLException {
    return con.setSavepoint(name);
  }

  public void rollback(Savepoint savepoint) throws SQLException {
    con.rollback(savepoint);
  }

  public void releaseSavepoint(Savepoint savepoint) throws SQLException {
    con.releaseSavepoint(savepoint);
  }

  public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
      throws SQLException {
    return con.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
  }

  public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
      int resultSetHoldability) throws SQLException {
    return con.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  }

  public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
      int resultSetHoldability) throws SQLException {
    return con.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
  }

  public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
    return con.prepareStatement(sql, autoGeneratedKeys);
  }

  public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
    return con.prepareStatement(sql, columnIndexes);
  }

  public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
    return con.prepareStatement(sql, columnNames);
  }

  public Clob createClob() throws SQLException {
    return con.createClob();
  }

  public Blob createBlob() throws SQLException {
    return con.createBlob();
  }

  public NClob createNClob() throws SQLException {
    return con.createNClob();
  }

  public SQLXML createSQLXML() throws SQLException {
    return con.createSQLXML();
  }

  public boolean isValid(int timeout) throws SQLException {
    return con.isValid(timeout);
  }

  public void setClientInfo(String name, String value) throws SQLClientInfoException {
    con.setClientInfo(name, value);
  }

  public void setClientInfo(Properties properties) throws SQLClientInfoException {
    con.setClientInfo(properties);
  }

  public String getClientInfo(String name) throws SQLException {
    return con.getClientInfo(name);
  }

  public Properties getClientInfo() throws SQLException {
    return con.getClientInfo();
  }

  public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
    return con.createArrayOf(typeName, elements);
  }

  public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
    return con.createStruct(typeName, attributes);
  }

  public void setSchema(String schema) throws SQLException {
    con.setSchema(schema);
  }

  public String getSchema() throws SQLException {
    return con.getSchema();
  }

  public void abort(Executor executor) throws SQLException {
    con.abort(executor);
  }

  public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
    con.setNetworkTimeout(executor, milliseconds);
  }

  public int getNetworkTimeout() throws SQLException {
    return con.getNetworkTimeout();
  }
}

 

 

게시판 관리 - JDBC 코드를 별도의 클래스로 캡슐화시킴. DAO 적용.
package com.eomcs.jdbc.ex5;

import java.util.Scanner;

public class Exam0110 {

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

    Board board = new Board();

    try (Scanner keyScan = new Scanner(System.in)) {

      // 사용자로부터 제목, 내용을 입력 받는다.
      System.out.print("제목? ");
      board.setTitle(keyScan.nextLine());

      System.out.print("내용? ");
      board.setContent(keyScan.nextLine());

      System.out.print("입력하시겠습니까?(Y/n) ");
      String input = keyScan.nextLine();

      if (!input.equalsIgnoreCase("y") && input.length() != 0) {
        System.out.println("등록을 취소 하였습니다.");
        return;
      }
    }

    try {
      DataSource dataSource = new DefaultDataSource();
      BoardDao boardDao = new BoardDao(dataSource);
      int count = boardDao.insert(board);
      System.out.printf("%d 개 입력 성공!", count);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex5;

import java.util.List;

public class Exam0120 {

  public static void main(String[] args) throws Exception {
    try {
      DataSource dataSource = new DefaultDataSource();
      BoardDao boardDao = new BoardDao(dataSource);
      List<Board> list = boardDao.findAll();
      System.out.println("번호, 제목, 등록일, 조회수");
      for (Board b : list) {
        System.out.printf("%d, %s, %s, %s, %d\n", //
            b.getNo(), //
            b.getTitle(), //
            b.getContent(), //
            b.getRegisteredDate(), //
            b.getViewCount());
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex5;

import java.util.Scanner;

public class Exam0130 {

  public static void main(String[] args) throws Exception {
    String no = null;
    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = keyScan.nextLine();
    }

    try {
      DataSource dataSource = new DefaultDataSource();
      BoardDao boardDao = new BoardDao(dataSource);
      Board board = boardDao.findBy(no);

      if (board != null) {
        System.out.printf("제목: %s\n", board.getTitle());
        System.out.printf("내용: %s\n", board.getContent());
        System.out.printf("등록일: %s\n", board.getRegisteredDate());
        System.out.printf("조회수: %d\n", board.getViewCount());
      } else {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex5;

import java.util.Scanner;

public class Exam0140 {

  public static void main(String[] args) throws Exception {
    Board board = new Board();

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      board.setNo(Integer.parseInt(keyScan.nextLine()));

      System.out.print("제목? ");
      board.setTitle(keyScan.nextLine());

      System.out.print("내용? ");
      board.setContent(keyScan.nextLine());
    }

    try {
      DataSource dataSource = new DefaultDataSource();
      BoardDao boardDao = new BoardDao(dataSource);
      int count = boardDao.update(board);

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("변경하였습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

 

 

package com.eomcs.jdbc.ex5;

import java.util.Scanner;

public class Exam0150 {

  public static void main(String[] args) throws Exception {
    int no = 0;

    try (Scanner keyScan = new Scanner(System.in)) {
      System.out.print("번호? ");
      no = Integer.parseInt(keyScan.nextLine());
    }

    try {
      DataSource dataSource = new DefaultDataSource();
      BoardDao boardDao = new BoardDao(dataSource);
      int count = boardDao.delete(no);

      if (count == 0) {
        System.out.println("해당 번호의 게시물이 존재하지 않습니다.");
      } else {
        System.out.println("삭제하였습니다.");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}