JavaのDataSource、JDBCのDataSourceの例を示します。
JavaのDataSourceとJDBCのDataSourceプログラミングは、Javaプログラム内でデータベースを操作するための方法です。先ほども見てきたように、JDBCのDriverManagerを使用して、リレーショナルデータベースの接続を取得することができます。しかし、実際のプログラミングにおいては、接続以上の機能が必要です。
Javaのデータソース
ほとんどの場合、私たちは緩やかな連携性を求めています。これにより、データベースを簡単に切り替えることができ、トランザクション管理のためのコネクションプーリングや分散システムのサポートが可能になります。JDBCのDataSourceは、アプリケーション内でこれらの機能を必要とする場合に最適な方法です。JavaのDataSourceインターフェースは、javax.sqlパッケージに存在し、getConnection()とgetConnection(String str1, String str2)という2つのオーバーロードされたメソッドを宣言しています。
JDBCのデータソース
異なるデータベースベンダーは、DataSourceインターフェースの異なる種類の実装を提供する責任があります。たとえば、MySQL JDBCドライバはcom.mysql.jdbc.jdbc2.optional.MysqlDataSourceクラスでDataSourceインターフェースの基本的な実装を提供し、Oracleデータベースドライバはoracle.jdbc.pool.OracleDataSourceクラスで実装します。これらの実装クラスは、データベースサーバーの詳細とユーザーの認証情報を提供するためのメソッドを提供します。これらのJDBC DataSourceの実装クラスが提供する他の一般的な機能には、以下のものがあります。
- Caching of PreparedStatement for faster processing
- Connection timeout settings
- Logging features
- ResultSet maximum size threshold
JDBC データソースの例
シンプルなJDBCのデータソースの例プロジェクトを作成しましょう。MySQLとOracleのデータソースの基本的な実装クラスを使用してデータベースの接続方法を学びます。最終プロジェクトは以下の画像のようになります。
JavaのJDBCデータソース – データベースのセットアップ
例題プログラムに入る前に、データベースの設定とテーブル、サンプルデータが必要です。このチュートリアルではMySQLやOracleデータベースのインストールは範囲外なので、単にテーブルとサンプルデータのセットアップを行います。
--Create Employee table
CREATE TABLE `Employee` (
`empId` int(10) unsigned NOT NULL,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`empId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- insert some sample data
INSERT INTO `Employee` (`empId`, `name`)
VALUES
(1, 'Pankaj'),
(2, 'David');
commit;
CREATE TABLE "EMPLOYEE"
(
"EMPID" NUMBER NOT NULL ENABLE,
"NAME" VARCHAR2(10 BYTE) DEFAULT NULL,
PRIMARY KEY ("EMPID")
);
Insert into EMPLOYEE (EMPID,NAME) values (10,'Pankaj');
Insert into EMPLOYEE (EMPID,NAME) values (5,'Kumar');
Insert into EMPLOYEE (EMPID,NAME) values (1,'Pankaj');
commit;
さて、Javaプログラムに移りましょう。データベースの設定を疎結合にするため、プロパティファイルから読み込みます。db.propertiesファイルです。
#mysql DB properties
MYSQL_DB_DRIVER_CLASS=com.mysql.jdbc.Driver
MYSQL_DB_URL=jdbc:mysql://localhost:3306/UserDB
MYSQL_DB_USERNAME=scdev
MYSQL_DB_PASSWORD=scdev123
#Oracle DB Properties
ORACLE_DB_DRIVER_CLASS=oracle.jdbc.driver.OracleDriver
ORACLE_DB_URL=jdbc:oracle:thin:@localhost:1521:orcl
ORACLE_DB_USERNAME=hr
ORACLE_DB_PASSWORD=oracle
ローカルな設定と一致していることを確認してください。また、プロジェクトのビルドパスにMySQLとOracle DBのJDBC JARが含まれていることも確認してください。
Java JDBC データソース – MySQL、Oracle の例
MySQLまたはOracleのデータソースを取得するために使用できるファクトリークラスを書いてみましょう。
package com.scdev.jdbc.datasource;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import oracle.jdbc.pool.OracleDataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
public class MyDataSourceFactory {
public static DataSource getMySQLDataSource() {
Properties props = new Properties();
FileInputStream fis = null;
MysqlDataSource mysqlDS = null;
try {
fis = new FileInputStream("db.properties");
props.load(fis);
mysqlDS = new MysqlDataSource();
mysqlDS.setURL(props.getProperty("MYSQL_DB_URL"));
mysqlDS.setUser(props.getProperty("MYSQL_DB_USERNAME"));
mysqlDS.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));
} catch (IOException e) {
e.printStackTrace();
}
return mysqlDS;
}
public static DataSource getOracleDataSource(){
Properties props = new Properties();
FileInputStream fis = null;
OracleDataSource oracleDS = null;
try {
fis = new FileInputStream("db.properties");
props.load(fis);
oracleDS = new OracleDataSource();
oracleDS.setURL(props.getProperty("ORACLE_DB_URL"));
oracleDS.setUser(props.getProperty("ORACLE_DB_USERNAME"));
oracleDS.setPassword(props.getProperty("ORACLE_DB_PASSWORD"));
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return oracleDS;
}
}
OracleとMySQLのDataSourceの実装クラスは非常に似ていることに注意してください。これらのメソッドを使用して、いくつかのテストを実行するためのシンプルなテストプログラムを作成しましょう。
package com.scdev.jdbc.datasource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
public class DataSourceTest {
public static void main(String[] args) {
testDataSource("mysql");
System.out.println("**********");
testDataSource("oracle");
}
private static void testDataSource(String dbType) {
DataSource ds = null;
if("mysql".equals(dbType)){
ds = MyDataSourceFactory.getMySQLDataSource();
}else if("oracle".equals(dbType)){
ds = MyDataSourceFactory.getOracleDataSource();
}else{
System.out.println("invalid db type");
return;
}
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select empid, name from Employee");
while(rs.next()){
System.out.println("Employee ID="+rs.getInt("empid")+", Name="+rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
クライアントクラスがデータベース固有のクラスと完全に独立していることに注目してください。これにより、クライアントプログラムから基盤となる実装の詳細を隠すことができ、緩い結合と抽象化の利点を得ることができます。上記のテストプログラムを実行すると、以下の出力が得られます。
Employee ID=1, Name=Pankaj
Employee ID=2, Name=David
**********
Employee ID=10, Name=Pankaj
Employee ID=5, Name=Kumar
Employee ID=1, Name=Pankaj
Apache Commons DBCP の例
上記のJavaのDataSourceファクトリークラスを見ると、2つの主要な問題があります。
-
- MySQLとOracleのデータソースを作成するためのファクトリクラスメソッドは、それぞれのドライバAPIと強く結びついています。将来的にOracleデータベースのサポートを削除したり、他のデータベースのサポートを追加したりする場合、コードの変更が必要になります。
- MySQLとOracleのデータソースを取得するためのほとんどのコードは似ており、唯一の違いは使用している実装クラスです。
Apache Commons DBCP APIは、私たちのプログラムと異なるJDBCドライバーの間の抽象化レイヤーとして機能するJava DataSourceの実装を提供することで、これらの問題を解決するのに役立ちます。Apache DBCPライブラリはCommons Poolライブラリに依存しているため、画像に示すようにビルドパスに両方が含まれていることを確認してください。以下はBasicDataSourceを使用したDataSourceファクトリークラスの実装です。
package com.scdev.jdbc.datasource;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
public class DBCPDataSourceFactory {
public static DataSource getDataSource(String dbType){
Properties props = new Properties();
FileInputStream fis = null;
BasicDataSource ds = new BasicDataSource();
try {
fis = new FileInputStream("db.properties");
props.load(fis);
}catch(IOException e){
e.printStackTrace();
return null;
}
if("mysql".equals(dbType)){
ds.setDriverClassName(props.getProperty("MYSQL_DB_DRIVER_CLASS"));
ds.setUrl(props.getProperty("MYSQL_DB_URL"));
ds.setUsername(props.getProperty("MYSQL_DB_USERNAME"));
ds.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));
}else if("oracle".equals(dbType)){
ds.setDriverClassName(props.getProperty("ORACLE_DB_DRIVER_CLASS"));
ds.setUrl(props.getProperty("ORACLE_DB_URL"));
ds.setUsername(props.getProperty("ORACLE_DB_USERNAME"));
ds.setPassword(props.getProperty("ORACLE_DB_PASSWORD"));
}else{
return null;
}
return ds;
}
}
ユーザーの入力に応じて、MySQLまたはOracleのデータソースが作成されることがわかります。アプリケーションで1つのデータベースのみをサポートしている場合は、これらのロジックは必要ありません。プロパティを変更するだけで、データベースサーバーを切り替えることができます。Apache DBCPが抽象化を提供する鍵点は、setDriverClassName()メソッドです。ここには、上記のファクトリメソッドを使用して異なるタイプの接続を取得するクライアントプログラムがあります。
package com.scdev.jdbc.datasource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
public class ApacheCommonsDBCPTest {
public static void main(String[] args) {
testDBCPDataSource("mysql");
System.out.println("**********");
testDBCPDataSource("oracle");
}
private static void testDBCPDataSource(String dbType) {
DataSource ds = DBCPDataSourceFactory.getDataSource(dbType);
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
con = ds.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery("select empid, name from Employee");
while(rs.next()){
System.out.println("Employee ID="+rs.getInt("empid")+", Name="+rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
上記のプログラムを実行すると、出力は以前のプログラムと同じになります。JavaのJDBCデータソースと上記の使用方法を見ると、通常のドライバーマネージャーでも同じことができます。Javaデータソースの主な利点は、それがコンテキストとJNDI内で使用される場合です。簡単な設定で、コンテナ自体が維持するデータベース接続プールを作成することができます。ほとんどのサーブレットコンテナ(TomcatやJBossなど)は、独自のJavaデータソース実装を提供しており、簡単なXMLベースの設定を介して設定し、JNDIコンテキストルックアップを使用してJavaデータソースを取得して使用するだけです。これにより、接続プーリングや管理をアプリケーション側からサーバー側で行うことができるため、アプリケーションのビジネスロジックの記述により多くの時間を確保することができます。次のチュートリアルでは、Tomcatコンテナでデータソースを設定し、Webアプリケーションで使用する方法を学びます。