アプリケーションからの データベースアクセス

アプリケーションからの
データベースアクセス
講師: 大川 昌弘
[email protected]
更新日: 2014/12/07
1
データベースアクセス形態
典型的な例
Web
ブラウザ
データベース
クライアント
アプリケーション
Web
アプリケーション
サーバー
データベース
2
データベース
クライアントアプリケーション
各データベース製品が
独自のAPIを提供
標準インターフェースに
合わせたAPIを提供
データベース
クライアント
アプリケーション
データベース
クライアント
アプリケーション
データベース
アクセス
API
標準インターフェース
データベース
データベース
データベース
アクセス
API
3
各データベース製品が
独自のAPIを提供
• 例: OracleのOCI
– データベース接続
• strcpy( usernames, "scott/tiger@ora" );
• rc = orlon( &lda, hda, usernames, -1, (text *)0, -1, 0 );
– SQL文を準備
• strcpy( sql, "SELECT ename, deptno INTO :ename, :dno FROM emp WHERE empno =
:eno" );
• rc = oparse( &cda, sql, strlen( sql ), 1, 2 );
– 入力値のセット
• eno = 1234;
• rc = obndrv( &cda, ":eno", -1, (ub1 *)&eno, sizeof( int ), 3, -1, 0, 0, -1, -1 );
– SQL実行結果の値が保存される変数のセット
• rc = odefin( &cda, 1, ename, 32, 96, -1, 0, 0, -1, -1, 0, 0 );
• rc = odefin( &cda, 1, dno, sizeof(int), 3, -1, 0, 0, -1, -1, 0, 0 );
– SQL文の実行
• rc = oexfet( &cda, 1, -1, -1 );
– 実行結果を1行ずつ取得(フェッチ:Fetch)
• rc = ofen( &cda, 1 );
– …
4
各データベース製品が
独自のAPIを提供
• 例: SybaseのDBLIB
– データベース接続
•
•
•
•
login = dblogin();
DBSETLPWD(login, "password");
DBSETAPP(login, "app");
dbproc = dbopen(login, NULL);
– SQL文を準備
• dbcmd(dbproc, "select ename,deptname from emp where empno=1234");
– SQL文の実行
• dbsqlexec(dbproc);
– SQL実行結果の値が保存される変数のセット
• dbbind(dbproc, 1, STRINGBIND, (DBINT)0, ename);
• dbbind(dbproc, 2, STRINGBIND, (DBINT)0, deptname);
– レコードのフェッチ(実行結果を1行ずつ取得)
• dbnextrow(dbproc);
– …
5
標準インターフェース
• 代表的な例
– ODBC
• Open Database Connectivityの略
• マイクロソフトが1992年にC言語上のAPIレベルで統一
したインターフェイスとしてデータベースに接続するた
めのAPIをまとめた
• ODBC3.0が1995年に「SQL/CLI」としてSQL標準の一部と
なる
– JDBC
• Java Database Connectivity
• JDK 1.1で正式にJavaの基本SDKに同梱
6
ODBC
7
ODBC
• API例
– 資源(メモリ領域)の獲得
• SQLAllocEnv(&env);
• SQLAllocConnect(henv, &hdbc);
– データベース接続
• SQLConnect(hdbc, server, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
– SQL文の実行
• SQLAllocStmt(hdbc, &hstmt);
• strcpy(select, "select empno, ename from emp");
• SQLExecDirect(hstmt, select, SQL_NTS);
– SQL実行結果の値が保存される変数のセット
• SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0,
&id, 0, NULL);
• SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
MAX_NAME_LEN, 0, name, 0, NULL);
– レコードのフェッチ(実行結果を1行ずつ取得)
• SQLFetch(hstmt);
– …
8
ODBCの構成要素
• ODBCクライアント
ODBC
アプリケーション
– クライアントアプリケーションの
データベース要求を処理
ODBC
クライアント
• ODBCマネージャ
– ODBCクライアントからの要求を
処理
– 各DB製品用ODBCドライバの
組み込みと処理要求
ODBC
マネージャ
ODBC
ドライバ
(DB2用)
• ODBCドライバ
– ODBCマネージャからの要求を
処理し、該当するDBにアクセス
DB1
DB2
ODBC
ドライバ
(Oracle用)
DB3
DB4
9
ODBCマネージャ
• Windowsは標準装備
• UNIX系は、以下のようなものを導入する
– UnixODBC
• http://www.unixodbc.org
– DataDirect
• http://www.datadirect.com
10
ODBCアプリケーション
• 例:
– ExcelからODBC経由で各DBにアクセス可能
11
ODBCデータソースの構成
12
ODBCデータソースの構成
13
ODBCデータソースの構成
14
ExcelからODBCアクセス
15
ExcelからODBCアクセス
16
ExcelからODBCアクセス
17
ExcelからODBCアクセス
18
ExcelからODBCアクセス
19
Java
(JDBCの前に)
20
Java
• オブジェクト指向プログラム言語
• Java実行環境(JRE=Java Runtime Environment)
– JREがあれば、コンパイルしたJavaが実行可能
• Java開発環境(JDK=Java Development Kit)
– JDKがあれば、Javaのプログラムをコンパイル可能
– JREも含まれるので、コンパイルしたJavaを実行可能
Java
プログラム
基本的にどこでも実行可能
Windows用JRE
Linux用JRE
Solaris用JRE
AIX用JRE
Windows
Linux
Solaris
AIX
21
Javaのプログラム例
public class Hello {
public static void main(String[] args) {
System.out.println("クラスオブジェクトの作成");
Hello hello = new Hello();
System.out.println("メソッドの呼び出し1");
hello.sayHello();
System.out.println("メソッドの呼び出し2");
String s = hello.getMessage("日本");
System.out.println("メソッドの呼び出し2で受け取ったメッセージ: " + s);
}
public Hello() {
System.out.println("コンストラクター");
}
public void sayHello() {
System.out.println("ハロー");
}
public String getMessage(String s) {
Javaソースファイルの拡張子は、.java
String s2 = "ようこそ" + s;
例えば Hello.java
return s2;
}
}
22
Javaのコンパイル
• javac [Javaファイル名]
– 前ページのファイル名を Hello.java とすると、
> javac Hello.java
– 結果としてコンパイルされたファイル Hello.class
が生成される
23
Javaの実行
• java [クラス名]
– 前ページの Hello.class を実行する場合、
> java Hello
クラスオブジェクトの作成
コンストラクター
メソッドの呼び出し1
ハロー
メソッドの呼び出し2
メソッドの呼び出し2で受け取ったメッセージ: ようこそ日本
24
Javaのパッケージ化
• Javaが複数のパッケージから構成される場合、それらを1つにまとめるこ
とができる
• 拡張子をjarとする。そのためjarファイルと呼ばれる
• pkgディレクトリ下のすべてのファイルをまとめて、pkg.jarファイルを作成
する場合
> jar cvf pkg.jar pkg/
マニフェストが追加されました
追加中: pkg/(入力 = 0) (出力 = 0)(保管済み: 0%)
追加中: pkg/a.class(入力 = 4) (出力 = 6)(圧縮率 -50%)
追加中: pkg/b.class(入力 = 4) (出力 = 6)(圧縮率 -50%)
• 既存のディレクトリにある*.classファイルをまとめて、hello.jarファイルを作
成する場合
> jar cvf hello.jar *.class
マニフェストが追加されました
追加中: Hello.class(入力 = 1102) (出力 = 665)(圧縮率 39%)
25
jarファイルにあるクラスの実行
•
java -classpath [jarファイル名] [クラス名]
> java -classpath hello.jar Hello
クラスオブジェクトの作成
コンストラクター
メソッドの呼び出し1
ハロー
メソッドの呼び出し2
メソッドの呼び出し2で受け取ったメッセージ: ようこそ日本
•
あるいは CLASSPATH 環境変数にjarファイルをセット
> set CLASSPATH=hello.jar
> java Hello
クラスオブジェクトの作成
コンストラクター
メソッドの呼び出し1
ハロー
メソッドの呼び出し2
メソッドの呼び出し2で受け取ったメッセージ: ようこそ日本
26
eclipseによる開発
27
eclipseによる開発(デバッグ画面)
28
JDBC
29
JDBC
• JDBCライブラリを使用して
プログラミングする
• プログラミングで使用する
JDBCドライバのクラスを
動的にロードする
• JDBCライブラリはJREやJDKに
同梱
JDBC
アプリケーション1
JDBC
アプリケーション2
JDBCライブラリ
JDBCライブラリ
JDBCドライバ
(DB2用)
JDBCドライバ
(Oracle用)
データベース管理
システム
(DB2)
データベース管理
システム
(Oracle)
• JDBCドライバは一般的に
各DB製品に同梱
DB1
DB2
DB3
DB4
30
JDBCドライバのタイプ
• タイプ1,2,3,4があるが、2と4が多い。4が主流
• タイプ2
– JDBCからの要求を、OS専用のDBライブラリを用いて
処理する
– TCP/IPを経由せず、直接DBにアクセスすることも可能
– OSに依存
• タイプ4
– JDBCからの要求を、すべてJava上で処理する
– 一般的にTCP/IPを経由
– OSに依存しない
31
JDBCプログラミング例
JDBCSample1.java (1/2)
import java.sql.*;
public class JDBCSample1 {
DB2のJDBCドライバ・クラスをロード
public static void main(String[] args) {
String pubname;
String title;
データベースに接続
try {
Class.forName("com.ibm.db2.jcc.DB2Driver");
Connection conn = DriverManager.getConnection("jdbc:db2://localhost:50000/shonanit",
"userid", "password");
conn.setAutoCommit(false);
SQL文を実行
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select pubname,title from publisher,book where
publisher.pid=book.pid");
while (rs.next()) {
SQL文の実行結果を1行ずつ取得
pubname = rs.getString(1);
title = rs.getString(2);
System.out.println(pubname + ", " + title);
}
32
JDBCプログラミング例
JDBCSample1.java (1/2)
rs.close();
stmt.close();
conn.commit();
conn.close();
} catch (Exception e) {
System.out.println("Exception : " + e.toString());
e.printStackTrace();
}
}
}
33
Javaのコンパイル
• javac [Javaファイル名]
– 前ページのファイル名を Hello.java とすると、
> javac JDBCSample1.java
– 結果としてコンパイルされたファイル
JDBCSample1.class が生成される
34
Javaの実行
• 実行すると以下のエラー
>java JDBCSample1
Exception : java.lang.ClassNotFoundException:
com.ibm.db2.jcc.DB2Driver
java.lang.ClassNotFoundException:
com.ibm.db2.jcc.DB2Driver
at java.lang.Class.forName(Class.java:137)
at JDBCSample1.main(JDBCSample1.java:8)
– これは、DB2のJDBCドライバ・クラスが見つからな
いため
– DB2のJDBCドライバ・クラス
• [DB2導入ディレクトリ]¥SQLLIB¥java¥db2jcc4.jar
35
Javaの実行
• DB2のJDBCドライバ・クラス・ファイルをCLASSPATH環境変数にセット
して実行
– JDBCSample1.classがカレントディレクトリにあるので、;. も加える
>set CLASSPATH=[DB2導入ディレクトリ]/SQLLIB/java/db2jcc4.jar;.
>java JDBCSample1
小学館, はみだしインディアンのホントにホントの物語
講談社, フュージョン
岩波書店, ナルニア国物語
岩波書店, ホビットの冒険
講談社, 穴
毎日新聞社, 14歳の君へ
早川書房, これからの「正義」の話をしよう
36
SELECT文の条件(定数との比較方法)
SQL文に直接書くやり方
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select bid,title from book where bid=3");
while (rs.next()) {
bid = rs.getString(1);
title = rs.getString(2);
BID列のデータ・タイプはINTEGERだが
System.out.println(bid + ", " + title);
Stringで受けることも可能
}
(自動変換してくれる)
BID列の値をint型で受ける場合
int bid2;
…
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select bid,title from book where bid=3");
while (rs.next()) {
bid2 = rs.getInt(1);
title = rs.getString(2);
System.out.println(bid2 + ", " + title);
}
37
SELECT文の条件(定数との比較方法)
SQL文には値の代わりに ? を使用し、値は後でセットする(?をパラメーター・マーカーと呼ぶ)
PreparedStatement pstmt = conn.prepareStatement("select bid,title from book where bid=?");
pstmt.setInt(1, 3);
1つ目の?に3をセットする
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
bid = rs.getString(1);
title = rs.getString(2);
System.out.println(bid + ", " + title);
}
pstmt.setInt(1, 6);
rs = pstmt.executeQuery();
…
この方法だと値が異なる場合でも、同じSQL文を使いまわすことができる
• conn.prepareStatementメソッドの実行で、アクセス・プランが生成される
o アクセス・プラン … SQL文をどのように処理するかを示したもの
• 1回のアクセス・プラン生成で、複数回のSQL文を実行することができる
38
挿入・更新等(レコードが戻らないSQL)
パラメーター・マーカーを使用する場合
PreparedStatement pstmt = conn.prepareStatement("insert into publisher values (?,?)");
pstmt.setInt(1, 6);
pstmt.setString(2, "日本経済新聞社");
pstmt.execute();
pstmt.close();
パラメーター・マーカーを使用しない場合
Statement stmt = conn.createStatement();
stmt.execute("delete from publisher where pubname='日本経済新聞社'");
stmt.close();
39
END
40