개발자입니다
[SQL] 예제 소스 정리 - JDBC 본문
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();
}
}
}
'네이버클라우드 AIaaS 개발자 양성과정 1기 > DBMS, SQL, JDBC, Servlet' 카테고리의 다른 글
[비트캠프] 69일차(15주차1일) - JDBC: myapp-38 (0) | 2023.02.13 |
---|---|
[비트캠프] 68일차(14주차5일) - JDBC: myapp-36~37 (0) | 2023.02.10 |
[비트캠프] 67일차(14주차4일) - JDBC(JDBC API), myapp-35 (0) | 2023.02.09 |
[비트캠프] 66일차(14주차3일) - SQL(ER Diagram, JOIN) (0) | 2023.02.08 |
[SQL] 예제 소스 정리 - ORDER BY, JOIN, 서브 쿼리, GROUP BY, HAVING (0) | 2023.02.07 |