※当サイトの記事には、広告・プロモーションが含まれます。

Java JDBC(Java DataBase Connectivity)の構成など

Javaからデータベースへ接続するには、JDBCJava DataBase Conectivity)というAPIクラス(Java SEに元々入っているクラスライブラリ)と、別途でJDBCドライバをインストールする必要がありました。

f:id:ts0818:20170716133736p:plain

使用するデータベースがMySQLの場合だと、C:¥Program Files (x86MySQL¥Connector.J 5.1¥mysql-connector-java-5.1.41-bin.jarのファイルがJDBCドライバになります。

JDBCドライバAPIJDBCドライバについては、JDBCドライバの開発者が考慮することであるらしく、Javaでプログラムするときに考える必要はないようです。

JDBCドライバの種類

全部で4つのタイプが存在するようですが、専ら「タイプ4」 が利用されているようです。

  • タイプ1. JDBC-ODBCブリッジ
    • JDBC APIコールをODBC APIコールに変換します。ODBCドライバも必要になります。
  • タイプ2. ネイティブAPI
    • JDBC APIコールをデータベースのネイティブAPIに変換します。
  • タイプ3. ネットプロトコル
    • JDBC APIコールをDBMSに依存しないネットワークプロトコルに変換します。構成が複雑になるメリットがあり、あまり利用されていません。
  • タイプ4. ネイティブプロトコル
    • JDBC APIコールをDBMS固有のネットワークプロトコルに変換します。Javaで実装され、このドライバさえあればデータベースに接続できます。構成がシンプルになるため、現在の主流となっています。

タイプ1. JDBC-ODBCブリッジ

f:id:ts0818:20170716141050p:plain

 

タイプ2. ネイティブAPI

f:id:ts0818:20170716141047p:plain

 

タイプ3. ネットプロトコル

f:id:ts0818:20170716141043p:plain

 

タイプ4. ネイティブプロトコル

f:id:ts0818:20170716141040p:plain

タイプを確認してみます。

Eclipseの「パースペクティブ」を「DBviewer」 に切り替えて、「DBツリー・ビュー」の『DBViewerPlugin』の上で右クリックし、「登録(A)」を選択。

f:id:ts0818:20170716142637j:plain

「登録済みDriverから選択する(C)」を選択し、MySQLJDBCドライバを選択します。

f:id:ts0818:20170716142633j:plain

「次へ(N)>」を選択。

f:id:ts0818:20170716142629j:plain

JDBCタイプ(D):」に「Type4」「Type2」の2つが選択できることが分かりました。

f:id:ts0818:20170716142624j:plain

確認できたので「キャンセル」をクリックします。 「パースペクティブ」も「Java」に戻しておきます。

f:id:ts0818:20170716143555j:plain

f:id:ts0818:20170716143438j:plain

 

JavaプロジェクトでMySQL接続

Eclipseで、「ファイル」>「新規」 >「Javaプロジェクト」

f:id:ts0818:20170716144705j:plain

「プロジェクト名(P):」を入力し、「次へ(N)>」をクリック。

f:id:ts0818:20170716144702j:plain

「完了(F)」をクリック。

f:id:ts0818:20170716144658j:plain

続いて、作成したプロジェクトでJDBCドライバを利用できるようにします。

作成された「プロジェクト名」の上で右クリックし、「ビルド・パス(B)」>「ビルド・パスの構成(C)...」を選択。

f:id:ts0818:20170716144655j:plain

「ライブラリー(L)」タグを選択した状態で、「外部JARの追加(X)...」を選択し、MySQLJDBCドライバを選択します。

f:id:ts0818:20170716144652j:plain

JDBCドライバが追加されたら、「OK」を選択。 

f:id:ts0818:20170716145302j:plain

「パッケージ・エクスプローラー」に「参照ライブラリー」>「mysql-connector-java-5.1.41-bin.jar」が追加されていればOK。

f:id:ts0818:20170716145259j:plain

続いて「パッケージ」を作成。 

「ファイル」>「新規」>「パッケージ」を選択。

f:id:ts0818:20170716150229j:plain

 「名前(M):」を入力し「完了(F)」 を選択。

f:id:ts0818:20170716150222j:plain

続いて、「クラス」の作成。

作成したパッケージ上で右クリックし、「新規(W)」>「クラス」を選択。

f:id:ts0818:20170716150214j:plain

「名前(M):」を入力し、「どのメソッド・スタブを作成ますか?」で、「public static void main(String[] args)(V)」にチェックをし、「完了(F)」をクリック。

f:id:ts0818:20170716150210j:plain

SelectExsample.javaが作成されました。 

f:id:ts0818:20170716150206j:plain

データベースに接続していくためのコードを記述していきます。使用するデータベースは前回作成した、sampledbを使い、テーブルは、employeesを利用していきます。

package mysqlExample;

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

public class SelectExsample {

  public static void main(String[] args) {
    // データベース接続のための情報
    String url = "jdbc:mysql://localhost:3306/sampledb?useSSL=false";
    String user = "root";
    String password = "root";
    
    int rowCount = 0;
    // try-with-resouces文でデータベースに接続
    // SQL文を実行するためのStatementオブジェクトも生成
    try(Connection conn = DriverManager.getConnection(url, user, password);
      Statement stmt = conn.createStatement()  ) {

      // SQL文(SELECT文)を生成
      String sql = "SELECT * FROM employees";
      // SQL文を実行
      ResultSet res = stmt.executeQuery(sql);
      
      // テーブルの列数とか取得するためのオブジェクト
      ResultSetMetaData rsmd = res.getMetaData();
      // テーブルの列数
      int columnCount = rsmd.getColumnCount();
      // カラム名格納用
      String[] colName = new String[columnCount];
      
      // 行数を取得できるメソッドがないらしいので苦肉の策
      res.last();
      rowCount = res.getRow();
      res.beforeFirst();
      
      // 行数が取得できたので配列生成
      String[] dbObject = new String[rowCount];
      
      // SELECT文が実行されたか判定用の変数
      int resCount = 0;
      // 文字列連結用
      StringBuilder br = new StringBuilder();
      
      // 行数でループ
      while(res.next()) {
        // 列数だけループ
        for(int columnIndex = 1; columnIndex <= columnCount; columnIndex++){
          if(resCount == 0) {
            // カラム名
            colName[columnIndex -1] = rsmd.getColumnName(columnIndex);              
          }
          // データベースからの値を、String型にして文字列連結
          br.append(colName[columnIndex -1]);
          br.append("=");
          br.append(res.getObject(columnIndex).toString());
        
          // 行の最後の列かどうか
          if(columnIndex != columnCount) {
            br.append(", ");
            // 最後の列なら、改行
          } else {
            br.append("\n");
          }            
        }
        // データベースの1行分を格納
        dbObject[resCount] = br.toString();
        // StringBuilderオブジェクトの中身を空にする
        br.setLength(0);
        // ResultSetを次の行へ
        resCount++;
      }
    
      // SELECT文が実行されていれば、
      if(resCount != 0) {
        for(int i = 0; i < dbObject.length; i++) {
          System.out.print(dbObject[i]);
        }
      }

    } catch(SQLException e) {
      e.printStackTrace();
      System.out.println("データベース接続かSQLの実行で異常が発生しました。");
    } catch(Exception e) {

    }
  }
}
    

いまいちデータベースから取得した値の保存の仕方が分からない感じですが、Mapを使うやり方が上手くいかずでした。

⇩  下記サイトのようにスマートに記述したかったのですが

【JAVA】DB取得結果分をHashMapを使いListに格納する - 高卒プログラマの日常

演習課題も解き方がなかなか思いつかない今日この頃です。

package mysqlEmployees;

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


public class InsertEmployee {

  public static void main(String[] args) {
    //
    String url = "jdbc:mysql://localhost:3306/sampledb?useSSL=false";
    String user = "root";
    String password = "root";

    String result = "";
    String message = "";

    try(Connection conn = DriverManager.getConnection(url, user, password);
      Statement stmt = conn.createStatement();
      PreparedStatement pstmt = conn.prepareStatement("INSERT INTO employees VALUES(?, ?, ?, ? )");) {

      if(args.length != 4) {
        throw new ArrayIndexOutOfBoundsException();
      }
      // 入力値
      String input_code    = args[0];
      String input_name    = args[1];
      String input_age     = args[2];
      String input_section = args[3];

      ResultSet res = stmt.executeQuery("SELECT * FROM employees WHERE code = " + input_code);

      int recordCount = 0;
      // SELECTした結果をループ
      while(res.next()) {
        recordCount++;
      }

      // 既に従業員コードが存在する場合、
      if(recordCount != 0) {
      message = "を挿入できません。";
      // 従業員コードが存在しない場合、
      } else {
            message = "が挿入されました。";
            pstmt.setString(1, input_code);
            pstmt.setString(2, input_name);
            pstmt.setInt(3, Integer.parseInt(input_age));
            pstmt.setString(4, input_section);
            // prepareStatement(INSERT文)を実行
            int count = pstmt.executeUpdate();
      }

      // 処理結果
          result +=
              "CODE      :" + input_code + "\n" +
              "NAME      :" + input_name + "\n" +
              "AGE       :" + input_age  + "\n" +
              "SECTION   :" + input_section;

      System.out.print("処理結果: 以下のレコード" + message + "\n");
      System.out.println(result);

    } catch(ArrayIndexOutOfBoundsException e) {
        System.out.println("引数の数が違います。<従業員コード><名前><年齢><部署>です。");
    } catch (SQLException e) {
      //
    } catch (Exception e) {

    }
  }

}

package mysqlEmployees;

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

public class UpdateEmployee {

  public static void main(String[] args) {
    //
    String url = "jdbc:mysql://localhost:3306/sampledb?useSSL=false";
    String user = "root";
    String password = "root";

    String message = "";
    //
    try(Connection conn = DriverManager.getConnection(url, user, password);
      Statement stmt = conn.createStatement();
      PreparedStatement pstmt = conn.prepareStatement("UPDATE employees SET code = ?, section = ?;")) {

      // コマンドラインの引数チェック
      if(args.length != 2) {
        throw new ArrayIndexOutOfBoundsException();
      }
      String input_code    = args[0];
      String input_section = args[1];

      ResultSet res = stmt.executeQuery("SELECT code FROM employees WHERE code = " + input_code);
      int resCount = 0;
      while(res.next()) {
        resCount++;
      }

      // 従業員コードが存在した場合、
      if(resCount != 0) {
        pstmt.setString(1, input_code);
        pstmt.setString(2, input_section);
        message = "しました。";
        // prepareStatement(UPDATE文)を実行
        int count = pstmt.executeUpdate();

      // 従業員コードが存在しない場合
      } else {
        message = "できませんでした。";
      }

      System.out.println("次のレコードを更新" + message +
          "CODE:" + input_code + " ==> SECTION:" + input_section);


    } catch(ArrayIndexOutOfBoundsException e) {
      System.out.println("引数が違います。<従業員コード><部署コード>です。");

    } catch(SQLException e) {
      //
      System.out.println("prepareStatementの実行に失敗しました。");
      } catch(Exception e) {

    }

  }

}
package mysqlEmployees;

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

public class DeleteEmployee {

  public static void main(String[] args) {
    //
    String url ="jdbc:mysql://localhost:3306/sampledb?useSSL=false";
    String user = "root";
    String password = "root";

    String message = "";
    
    try(Connection conn = DriverManager.getConnection(url, user, password);
      Statement stmt = conn.createStatement();
      PreparedStatement pstmt = conn.prepareStatement("DELETE FROM employees WHERE code = ?")) {

      if(args.length != 1) {
      throw new ArrayIndexOutOfBoundsException();
      }
      String input_code = args[0];
      
      ResultSet res = stmt.executeQuery("SELECT code FROM employees WHERE code = " + input_code);
      int resCount = 0;
      while(res.next()) {
      resCount++;  
      }
      
      int count = 0;
      if(resCount != 0) {
        pstmt.setString(1, input_code);
        message = "しました。";
        count = pstmt.executeUpdate();
      } else {
      message = "できません。";
      }
      System.out.println("次のレコードを削除" + message + "\t CODE:" + input_code);  
          System.out.println(count + "件の変更");

    } catch(ArrayIndexOutOfBoundsException e) {
          System.out.println("引数に従業員コードを指定してください。");
    } catch(SQLException e) {
          System.out.println("データベース接続、またはprepareStatementの実行などに失敗しました。");
    } catch(Exception e) {
      
    }

  }

}

大人にも先生がいたって良い、って糸井重里さんが仰っていたような...。

同感です、館長。

今回はこのへんで。