注: この章の内容は、Addison Wesley 社より Java シリーズの 1 巻として出版された『JDBCTM API Tutorial and Reference, Second Edition: Universal Data Access for the JavaTM 2 Platform』(ISBN 0-201-43328-1) に基づいています。
Connection
オブジェクトは、データベースとの接続を表します。 接続セッションには、実行される SQL 文とその接続を介して返された結果が入ります。 1 つのアプリケーションが 1 つのデータベースとの 1 つ以上の接続を持つことも、多くの異なるデータベースとの接続を持つこともできます。
Connection.getMetaData
メソッドを呼び出すと、Connection
オブジェクトのデータベースの情報を取得できます。このメソッドは、データベースのテーブル、サポートしている SQL 文法、ストアドプロシージャ、この接続の機能などの情報が含まれている DatabaseMetaData
オブジェクトを返します。
データベースとの接続を確立する従来の方法は、メソッド DriverManager.getConnection
を呼び出すことです。 このメソッドは、URL の入った文字列をパラメータとして受け取ります。 JDBC 管理レイヤと呼ばれる DriverManager
クラスは、URL が表すデータベースに接続できるドライバの検索を試みます。 DriverManager
クラスは登録済みの Driver
クラスのリストを持ち、メソッド getConnection
が呼び出されると、URL で指定されたデータベースに接続できるドライバが見つかるまで、リストの中の各ドライバを確認します。 Driver
のメソッドの connect
は、この URL を使用して実際に接続を確立します。
ユーザは、JDBC 管理レイヤをバイパスして、Driver
メソッドを直接呼び出すことができます。 これは、2 つのドライバがデータベースに接続でき、ユーザが特定のドライバを明示的に選択するというまれなケースでは役に立ちます。 しかし、通常は、DriverManager
クラスに接続の開始を処理させる方がはるかに簡単です。
以下のコードは、oboy
という ID と 12Java
というパスワードを使用して URL jdbc:odbc:wombat
にあるデータベースへの接続を開始する例を示します。
String url = "jdbc:odbc:wombat"; Connection con = DriverManager.getConnection(url, "oboy", "12Java");
JDBC 2.0 標準拡張機能 API では、接続を確立するために、DriverManager
の代替として DataSource
インタフェースが提供されています。 DataSource
クラスが適切に実装されている場合は、DataSource
オブジェクトを使用して、接続プールに関係する Connection
オブジェクトまたは分散トランザクションに関係する Connection
オブジェクト、あるいはその両方を作成できます。 詳細および DataSource
オブジェクトを使用して接続を作成するコード例については、「DataSource」の章を参照してください。この章では、接続を作成するのに、DataSource
オブジェクトの使用が良い代替方法になる理由についても説明します。
アプリケーションでは、DataSource
オブジェクトによって生成された Connection
オブジェクトは、基本的に DriverManager
によって生成された Connection
オブジェクトと同じ方法で使用されます。 ただし、いくつか相違点があります。 Connection
オブジェクトがプールされた接続の場合は、アプリケーションに finally
ブロックを組み込み、例外がスローされたときにも接続が閉じるようにする必要があります。 この結果、接続が有効な場合は、常に有効な接続プールに戻ります。
Connection
オブジェクトが分散トランザクションの一部である場合は、アプリケーションから Connection.commit
メソッドまたは Connection.rollback
メソッドを呼び出したり、接続の自動コミットモードをオンに設定したりしないでください。 トランザクションマネージャの分散トランザクション処理を妨害する可能性があります。
アプリケーションから DriverManager
を使用して Connection
オブジェクトを生成するときは、URL を DriverManager.getConnection
メソッドに渡す必要があります。URL に関しては混乱が生じることがよくあるので、まず URL の一般的な説明を手短かに行なってから、JDBC の URL について説明することにします。
URL (Uniform Resource Locator) は、インターネット上のリソースの位置を指定するために使用します。 これはアドレスと考えることができます。
URL の最初の部分で、情報にアクセスするために使用するプロトコルを指定します。 そのあとには常に、コロンが続きます。 よく使用されるプロトコルには、ファイル転送プロトコルを指定する ftp
とハイパーテキスト転送プロトコルを指定する http
があります。 プロトコルが file
の場合は、リソースはインターネット上ではなくローカルファイルシステムに格納されていることを示します。
ftp://javasoft.com/docs/JDK-1_apidocs.zip http://java.sun.com/products/JDK/CurrentRelease file:/home/haroldw/docs/tutorial.html
URL の最初のコロンのあとに続く残りの部分はすべて、データソースがどこにあるかを指定するものです。 プロトコルが file
の場合には、URL の残りの部分はファイルに対するパスになります。 プロトコルが ftp
と http
の場合には、URL の残りの部分はホストを指定するもので、より具体的なサイトに対するパスをオプションとして指定することもできます。 たとえば、次は、Java ソフトウェアのホームページに対する URL となります。 この URL はホストだけを指定します。
http://www.java.sun.com
このホームページから、多数のほかのホームページに行くことができます。 JDBC ホームページもその 1 つです。 JDBC ホームページの URL はより具体的で、次のようになっています。
http://www.java.sun.com/products/jdbc
JDBC の URL は、適切なドライバがデータソースを認識してそれとの接続を確立するように、データソースを識別する方法を提供します。 ドライバの作成者が、特定のドライバを識別する JDBC URL を何にするかを実際に決定します。 ユーザは、JDBC URL をどのような形式するかについては心配する必要はありません。 ユーザは、その使用しているドライバが供給する URL を単に使用するだけですみます。 JDBC の役割は、単にドライバの作成者が JDBC の URL を構成する際に使用する規則を推奨するだけです。
JDBC の URL は、さまざまな種類のドライバで使用するため、規則は当然、非常に柔軟です。 まず、この規則では、異なるドライバがデータベースを名付けるための異なる仕組みを使用できます。 たとえば、odbc
サブプロトコルを使用すると、URL に属性値を含めることができます (ただし、必要とするわけではない)。
第 2 に、JDBC の URL により、ドライバの作成者が必要な接続情報をその中に符号化できるようになります。 これにより、たとえば、アプレットがデータベースとやり取りを行おうとする際、ユーザがなんらの管理作業を行うことなくデータベース接続を開始することができます。
第 3 に、JDBC の URL では間接的なレベルが可能です。 すなわち、JDBC の URL が、論理ホスト、またはネットワークネーミングシステムによって実際の名前に動的に翻訳されるデータベース名を参照できるということです。 これにより、システム管理者は特定のホストを JDBC 名の一部として指定しなくてすみます。 ネットワークネームサービスにはいくつかの異なる種類 (たとえば、DNS、NIS、および DCE) があり、どれを使用するかについての制約はありません。
JDBC URL の標準構文は以下のとおりです。 その構文には 3 つの部分があり、コロンによって区切られています。
jdbc:<subprotocol>:<subname>
JDBC の URL の 3 つの部分は以下のように分割できます。
jdbc
はプロトコルです。 JDBC のURL のプロトコルは常に jdbc
です。
<subprotocol>
は通常、ドライバ名またはデータベース接続機構の名前で、1 つ以上のドライバによってサポートすることができます。 サブプロトコル名の顕著な例は、odbc
で、これは OBDC スタイルデータソース名を指定する URL のために予約されています。 たとえば、JDBC-ODBC ブリッジによってデータベースにアクセスするには、以下のように URL を使用します。
jdbc:odbc:fred
この例では、サブプロトコルは odbc
で、サブネームはローカルの ODBC データソース名 fred
です。
ネットワークネームサービスを使用したい (JDBC の URL 中のデータベース名を実際の名前にする必要をなくしたい) 場合には、ネームサービスはサブプロトコルにすることができます。 すなわち、たとえば、次のような URL を持っているものとします。
この URL は、「ローカルの DCE ネームサービスを使ってデータベース名jdbc:dcenaming:accounts-payable
accounts-payable
を解釈して、実際のデータベースへの接続に使用できる特定の名前に変換する」ことを指定しています。
<subname>
は、データソースを識別する方法です。 サブネームは、サブプロトコルによってさまざまに変化することができ、ドライバの作成者が選択する、サブサブネームを含むどのような内部構文でも持つことができます。 サブネームのポイントは、データソースを探すために十分な情報を提供することです。 上記の例では、ODBC が残りの情報を提供するので、fred
で十分です。 しかし、リモートサーバ上のデータソースでは、もっと多くの情報が要求されます。 たとえば、データソースがインターネット経由でアクセスされる場合は、ネットワークアドレスがサブネームの一部として JDBC の URL に含まれるべきであり、次の標準の URL 命名規則に従う必要があります。
//hostname:port/subsubname
dbnet
がインターネット上のホストに接続するためのプロトコルだとすると、JDBC の URL は以下のような形になります。
jdbc:dbnet://wombat:356/fred
サブプロトコル odbc
は、特別なケースです。 これは ODBC スタイルのデータソース名を指定する URL のために予約され、サブネーム (データソース名) のあとに任意の数の属性値を指定できるようにする特別な機能を備えています。 odbc サブプロトコルの完全な構文は以下のとおりです。
jdbc:odbc:<data-source-name>[;<attribute-name>=<attribute-value>]*
したがって、以下はすべて有効な jdbc:odbc 名です。
jdbc:odbc:qeor7 jdbc:odbc:wombat jdbc:odbc:wombat;CacheSize=20;ExtensionCase=LOWER jdbc:odbc:qeora;UID=kgh;PWD=fooey
ドライバ開発者は、JDBC の URL でサブプロトコルとして使用する名前を予約することができます。 DriverManager
クラスがこの名前をその登録済みドライバのリストに示すと、この名前で予約されたドライバがそれを認識して、それによって識別されるデータベースへの接続を確立します。 たとえば、「odbc」は JDBC-ODBC ブリッジのために予約されています。 また、仮に Miracle Corporation という企業が存在すれば、その Miracle DBMS に接続する JDBC ドライバのサブプロトコルとして「miracle」を登録して、ほかに誰もその名前を使えないようにします。
Java ソフトウェアは JDBC サブプロトコル名の非公式な登録機関として活動しています。 サブプロトコル名を登録するには、以下のアドレスに電子メールを送ります。
jdbc@eng.sun.com
いったん確立されると、接続は、SQL 文をその基盤となるデータベースに渡すために使用されます。 JDBC API は送付される SQL 文の種類について何の制約も課していないので、大きな柔軟性があり、データベース固有の文や SQL でない文でさえも使用することができます。 ただしユーザは、基盤となるデータベースが送付される SQL 文を処理できることを確認する責任があり、処理できない場合はその結果を甘受する必要があります。 たとえば、アプリケーションが、ストアドプロシージャをサポートしない DBMS にストアドプロシージャ呼び出しを送信しようとすると、正常には処理されず、例外処理を生成します。
JDBC API は、SQL 文をデータベースに送付するために、以下の 3 つのインタフェースを用意しており、Connection
インタフェースの対応するメソッドはそのインスタンスを生成します。 SQL 文およびそれを作成する Connection
メソッドを送信するインタフェースは、次のとおりです。
Statement
- Connection.createStatement
メソッドによって生成されます。Statement
オブジェクトは、パラメータを指定しないで SQL 文を送信するときに使用します。
PreparedStatement
- Connection.prepareStatement
メソッドによって生成されます。PreparedStatement
オブジェクトは、プリコンパイルされた SQL 文に使用します。SQL 文には、1 つ以上のパラメータを入力引数 (IN パラメータ) として指定できます。 PreparedStatement
は IN パラメータの値を設定するメソッドのグループを持ち、これらの IN パラメータは文が実行されるときにデータベースに送付されます。 PreparedStatement
のインスタンスは、Statement
を継承しているため Statement
メソッドを含みます。 PreparedStatement
オブジェクトはコンパイル済みで、将来の使用に備えて格納されているので、Statement
オブジェクトよりも効率的に使用できる能力を潜在的に備えています。 このため、PreparedStatement
オブジェクトは、パフォーマンスの向上が必要なときに、頻繁に実行される SQL 文に対して使用します。
CallableStatement
- Connection.prepareCall
メソッドによって生成されます。CallableStatement
オブジェクトは、SQL ストアドプロシージャ (一連の SQL 文で、関数を起動するのとまったく同様に、名前によって呼び出される) を実行するために使用します。 CallableStatement
オブジェクトは、IN パラメータを処理するためのメソッドを PreparedStatement
から継承し、さらに、OUT および INOUT パラメータを処理するためのメソッドが追加されています。
以下のリストは、異なるタイプの SQL 文を作成するために、どちらの Connection
メソッドが適切かを素早く判定する方法を示します。
createStatement
メソッド - 簡単な SQL 文 (パラメータなし) に対して使用される
prepareStatement
メソッド - 頻繁に実行される SQL 文に対して使用されるprepareCall
メソッド - ストアドプロシージャの呼び出しに対して使用される これらのメソッドでは、引数を指定しないため、デフォルトの ResultSet
オブジェクトを生成する文が作成されます。すなわち、スクロールおよび更新を行うことができない結果セットが生成されます。 JDBC 2.0 API を使用すると、スクロールまたは更新、あるいはその両方を行うことができる結果セットが生成される文を作成できます。 作成するには、新しい createStatement
、prepareStatement
、および prepareCall
メソッドを使用します。これらのメソッドには、結果セットの型および作成中の結果セットの並行処理のレベルを指定するために、追加のパラメータを指定できます。 ResultSet
オブジェクトの型および型を指定するための定数については、第 5 章「ResultSet」の 「結果セットの型」を参照してください。並行処理のレベルについては、「並行処理のタイプ」 を参照してください。 文を作成するときに新しい Connection
メソッドを使用して ResultSet
オブジェクトを生成する方法については、「タイプの異なる結果セットの作成」 を参照してください。
トランザクションは、実行され、完了され、その後にコミットもしくはロールバックする 1 つ以上の文で構成されます。 メソッド commit
または rollback
が呼び出された時点で、現在のトランザクションが終了し、別のトランザクションが開始します。
通常デフォルトでは、新しい Connection
オブジェクトは自動コミットモードになっています。 つまり、文が完了すると、メソッド commit
が自動的にその文で呼び出されます。 この場合、各文が個々にコミットされるので、1 つのトランザクションがただ 1 つの文によって構成されています。 自動コミットモードが無効になっていると、トランザクションはメソッド commit
または rollback
が明示的に呼び出されるまで終了しないので、1 つのトランザクションは commit
または rollback
メソッドの最後の呼び出し以降に実行されたすべての文を含みます。 この 2 番目の場合、トランザクションのすべての文はグループとしてコミットまたはロールバックされます。
トランザクションを開始するときに、明示的な呼び出しは必要ありません。自動コミットモードを無効にしたとき、または commit
または rollback
メソッドを呼び出した後に、暗黙に開始されます。 メソッド commit
は、SQL 文がデータベースに対して加えたあらゆる変更を永続化し、トランザクションによってかけられたロックをすべて解放します。 メソッド rollback
はそれらの変更を破棄します。
ほかの変更が同様に行われない限り、ある変更を有効にしたくない場合があります。 自動コミットを無効にし、両方の更新作業を 1 つのトランザクションにグループ化することによって実現できます。 両方の更新作業が正常に行われた場合に、commit
メソッドを呼び出し、両方の更新結果をデータベースに反映します。 1 つまたは両方が失敗した場合には、rollback
メソッドを呼び出し、更新作業が実行される前の値に戻します。
ほとんどの JDBC ドライバはトランザクションという概念をサポートします。 JDBC 準拠として指定されるためには、JDBC ドライバがトランザクションをサポートする必要があります。
JDBC 2.0 標準拡張機能 API では、Connection
オブジェクトを分散トランザクションの一部とすることができます。つまり 1 つのトランザクションが複数の DBMS サーバとかかわり合うことができます。 Connection
オブジェクトが分散トランザクションの一部である場合は、トランザクションマネージャが commit
または rollback
メソッドを呼び出すタイミングを決定します。 Connection
オブジェクトが分散トランザクションに関係している場合には、このため、アプリケーションから接続の開始または終了のタイミングに影響する処理を行わないでください。
Connection
オブジェクトを分散トランザクションに関係させるには、中間層のサーバの分散トランザクションインフラストラクチャと共に動作するように実装された、DataSource
オブジェクトを使用して Connection
オブジェクトを生成する必要があります。 DriverManager
によって生成された Connection
オブジェクトと異なり、DetaSource
オブジェクトのようなオブジェクトによって生成された Connection
オブジェクトは、自動コミットモードがデフォルトで無効になります。 一方、DataSource
オブジェクトの標準的な実装で生成される Connection
オブジェクトは、DriverManager
クラスによって生成される Connection
オブジェクトと完全に同じになります。
DBMS がトランザクション処理をサポートする場合、DBMS には、2 つのトランザクションが 1 つのデータベース上で同時に稼動しているときに生じ得る、潜在的な競合を管理する方法がいくつかあります。 ユーザは、潜在的な競合を解決するのに、DBMS がどの程度の注意を払う必要があるかを示すトランザクションの遮断レベルを指定することができます。 たとえば、あるトランザクションが値を変更し、変更がコミットまたはロールバックされる前に、2 番目のトランザクションがその値を読み取るとどうなるでしょうか。 最初のトランザクションがロールバックした場合、2 番目のトランザクションが読み取った、変更された値が無効だということが許容されるのでしょうか。 JDBC ユーザは、以下のコードを使用して (con は現在の接続)、コミットされる前に値を読めるように (汚れた値の読み取り) 指示することができます。
con.setTransactionIsolation(TRANSACTION_READ_UNCOMMITTED);
トランザクションの遮断レベルが高くなればなるほど、競合を避けるための注意がより多く払われます。 Connection
インタフェースは、トランザクションがまったくサポートされない最低レベルから、1 つのトランザクションがデータベース上で操作している間に、そのトランザクションが読み取っているデータに対して、ほかのトランザクションが変更を行わないという最高レベルまで、5 段階のレベルを定義します。 上記の例で使用された TRANSACTION_READ_UNCOMMITTED
のレベルは、最低レベルの 1 つ上です。 通常、遮断のレベルが高くなると、アプリケーションを実行する速度は低下します (ロッキングによるオーバーヘッドが増大し、ユーザ間の同時使用が低減するため)。 どの遮断レベルを使用するかを決定するときは、開発者はパフォーマンス上のニーズとデータの一貫性について、ニーズのバランスを取る必要があります。 もちろん、実際にサポートされるレベルは、基盤の DBMS の能力に依存します。
Connection
オブジェクトが新たに生成されると、そのトランザクションの遮断レベルは、ドライバによりますが、通常の場合には基盤のデータソースのデフォルト値になります。 ユーザはメソッド setIsolationLevel
を呼び出して、トランザクションの遮断レベルを変更し、その接続セッションの残りに対しては新しいレベルを有効にできます。 1 つのトランザクションについてだけトランザクションの遮断レベルを変更するには、そのトランザクション内の文を実行する前に遮断レベルを設定する必要があります。そして、トランザクションが終了したあとにそれをリセットします。 トランザクションの最中のトランザクションの遮断レベル変更はお勧めできません。commit
メソッドへの即時呼び出しのきっかけとなり、その時点までに行われたすべての変更がデータベースに反映されてしまいます。
作成した接続および文が必要なくなった時点で、明示的にクローズすることをお勧めします。
Java プログラミング言語でコードを記述し、外部リソースを使用していない場合は、メモリ管理について心配する必要はありません。 もはや使われないオブジェクトは、ガベージコレクタによって自動的に削除され、使用していたメモリは解放されます。 メモリが不足してくると、破棄されたオブジェクトが現在閉めているメモリをすばやい再利用として使えるようにしてリサイクルします。
ただし、アプリケーションによって外部リソースが使用されている場合、つまり JDBC API を使用して DBMS にアクセスしている場合は、ガベージコレクタではそれらのリソースの状態を認識することはできません。 破棄されたオブジェクトのリサイクルは依然として行われますが、Java ヒープに空きメモリが多く存在しているときは、少量の Java のガベージが大量の高価なデータベースリソースをオープンしたままにしているにもかかわらず、ガベージコレクトがたまにしか行われません。 したがって、必要がなくなったらできるだけ早く明示的にすべての接続を Connection.close
でクローズし、すべての文を Statement.close
でクローズし、それによってできるだけ早く DBMS のリソースを解放することをお勧めします。 ある DBMS と他のそれとでは違いがあるので、このことは、異なる複数の DBMS を使う予定のアプリケーションに特に当てはまります。
Connection.isClosed
メソッドは、Connection.close
が呼び出されたあとに呼び出されたときだけ、true
を返すということが保証されています。 このため、接続が有効かどうかを調べるのには、このメソッドは当てになりません。 代わりに、典型的な JDBC クライアントでは、JDBC の操作を試みたときにスローされる例外をキャッチすることで、接続が無効になっていることを判断できます。
SQL の構造化型および DISTINCT
型は、SQL3 の新しいデータ型です。これらは、ユーザ定義の型 (UDT) であり、Java プログラミング言語のクラスにカスタムマッピングできます。 SQL3 のすべてのデータ型と同様に、標準的なマッピングを持っていますが、カスタムマッピングも作成できます。 個々の UDT にカスタムマッピングが存在するかどうかは、java.util.Map
オブジェクト内で宣言されています。この Map
オブジェクトは、接続に関連付けられるか、メソッドに渡されます。
Map
オブジェクトにエントリを追加することによってカスタムマッピングを宣言します。 このエントリには、(1) マッピングされようとしている UDT の名前、および (2) UDT がマッピングしようとしている Java プログラミング言語の中のクラスの Class
オブジェクトを含める必要があります。 そのクラスはそれ自身で特有のマッピングを含むようになります。なお、このクラスは、SQLData
インタフェースも実装していなければなりません。
カスタムマッピングをサポートしている JDBC 2.0 ドライバによって生成された個々の Connection
は、カスタムマッピングを追加するための空の型マップが組み込まれます。 この型マップは、java.util.Map
インタフェースのインスタンスです。これは Java 2 プラットフォームの新しい機能で、java.util.Dictionary
を置き換えます。 カスタムマップのエントリをこの型マップに追加するまでの間は、STRUCT
および DISTINCT
値のすべての操作には、標準マッピングが使用されます (STRUCT
値の場合は Struct
インタフェース、DISTINCT
値の場合は基盤となる型)。
次のコードでは、con に関連付けられた型マップが取り出され、新しいエントリが con に追加されます。ここで、con は Connection
オブジェクト、ADDRESSES
は SQL 構造化型です。 型マップが変更された後に、con の新しい型マップとして設定しています。
java.util.Map map = con.getTypeMap(); map.put("SchemaName.ADDRESSES", Class.forName("Addresses")); con.setTypeMap();
Map
オブジェクトの map は、con に関連付けられた型マップで、このコードの実行後には少なくとも、1 つ (マッピングがすでに追加されている場合は複数) のカスタムマッピングが含まれています。 (多くの場合、クラスを生成するツールを使用して) Addresses
クラスを作成しておきます。 SQLData
インタフェースを実装していないクラスを提供するのは誤りです。 Addresses
クラスには、SQLData
が実装されており、ADDRESSES
の各属性に対応するフィールドが存在します。ADDRESSES
型の値が Java プログラミング言語のメソッドで操作されると、デフォルトで Addresses
クラスのインスタンスにマッピングされます。 別の型のマップが明示的にメソッドに渡されない場合は、接続に関連付けられている型マップが、デフォルトの型マップになります。
UDT の名前は、完全に修飾された名前でなければなりません。 一部の DBMS では、catalogName.schemaName.UDTName
の形式が使用されます。 しかし、多くの DBMS では、この形式は使用されていません。たとえば、カタログ名を含めずにスキーマ名が使用されます。 各 DBMS に適した形式を使用してください。 DatabaseMetaData
の getCatalogs
、getCatalogTerm
、getCatalogSeparator
、getSchemas
、および getSchemaTerm
メソッドを使用すると、DBMS のカタログ名、スキーマ名、カタログとして好ましい語句、およびカタログ名とテーブル名の間に使用されている区切り文字に関する情報を取得できます。
既存の型マップを修正する代わりに、アプリケーションで別の型マップに置き換えることができます。 次のコードに示すように、Connection
の setTypeMap
メソッドを使用します。 新しい型マップを作成し、その型マップに 2 つのエントリ (それぞれは、SQL UDT 名およびその型の値のマッピング先のクラスを持つ) を追加します。次に、Connection
の con に関連付けられた型マップとして新しい型マップをインストールします。
java.util.Map newConnectionMap = new java.util.HashTable(); newConnectionMap.put( "SchemaName.UDTName1", Class.forName("className1")); newConnectionMap.put( "SchemaName.UDTName2", Class.forName("className2")); con.setTypeMap(newConnectionMap);
これで、Connection
オブジェクトの con にもともと関連付けられていた型マップは、Map
オブジェクトの newConnectionMap に置き換わります。 newConnectionMap は、次に置き換えられるまで、カスタム型マップとして使用されます。この例では、新しい型マップを作成するときに、HashTable
クラスのデフォルトのコンストラクタが使用されています。 このクラスは、Java 2 プラットフォーム API で提供されている java.util.Map
の実装の 1 つです。その他の実装を使用することもできます。
前述のいくつかの例では、接続に関連付けられた型マップが、追加のマッピングを組み込むように変更されたり、まったく異なる型マップとして設定されました。 いずれの場合も、JDBC の型と Java プログラミング言語の型をカスタムマッピングするという点では、接続の型マップがデフォルト値になります。 次の例では、別の型マップを使うメソッドを提供することによって、接続の型マップを置き換える方法を示します。
メソッドの実装に UDT のカスタムマッピングを含めるかもしれない場合には、型マップを指定するメソッドと指定しないメソッドの 2 つのバージョンを用意します。 型マップをメソッドに渡した場合には、その型マップが、接続に関連付けられた型マップの代わりに使用されます。 たとえば、Array
の getArray
および getResultSet
メソッドには、型マップを指定するメソッドと指定しないメソッドがあります。 型マップがメソッドに渡された場合は、その型マップを使用して配列要素がマッピングされます。型マップが指定されていない場合は、接続に関連付けられた型マップがメソッドで使用されます。
メソッドに型マップを渡すと、同じユーザ定義の型の値に別のマッピングを設定できます。 たとえば、2 つのアプリケーションが同じ接続を使用し、同じ列の値を操作している場合、一方は、接続に関連付けられた型マップを使用し、他方は適切なメソッドに引数として渡した別の型のマップを使用することができます。
次のコードでは、新しい型マップを作成し、Array
の getArray
メソッドにパラメータとして渡しています。
java.util.Map arrayMap = new java.util.HashTable(); arrayMap.put("SchemaName.DIMENSIONS", Class.forName("Dimensions")); Dimensions [] d = (Dimensions [])array.getArray(arrayMap);
2 行目で、新しい型マップ arrayMap に、完全に修飾された SQL 構造化型の名前 (SchemaName.DIMENSIONS
) および Java クラスオブジェクト (Class.forName("Dimensions")
) のエントリが与えられています。 この結果、Java の Dimensions
型と SQL の DIMENSIONS
型の間にマッピングが確立されます。 3 行目では、arrayMap が型マップとして指定され、この Array
オブジェクトの内容のマッピングに使用されます。基本型は、SchemaName.DIMENSIONS
です。
getArray
メソッドでは、array
で指定された SQL3 ARRAY
値の要素が生成されます。このとき、各要素は、arrayMap で指定されているマッピングに応じてマッピングされます。 つまり、各 DIMENSIONS
値の属性を Dimensions
オブジェクトのフィールドにマッピングすることによって、Schema.DIMENSIONS
型の値である各要素が、Dimensions
クラスのインスタンスに変換されます。 配列の基になっている型が arrayMap で命名されている UDT 名と一致しない場合は、ドライバによって、配列の要素が標準的なマッピングに応じて変換されます。 また、getArray
メソッドに型マップが指定されていない場合は、ドライバでは、接続の型マップで指定されているマッピングが使用されます。 その型マップに Schema.DIMENSIONS
のエントリが存在しない場合は、ドライバでは標準的なマッピングが代わりに使用されます。