🐥

【初心者向け/ITスクール33日】JDBCを通してOracleDBMSを利用すする方法

2023/08/25に公開

はじめに

今日は、ITスクールに通った33日目の日、今日学んだ知識を記事にシェアしたいと思います。
本記事が、ITを勉強を始めた方々にもロードマップになればいいと思います。

33日目は、JavaでOracle DBMSに繋ぎ、EclipseでQueryを作成する時間を持ちました。
今までは、Oracle DBMSのSQLをSQL Developerを通して、作成しましたが、Eclipseを連携し、
Javaを通してOracle DBMSのデーターを扱うこともできました。
他の言語になっておりますが、これが可能になる理由はJDBCというDriverのおかげです。

JDBC

JDBDとはJava Database Connectivityの略語で、Oracleだけでなく、様々なDBMSをJavaで作成するようにConnectしてくれるAPI Libraryの一種です。そのため、.jar に存在しており、
普段、Instant Clientを設置する際に、SQL plus、Instant Client Basic、JDBCを一緒にダウンロードし、同じフォルダーで解凍します。

現在、DBMSは400種類もあり、各DBMSによりJDBCの設定方法も少しは違いがありますが、今日はOracleを中心にして紹介したいと思います。
まず、JDBCを利用するためには、対象プロジェクトのBuild pathをクリックし、libraryからinstant client 設置経路にあるojdbc.jarというライブらにを追加します。

まず Connection というjava.sql packageクラスをインスタンス化します。

それから、コネクトしたいサーバーのアドレスをアドレスを追加します。
下段のData Source Explore -> Oracle Server -> Properties->Driver Properties -> Connection URLからサーバーのURLをコピーし、Stringタイプ変数addressにURLを代入します。

最後に、以下のようにDriverMangerのstatic method getConncetionを呼び出し、
パラメーターとして、addressとInstant clientに使用したID,PWを入力すれば、
Connectionができます。

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

public class ConnectionMain {

	public static void main(String[] args) {
	Connection con = null;
	try {	
	
	String addr = "jdbc:oracle:thin:@localhost:1521:xe";	
	con = DriverManager.getConnection(addr, "rnjsgurah2", "1234");
	System.out.println("Connection Succeed");
		
	}catch(Exception e) {
		e.printStackTrace();
	}
	try {
		con.close(); //必ず閉めます。
	}catch(SQLException e) {
		e.printStackTrace();
	}
	
  }
}	

これにより、EclipseからJavaでQuery文を作成することができるようになりました。
このアドレスはこれから、繰り返して使いますので、テンプレートとしてクラス化します。
ResultSetというクラスは、後ほど説明します。

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

public class HyonDBManager {
	public static Connection connect() throws SQLException{
	String addr = "jdbc:oracle:thin:@localhost:1521:xe";	
	return DriverManager.getConnection(addr, "rnjsgurah2", "1234");
	}
	
public static void close(Connection con, PreparedStatement pstmt, ResultSet rs) {
	try {
	  rs.close();                  
	}catch(Exception e) {     
	}try {                           
		pstmt.close();
	}catch(Exception e) {	
	}try {
		con.close();
	}catch(Exception e) {
	   }
	}
}

CRUD

入力

これから、DMLを中心にしてCRUDの自習をやってみましょう。
CRDはほぼ同じロジックにあり、Rのみ前出したResultSetクラスが必要になります。

Connectが成功したという前提から CRDの方法 を説明します!

String sql ="insert into product values(product_seq.nextval,'테스트',10,10,3)";

Queryと同じように作成しますが、空白文字と文字例内に;を付けないことがポイントです!

コードではなく、Scannerを通して場合はどのようにすれば、いいでしょうか?

String name = sc. next
.
.
.
String sql ="insert into product values(product_seq.nextval," + name + ")"

このように、CBVを通して入れてみようとトライしましたが、できませんでした。
Scannerから入力した値を入れるためにはGenericタイプの一種である ワイルドカードタイプパラメータ(?) を活用します。まだ、どのようなタイプが入るかは分からない状況ですが、一度値が入ったらキャストがいらない長所があるタイプがGenericタイプの長所ですね!

String sql ="insert into product values(product_seq.nextval,?)"

処理

先ほど、OracleDBに入れたいQueryを作成し、Stringタイプ変数sqlに代入しました。
それなら、どうやってOracleDBに転送するのでしょうか?

その時は、PreparedStatement(準備された状態)というクラスのオブジェクトを活用します。
そして、PreparedStatementのクラス変数にConnectionのinstance method prepareStatement(String sql)を呼び出せば、準備は完了です。

_PreparedStatement(準備された状態)-> Prepare Statement(準備する)_になりますね!

PreparedStatement pstmt = null;
String sql ="insert into market "
    	 		+ "values(market_seq.nextval,"
    	 		+ "?,?,?,?)";
			
pstmt = con.prepareStatement(sql); 			

もうよい、たん!みたいな待機状態ですが、Updateをする前に
何か忘れたものはありませんか?!

sqlの?を処理する必要がありますね!

pstmt.setString(1, name);
pstmt.setString(2, location);
pstmt.setInt(3, space);
pstmt.setInt(4, park);

?を順番にScannerから代入したデータータイプをセッティングしましょう。

 int datacount = pstmt.executeUpdate();
    	 if(datacount==1) {
    		 System.out.println("Success");
    	 }
    	 
    	 pstmt.close();

OracleDBにString sqlの値(Query文)入れるためにUpdateをすると、OracleDBに反映されます。
ちなみに、updateはintをリターンしますが、反映されたレコードの数をリターンしますので、計画通りデーターが入ったかもチェックができます!

こちらが、コードになります。

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

public class InsertMain2 {
     public static void main(String[] args) {
    	 Connection con = null;
		 //연결
    	 try{
         String addr = "jdbc:oracle:thin:@localhost:1521:xe";    	 
    	 con = DriverManager.getConnection(addr,"rnjsgurah2","1234");
    	 
    	 //연결이 되면 마켓 정보들 입력 받기
    	 Scanner sc = new Scanner(System.in);
    	 System.out.print("마트 이름 : ");
    	 String name = sc.next();
    	 System.out.print("지점명 : ");
    	 String location = sc.next();
    	 System.out.print("몇 평 : ");
    	 int space = sc.nextInt();
    	 System.out.print("주자 가능 대수 : ");
    	 int park = sc.nextInt();
    	 sc.close();
    	 
    	 //SQL => market테이블에 넣을 것 
    	 PreparedStatement pstmt = null;
    	 String sql ="insert into market "
    	 		+ "values(market_seq.nextval,"
    	 		+ "?,?,?,?)";
    	 
    	 pstmt =con.prepareStatement(sql);
    	 //?에 값 채우기 : pstmt.setXXX(물음표번호, 값)
    	 // XXX :자료형, 물음표번호는 1부터 시작 
    	 pstmt.setString(1, name);
    	 pstmt.setString(2, location);
    	 pstmt.setInt(3, space);
    	 pstmt.setInt(4, park);
    	 
    	 //성공 메시지
    	 int datacount = pstmt.executeUpdate();
    	 if(datacount==1) {
    		 System.out.println("Success");
    	 }
    	 
    	 pstmt.close();
    	 
    	 }catch(Exception e) {
    		 e.printStackTrace();
    	 }
    	 try {
			con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

UPDATE
mport java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

public class UpdateMain {
	//매장명입력 => 그 단어를 포함하는 모든 매장의 상품을 20% 할인된 가격으로 바꾸기
	public static void main(String[] args) {
		Connection con = null;
		PreparedStatement pstmt = null;
	
	try {
		//연결
		String addr = "jdbc:oracle:thin:@localhost:1521:xe";
		con = DriverManager.getConnection(addr,"rnjsgurah2","1234");
		System.out.println("success");
		
		//입력
		Scanner k = new Scanner(System.in);
		System.out.print("매장명: ");
		String name = k.next();
		k.close();
		
		String sql ="update product set p_price=p_price*0.8 where p_m_no in"
				+ "(select m_no from market where m_name like '%'||?||'%')";
		
		
		//처리
		pstmt = con.prepareStatement(sql);
		pstmt.setString(1,name);	    
		if(pstmt.executeUpdate()>=1) {
			System.out.println("success");
		}		
	}catch(Exception e ) {
		e.printStackTrace();
	}finally {
		try {
			pstmt.close();
		}catch(SQLException e) {
			e.printStackTrace();
		}try {
			con.close();
		}catch(SQLException e) {
			e.printStackTrace();
		}
	}

	}//main()end
}//Class end
DELETE
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Scanner;

public class DeleteMain {
public static void main(String[] args) {
	//상품명 입력(Scanner) => 입력한 내용을 포함하는 상품명의 정보를 삭제
	Connection con = null;
	PreparedStatement pstmt = null;
	Scanner sc = new Scanner(System.in);
	try {
		//연결
		String addr = "jdbc:oracle:thin:@localhost:1521:xe";
		con = DriverManager.getConnection(addr,"rnjsgurah2","1234");
			
		//입력
		System.out.print("상품명 입력 : ");
		String name = sc.next();
		sc.close();
			
		//문제점 :  여기는 자바의 영역... % 주의! 
		// %를 문자로 만들어서 문자들을 연결시켜주는 파이프를 사용
		String sql = "delete from product "
					+ "where p_name like '%'||?||'%'";
			
		pstmt = con.prepareStatement(sql);
		pstmt.setString(1,name) ;
			
		//삭제
		if(pstmt.executeUpdate()>=1) {
			System.out.println("success");
		}	
		}catch(Exception e) {
			e.printStackTrace();
		}finally{
			try {
			pstmt.close();
			}catch(SQLException e){
				e.printStackTrace();
			}try {
				con.close();
			}catch(SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

出力

Readも場合、pstmt.executeUpdate()ではなく、pstmt.executeQuery()を利用します。
前出したexecuteUpdate()はintタイプをリターンしますが、executeQuery()はDBからもらった結果をリターンしますので、そのデーターを込めるタイプが必要になります。
そのクラスがResultSetです。

ResultSet rs = null
.
.
re = pstmt.executeQuery();

結果を出力したい場合は、ResultSetクラスのinstance method getXXX("Tableのcolumn name")を呼び出します。注意点として、"Tableのcolumn name"ではなく、indexをキーとして代入することもできますが、readabilityと他の人がコードを見ることまで想定すれば、お勧めはしてないようです。
また、出力はCollectionで勉強したnext()のようにwhile文を通し、empty➡falseになるまでループをします。

while (rs.next()) {
	System.out.println(rs.getString(2));  //p_name
	System.out.println(rs.getInt("p_weight"));
	System.out.println(rs.getInt("p_price"));
	System.out.println("---------------");
}	

Discussion