JAVA에서 Oracle DB 연동 및 사용 하는법
How to connect Oracle DB with JAVA?
오늘은 자바랑 오라클 데이터베이스를 연결하여 실제로 DB에 데이터를
INSERT, SELECT, DELETE, UPDATE 를 해보는 코드를 짜보도록 하겠습니다!
계획 ⇒
- 서점 데이터베이스를 쿼리문을 이용해 구축한다 (ONLY TABLE)
- 자바에서 DB를 연결하기 위한 ORACLE JDBC를 다운받는다.
- 자바에서 DB를 연결시켜주는 API를 찾아서 정리해놓는다 ⇒ Class, Connection, PreparedStatement, ResultSet
- 사전에 준비한 테이블을 참고하여 자바에서 쿼리문을 실행할 수 있게 만든다.
코딩 순서 ⇒
- DB를 연결시키기 위한 클래스를 생성한다.
- 사전에 필요한 변수들을 미리 선언해놓는다. (단 접근제한자는 protected로)
- INSERT, DELETE, UPDATE, SELECT 문을 실행하는 클래스를 각각 나눠서 생성한다.
- 각각의 클래스가 DB연결 클래스를 상속받는다 ( 코드 중복 최소화 )
- 각각의 클래스들이 서로 엉키지 않게 한번에 하나의 클래스를 완성하고 나서 다음 클래스를 만든다.
- try catch문을 미리 사전에 생성을 해서 작성하는 메소드 내용을 포함시킨다.
- 모든 클래스가 완성되면, 메인메소드가 있는 DEFAULT 클래스를 생성한다.
- INSERT, DELETE, UPDATE, SELECT
- 클래스의 객체를 생성하여 접근을 하고 메소드를 호출하여 실행한다.
일단 JDBC와 Bulid Path 는 설정을 다 했다고 치고 꼭 필요한 코드 작성부터 시작하겠습니다 🙂
- DBConnection (DB와 JAVA를 연결시켜주는 클래스 생성)
package book_table;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DBConnection { // DB를 자바에 연결시키기 위한 클래스 DBConnection
protected Connection conn = null;
protected PreparedStatement statement = null;
protected ResultSet select = null;
String query = null;
String url = "jdbc:oracle:thin:@localhost:1521:xe";
String username = "scott";
String password = "tiger";
// 필요한 변수에 대해서 미리 선언을 하고 넘어갑니다.
/*
* 일단 첫번째,
* Connection 클래스 객체 생성 : JDBC를 활용하여 JAVA와 DB를 연결시켜줍니다.
*
* 두번쨰,
* 쿼리문 작성시 데이터를 객체로 담아서 전달해주는 역할을 하는 PreaparedStatement 클래스 객체 생성
*
* 세번째,
* SELECT절을 쓰기 위해서 필요한 ResultSet 클래스 객체 생성;
*
* 모든 변수값은 null로 초기화를 시켜놓고 쿼리문 실행 클래스를 만들때 가져다가 쓸수 있게
* 만들어놓습니다.
*
*/
//1, 2. JDBC 드라이버를 CLASS로 만들어서 사용할 수 있게 해주는 CLASS API를 사용하여 생성을 합니다.
// Connection 클래스를 이용하여 생성한 객체로 DriverManager 메소드를 이용하여 DB와 연결을 시도합니다.
// 앞에서 만든 url, username, password을 이용하여 접근이 가능합니다.
public void DBstart() {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
} catch (SQLException e) {
e.printStackTrace();
}
}
//
public void DBstop() { // 만약 쿼리문을 정상적으로 다 실행을 했다면 사용하였던 클래스 객체들을 close 해줍니다.
try {
if(select != null) {
select.close();
}
if(statement != null) {
statement.close();
}
if(conn != null) {
conn.close();
}
}catch (Exception e) {
e.printStackTrace();
}
}
}
DBstart 메소드 안에 바로 앞에 Class.forname( )을 통하여 드라이버를 로딩해줍니다. 무엇보다 제일 먼저 실행이 되야 하기 때문입니다. 구현할 때 해당 경로에서 드라이버를 찾지 못하는 예외 발생을 대비해 try catch문을 사용합니다.
여기서 유의깊게 봐야하는 것은 바로
Connection 클래스
PreparedStatement 클래스
ResultSet 클래스
입니다.
Connection :
DriverManager.getConnection() 를 Connection 객체를 통해 호출하고 getConnection() 의 매개변수로
연결하고자 하는 DB의 url, user, password를 선언합니다.
그렇게 되면 DB와 JAVA의 연결을 구축하는 시스템은 끝입니다.
PreparedStatement :
데이터베이스 관리 시스템(DBMS)에서 동일하거나 비슷한 쿼리문을 높은 효율성으로 반복적으로 실행하기 위해 사용되는 기능을 말합니다.
보통 Statement 와 PreparedStatement 두개를 사용을 하는데,
Statement를 사용하면 매번 쿼리를 수행할 때마다 4단계를 거치게 되고(계속 단계를 거치면서 수행)
PreparedStatement는 처음 한 번만 세 단계를 거친 후 캐시에 담아 재사용을 한다는 것이다. 만약 동일한 쿼리를 반복적으로 수행한다면 PreparedStatment가 DB에 훨씬 적은 부하를 주며, 성능도 좋습니다.
그래서 저는 PreparedStatement 를 사용하였습니다.
실행할 SQL문을 변수에 저장하고 이를 PreparedStatement의 메서드를 통해 실행한다. 이때 SQL문이 SELECT⇒ executeQuery()
INSERT, UPDATE, DELETE 등 DCL 문이면
executeUpdate() 를 사용합니다.
ResultSet :
PreparedStatement를 사용하여 SQL문 실행시 출력되는 데이터베이스 결과 값을 나타내는 테이블
.next() 와 같은 메소드를 이용하여 객체에 담긴 데이터를 차례대로 가져올 수 있습니다.
한마디로 SELECT 문의 역할을 하는것이죠.
INSERT 클래스 구현 ⇒
package book_table;
import java.sql.SQLException;
import java.util.Scanner;
public class InsertBookInfo extends DBConnection {
public InsertBookInfo() {
// TODO Auto-generated constructor stub
}
public void insertInfo() {
Scanner sc = new Scanner(System.in);
//1. DB연결하기.
DBstart();
//2. 데이터 입력받기.
System.out.println("===== 추가하실 데이터를 입력해주세요 =====");
System.out.println("== 나중에 입력하실 데이터는 ENTER를 눌러주세요");
System.out.println();
System.out.print("책 고유코드 : ");
int isbn=sc.nextInt();
System.out.println();
sc.nextLine();
System.out.print("책 이름 : ");
String book_name =sc.nextLine();
System.out.println();
System.out.print("정가 : ");
int price = sc.nextInt(); // 각 컬럼에 해당되는 자료형 타입의 변수에 입력받은 데이터를 저장합니다.
System.out.println();
sc.nextLine();
System.out.print("장르 : ");
String genre = sc.nextLine();
System.out.println();
System.out.print("출판일 : ");
String first_pub = sc.nextLine();
System.out.println();
System.out.println("총 페이지 수 : ");
int pages = sc.nextInt();
System.out.println();
System.out.print("작가 코드 : ");
int author_code = sc.nextInt();
System.out.println();
System.out.print("출판사 코드 : ");
int pub_code = sc.nextInt();
System.out.println();
query = "INSERT INTO book_tbl(isbn,book_name,price,genre,first_pub, pages, author_code, pub_code) values(?,?,?,?,?,?,?,?)";
try { // INSERT INTO 쿼리문을 작성하여 데이터를 넣을 컬럼을 선택합니다.
statement = conn.prepareStatement(query);
// PreparedStatement 객체를 생성하여 connection 객체를 통하여 쿼리문을 입력 받고 실행시킵니다.
statement.setInt(1, isbn);
statement.setString(2, book_name);
statement.setInt(3, price);
statement.setString(4, genre); // 여기서 숫자는 위에 작성한 쿼리문의 테이블 컬럼 순서대로입니다.
statement.setString(5, first_pub);
statement.setInt(6, pages);
statement.setInt(7, author_code);
statement.setInt(8, pub_code);
int result = statement.executeUpdate(); // preparedStatement 객체는 성공하면 입력한 열만큼 숫자가 표현됩니
if(result>0) { // 만약 실패헀다면 -1을 반환합니다.
System.out.println("정상적으로 등록되었습니다.");
}else {
System.out.println("등록이 실패하였습니다. 데이터를 확인해주세요.");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
DBstop(); // 실행이 끝났다면 무조건 DB연결도 끝내줍니다.
}
}
}
DELETE 클래스 구현 ⇒
package book_table;
import java.sql.SQLException;
import java.util.Scanner;
public class DeleteBookInfo extends DBConnection{
public DeleteBookInfo() {
// TODO Auto-generated constructor stub
}
public void Delete() {
DBstart();
Scanner sc = new Scanner(System.in);
try {
System.out.println("삭제하실 책 고유코드를 입력해주세요 : ");
int isbn = sc.nextInt();
query = "DELETE FROM book_tbl WHERE isbn=?";
statement = conn.prepareStatement(query);
statement.setInt(1, isbn);
int result = statement.executeUpdate();
if(result>0) {
System.out.println("정상적으로 삭제 되었습니다.");
}else {
System.out.println("책 고유코드가 잘못입력되었습니다.");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
DBstop();
}
}
}
UPDATE 클래스 구현 ⇒
package book_table;
import java.util.Scanner;
public class UpdateBookInfo extends DBConnection {
public UpdateBookInfo() {
// TODO Auto-generated constructor stub
}
public void Update() {
DBstart();
Scanner sc = new Scanner(System.in);
SelectBookInfo book = new SelectBookInfo(); // 수정하기 편하게 현제 테이블의 데이터 목록을 보여줍니다.
book.select();
try {
System.out.print("수정할 책 고유 코드를 입력해주세요 : ");
int isbn = sc.nextInt();
System.out.println();
sc.nextLine();
System.out.print("수정할 이름을 입력해주세요 : ");
String book_name = sc.nextLine();
System.out.println();
System.out.print("수정할 가격을 입력해주세요 : ");
int price = sc.nextInt();
System.out.println();
query = "UPDATE book_tbl SET book_name=?, price=? WHERE isbn=?";
statement = conn.prepareStatement(query);
statement.setString(1, book_name);
statement.setInt(2, price);
statement.setInt(3, isbn);
int result = statement.executeUpdate();
if(result>0) {
System.out.println("정상적으로 수정되었습니다.");
}else {
System.out.println("수정실패 : 데이터를 확인해주세요.");
}
}catch(Exception e) {
e.printStackTrace();
}finally {
DBstop();
}
}
}
SELECT 클래스 구현 ⇒
package book_table;
import java.sql.SQLException;
public class SelectBookInfo extends DBConnection{
public SelectBookInfo() {
// TODO Auto-generated constructor stub
}
String a = "책 고유코드";
String b = "책 이름";
String c = "가격";
String d = "장르"; // 출력문에 컬럼명을 표시하기 위한 변수들.
String e = "출판일";
String f = "총 페이지";
String g = "작가 코드";
String h = "출판사 코드";
String i = "등록일";
public void select() {
DBstart();
try {
query = "SELECT isbn, book_name, price, genre, TO_CHAR(first_pub,'YYYY-MM-DD'), pages, author_code, pub_code, TO_CHAR(writedate,'YYYY-MM-DD') FROM book_tbl";
statement = conn.prepareStatement(query);
select = statement.executeQuery();
while(select.next()) {
int isbn=select.getInt(1);
String book_name = select.getString(2);
int price = select.getInt(3);
String genre = select.getString(4);
String first_pub = select.getString(5);
int pages = select.getInt(6);
int author_code = select.getInt(7);
int pub_code = select.getInt(8);
String writedate = select.getString(9);
System.out.printf("%15s %15s %15s %15s %15s %15s %15s %15s %15s \\n",a,b,c,d,e,f,g,h,i);
System.out.printf("%14d %18s %16d원 %12s %17s %14d %17d %15d %23s \\n",isbn,book_name,price,genre,first_pub,pages,author_code, pub_code, writedate);
System.out.println();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
DBstop();
}
}
}
Main Method for Working
import java.util.Scanner;
import book_table.DeleteBookInfo;
import book_table.InsertBookInfo;
import book_table.SelectBookInfo;
import book_table.UpdateBookInfo;
public class BookMain {
public BookMain() {
}
public static void StartDB_Book() {
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println();
System.out.println("== 안녕하세요 교보문고 DB 시스템입니다 ==");
System.out.println("== 1. 책 목록 확인하기 ==");
System.out.println("== 2. 책 정보 수정하기 ==");
System.out.println("== 3. 책 정보 추가하기 ==");
System.out.println("== 4. 책 정보 삭제하기 ==");
System.out.println("== 5. 종료 하기 ==");
System.out.println();
int menuNum = sc.nextInt();
switch(menuNum) {. // 메뉴 생성을 하고 switch case문으로 접근
case 1:
SelectBookInfo s = new SelectBookInfo();
s.select();
break;
case 2:
UpdateBookInfo u = new UpdateBookInfo();
u.Update();
break;
case 3:
InsertBookInfo i = new InsertBookInfo(); // 각각의 항목에 맞게 객체 생성 및 메소드 호출
i.insertInfo();
break;
case 4:
DeleteBookInfo d = new DeleteBookInfo();
d.Delete();
break;
case 5:
System.out.println("! 교보문고 DB 시스템을 종료합니다 !");
System.exit(0);
default :
System.out.println("== 메뉴 번호를 다시 입력하세요 ==");
break;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
StartDB_Book(); //실제로 실행을 하는 메인 메소드 영역
}
}
실행결과 : (사진이 삭제 됬네요 ㅠ...)
실행해본 결과 모든 쿼리문이 이상없이 잘 작동하고 있습니다.
위에 테이블에 있는 데이터들은 자바에서 INSERT 한 것입니다 🙂
다만 좀 아쉬웠던건 SELECT 문을 콘솔에서 좀 예쁘게 나타내고 싶었는데 자바에서는 가운데정렬이 없다는 사실을
뒤늦게 알고 난후 어떻게든 시도를 해봤지만 각각의 문자열의 길이가 다르다보니 해결하지 못하였습니다…
다음번에는 콘솔에서도 정갈된 모습으로 출력할 수 있게 연구해서 돌아오겠습니다 ! ㅠ…..