MySQL の BLOB (Binary Large Object) を使う (Java と Eclipse を利用)

概要

MySQL の利用において、BLOB(Binary Large Object)を扱う Java プログラムの実装方法を、サンプルコードとともに解説する。開発環境として Eclipse を使用する。

Java と SQL の連携には JDBC を使用する。この仕組みにより、Java プログラムから SQL クエリをデータベースへ送信し、実行結果を処理できる。両者の間のデータ交換は変数を介して行う。

Java コードに SQL クエリを組み込み、SQL の実行結果(複数レコードで構成される)をループ処理で Java の変数に順次格納する。核となる部分は次のとおりである。

ResultSet rs = execute("SELECT * FROM commodity");
DecimalFormat dformat = new DecimalFormat("#,###円");
while (rs.next()) {
    int t = rs.getInt("type");
    String n = rs.getString("name");
    int p = rs.getInt("price");
    System.out.println(t + " " + n + " " + dformat.format(p));
}

目次

【サイト内の関連ページ】

MySQL 活用ガイド

必要なソフトウェア環境

事前設定と環境構成

このページのプログラムは、以下の設定を前提とする。環境が異なる場合は、プログラムコードを適切に修正する。

データベース名、および MySQL アクセス用の一般ユーザアカウント(ユーザ名とパスワード)の設定は次のとおりである。

MySQL の利用における重要な設定項目は次のとおりである。

テスト用データベースの構築

テスト環境として、以下の SQL コマンドを実行し、BLOBtest テーブルを作成する。あわせて、後続の Java プログラムで更新する行(主キー bid の値が 1 の行)をあらかじめ挿入しておく。

CREATE TABLE BLOBtest (
    bid INTEGER PRIMARY KEY NOT NULL,
    bytes BLOB
);

INSERT INTO BLOBtest(bid) VALUES (1);

* SQL の実行には、Eclipse データツール・プラットフォームの活用を推奨する。

Eclipse における JDBC プログラム実装手順

Eclipse の事前設定とクラス定義の準備

Eclipse のプロジェクト構成を以下のように設定する。既存の同名プロジェクトがある場合は、プロジェクト名を適切に変更する。

  1. プロジェクトとパッケージの作成手順の詳細は、Eclipse における JDBC プログラミングガイドを参照のこと。
  2. JDBC の jar ファイルの追加を行う。

    MySQL Connector/J の jar ファイル(mysql-connector-j の jar)をプロジェクトのビルドパスに追加する。

    JDBC の jar ファイルが未導入の場合は、MySQL Connector/J のダウンロードガイドを参照して導入する。

クラス定義

クラス定義の実装手順を説明する。前提として、パッケージ hoge.hoge.com が作成されていることを確認する。

  1. エディタでクラス HelloWorld を定義する

    【実装の要点】

    • テーブル BLOBtest には、BLOB 型の bytes 属性と、主キーとなる bid 属性が定義されている。
    • Java の変数 bid と同じ値を持つ bid 行の bytes 属性へ、byte[] 型の変数 bytes の内容を設定するプログラムを実装する。
    • データベース名やユーザ名が異なる環境で実行する場合は、適切な値へ設定を変更する。
    • 既定では localhost への接続を前提とする。リモートデータベースへ接続する場合は、接続設定を適切に変更する。

    【プログラムの核となる処理】

    String updateSql = "UPDATE BLOBtest SET bytes = ? WHERE bid = ?";
    PreparedStatement updateStatement = conn.prepareStatement(updateSql);
    // 第1引数(bytes 列)に、バイト配列を入力ストリームとして設定
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    updateStatement.setBinaryStream(1, bais, bytes.length);
    // 第2引数(bid)に、主キー値を設定
    updateStatement.setInt(2, bid);
    // プリペアードステートメントの実行
    updateStatement.executeUpdate();
    bais.close();
    updateStatement.close();
    

    問い合わせ結果は変数 rs(ResultSet)に格納される。rs には複数のレコード(行)が含まれ、while (rs.next()) による反復処理で各行を順に処理する。各行の属性値は、getInt("属性名")getString("属性名") などで取り出す。

    package hoge.hoge.com;
    
    import java.io.ByteArrayInputStream;
    import java.sql.*;
    import java.text.DecimalFormat;
    import java.util.Properties;
    
    public class HelloWorld {
        // MySQL Connector/J のドライバクラス
        private static final String JDBCDriver = "com.mysql.cj.jdbc.Driver";
    
        // 下記の変数を環境に合わせて設定する
        private static final String DBNAME = "testdb"; // データベース名
        private static final String USER = "testuser"; // データベースのユーザ名
        private static final String PASS = "hoge$#34hoge5"; // データベースのパスワード
        private static final String DBURL = "jdbc:mysql://localhost/" + DBNAME;
    
        private static Statement stmt = null;
        private static Connection conn = null;
    
        public static void main(String[] args) throws SQLException {
            printTable();
            byte[] d = new byte[100];
            d[0] = 1;
            insertBLOBdata(1, d);
            printTable();
        }
    
        public static void insertBLOBdata(int bid, byte[] bytes) throws SQLException {
            connect(USER, PASS);
            String updateSql = "UPDATE BLOBtest SET bytes = ? WHERE bid = ?";
            PreparedStatement updateStatement = conn.prepareStatement(updateSql);
            // 第1引数(bytes 列)に、バイト配列を入力ストリームとして設定
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            updateStatement.setBinaryStream(1, bais, bytes.length);
            // 第2引数(bid)に、主キー値を設定
            updateStatement.setInt(2, bid);
            updateStatement.executeUpdate();
            bais.close();
            updateStatement.close();
            disconnect();
        }
    
        public static void printTable() throws SQLException {
            connect(USER, PASS);
            ResultSet rs = execute("SELECT * FROM BLOBtest");
            DecimalFormat dformat = new DecimalFormat("#,###");
            while (rs.next()) {
                int bid = rs.getInt("bid");
                byte[] bytes = rs.getBytes("bytes");
                System.out.print(dformat.format(bid) + ":");
                if (bytes == null) {
                    System.out.println("(null)");
                } else if (bytes.length == 0) {
                    System.out.println("(empty)");
                } else {
                    System.out.printf("(%1$2x)", bytes.length);
                    for (int i = 0; i < bytes.length; i++) {
                        System.out.printf("%1$02x ", bytes[i] & 0xff);
                        if ((i % 16) == 15) System.out.print("\n      ");
                    }
                    System.out.println();
                }
            }
            rs.close();
            disconnect();
        }
    
        // データベース接続
        public static void connect(String user, String pass) throws SQLException {
            Properties prop = new Properties();
            prop.put("user", user);
            prop.put("password", pass);
            conn = DriverManager.getConnection(DBURL, prop);
        }
    
        // データベース切断
        public static void disconnect() throws SQLException {
            conn.close();
        }
    
        // 問い合わせの実行
        public static ResultSet execute(String sql) throws SQLException {
            stmt = conn.createStatement();
            return stmt.executeQuery(sql);
        }
    }
    
  2. ソースを保存

    「ファイル」メニューの「保管」を選択するか、CTRL+S で保存する。保存すると自動的にコンパイルが実行される。コンパイル中にエラーや警告が発生した場合は、Eclipse の問題ビューに詳細が表示されるため確認する。

実行

  1. 実行対象クラスを選択し、右クリックする

    プロジェクト・エクスプローラーには、パッケージ名の配下にクラスファイル一覧が表示される。実行対象のクラスファイル(この場合は HelloWorld.java)を右クリックで選択する。

  2. 実行」 → 「Java アプリケーション」を選択する。キーボードショートカットとして Alt+Shift+X を押した後、J キーを押すことでも実行できる。
  3. 実行結果は次のように表示される。1 回目の printTable では bytes 列は空(null)であり、insertBLOBdata の後の 2 回目で、先頭 1 バイトが 01 のデータが表示される。

    1:(null)
    1:(64)01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
          00 00 00 00 ...
    
  4. 実行時に「接続できない」というエラーが発生した場合の対処:他のプロセスが接続を保持している可能性があるため、Eclipse を再起動してから再度実行する。解決しない場合は、DBNAME・USER・PASS・DBURL などの設定値を確認する。

(参考情報) Eclipse でデータベースの内容を確認するには、Eclipse のデータツール・プラットフォームの活用を推奨する。