トップ 最新 追記

Masa's blog

検索キーワード:

2009年08月05日 mplayerplug-in には安全な更新方法が用意されていないため、インストールされません [長年日記]

_ mplayerplug-in には安全な更新方法が用意されていないため、インストールされません

about:configから

extensions.checkCompatibility  -> false
extensions.checkUpdateSecurity -> false

を設定すれば、インストールできるようになる。


2009年08月04日 Microsoft SQL Server儂(わし)的解釈によるメモ(sqlcmd編) [長年日記]

_ Microsoft SQL Server儂(わし)的解釈によるメモ(sqlcmd編)

Microsoft SQL ServerCUIでコントロールする為にsqlcmdコマンドが用意されている。SQL Server Management Studioを使えばGUIで操作できるが、やはりコマンドラインで操りたい...。

なぜなら、

  • 操作の内容を記録に残しやすい。
  • 操作の伝承がしやすい。
  • 記録の再利用がしやすい。

などの理由があげられる。

例によって、各種ウェブページの切り貼り、再編集。

当然、無保証。

階層構造(あくまで個人的な解釈)

サーバ/インスタンス(SQLExpress)/データベース(master)/スキーマ(dbo)/テーブル

括弧内はデフォルト値。

データ型

int
  • 整数データを格納するデータ型
  • 記憶域サイズ:64bits
  • 範囲:-2^31 (-2,147,483,648) 〜 2^31 - 1 (2,147,483,647)
decimal
  • 固定長桁数、固定長小数桁数を持つ数値データを格納するデータ型
  • 範囲:桁数最大38桁(標準セットアップでは28桁)
money
  • 通貨を格納するデータ型
  • 記憶域サイズ:64bits
  • 範囲:-2^63(-922,337,203,685,477.5808)〜2^63 - 1(+922,337,203,685,477.5807)
float
  • 浮動小数点数値を格納するデータ型
  • 記憶域サイズ:64bits、128bits
  • 範囲:- 1.79E + 308 〜1.79E + 308
char, nchar
  • 8000文字以内の固定長の文字列を格納するデータ型。UNICODEで格納する場合はncharを使用する(4000文字以内)
varchar, nvarchar
  • 8000文字以内の可変長の文字列を格納するデータ型。UNICODEで格納する場合はnvarcharを使用する(4000文字以内)
text, ntext
  • 約20億文字以内の可変長の文字列を格納するデータ型。UNICODEで格納する場合はntextを使用する(約10億文字以内)
datetime
  • 日付を格納するデータ型
  • 範囲:1753 年 1 月 1 日〜9999 年 12 月 31 日
  • 精度:3.33ミリ秒

sqlcmdのヘルプ

C:\Documents and Settings\m-ito>sqlcmd -?
Microsoft (R) SQL Server Command Line Tool
Version 10.0.1600.22 NT INTEL X86
Copyright (C) Microsoft Corporation.  All rights reserved.

使用法: Sqlcmd            [-U login id]          [-P password]
  [-S server]            [-H hostname]          [-E trusted connection]
  [-d use database name] [-l login timeout]     [-t query timeout]
  [-h headers]           [-s colseparator]      [-w screen width]
  [-a packetsize]        [-e echo input]        [-I Enable Quoted Identifiers]
  [-c cmdend]            [-L[c] list servers[clean output]]
  [-q "cmdline query"]   [-Q "cmdline query" and exit]
  [-m errorlevel]        [-V severitylevel]     [-W remove trailing spaces]
  [-u unicode output]    [-r[0|1] msgs to stderr]
  [-i inputfile]         [-o outputfile]        [-z new password]
  [-f <codepage> | i:<codepage>[,o:<codepage>]] [-Z new password and exit]
  [-k[1|2] remove[replace] control characters]
  [-y variable length type display width]
  [-Y fixed length type display width]
  [-p[1] print statistics[colon format]]
  [-R use client regional setting]
  [-b On error batch abort]
  [-v var = "value"...]  [-A dedicated admin connection]
  [-X[1] disable commands, startup script, enviroment variables [and exit]]
  [-x disable variable substitution]
  [-? show syntax summary]

データベース作成

masterデータベースには重要なシステム情報が保存されるので、ユーザデータは別データベースを作成して、そちらに格納するのが好ましい。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> CREATE DATABASE testdb
2> GO

データベース削除

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> DROP DATABASE testdb
2> GO

データベースの指定

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE testdb
2> GO

スキーマ作成

スキーマてなんじゃ?。データベースは複数のスキーマを含む器であり、スキーマは複数のテーブルを含む器である。具体的な使い方としては、同じ性格のテーブルをグループ化して管理しやすくしたり、グループ化することによりセキュリティを高めたりという事ではないかと想像する。

ちなみに、dboというスキーマがあらかじめ用意されており、明示的に指定しない場合はdbo内にテーブルが作成される。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> use testdb
2> GO
3> CREATE SCHEMA testschema
2> GO

スキーマ削除

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> use testdb
2> GO
3> DROP SCHEMA testschema
2> GO

テーブル作成

スキーマを省略した場合はdboという名称のスキーマ内に作成される。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> use testdb
3> CREATE TABLE testschema.testtable (id int)
2> GO

テーブル削除

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> use testdb
3> DROP TABLE testschema.testtable
2> GO

ログイン作成(SQL Server認証)

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE master
2> CREATE LOGIN testuser WITH PASSWORD = 'TESTUSER-PASSWORD'
3> GO

ログイン削除

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE master
2> DROP LOGIN testuser
3> GO

パスワードの変更

sqlcmd -U testuser -P CURRENT-PASSWORD -Z NEW-PASSWORD -S localhost\SQLEXPRESS

ユーザー作成

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE testdb
2> CREATE USER testuser FOR LOGIN testuser
3> GO

ユーザー削除

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE testdb
2> DROP USER testuser
3> GO

アクセス権の付与(管理者)

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE testdb
2> GRANT CONTROL ON DATABASE::testdb TO testuser WITH GRANT OPTION
3> GO

アクセス権の付与(ユーザ)

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE testdb
2> GRANT SELECT,INSERT,UPDATE,DELETE ON testtable TO testuser
3> GO

アクセス権の削除

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE testdb
2> REVOKE SELECT,INSERT,UPDATE,DELETE ON testtable FROM testuser
3> GO

接続

sqlcmd
1> :CONNECT localhost\SQLEXpress -U sa -P SA-PASSWORD

ヘルプを表示

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> :HELP

コマンド取消(GO実行前)

1> :RESET

ユーザ一覧

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE master
2> select name from syslogins
3> GO

データベース一覧

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> select name from sys.databases
2> GO

テーブル一覧

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> select name from sys.tables
2> GO

スキーマ一覧

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> select name from sys.schemas
2> GO

スキーマ、テーブル一覧

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> select SCHEMA_NAME(schema_id),name from sys.tables
2> GO

テーブル構造を見る

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> sp_columns 'testtable'
2> GO

バックアップモデル

単純復旧モデル : バックアップはフルバックアップ差分バックアップで運用する。ログ領域は自動的に削除される。(リストアに利用できない)。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> ALTER DATABASE testdb SET RECOVERY SIMPLE
2> GO

完全復旧モデル : バックアップはフルバックアップ差分バックアップログバックアップで運用する。ログ領域はバックアップを取るまで削除されない。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> ALTER DATABASE testdb SET RECOVERY FULL
2> GO

現在設定されている復旧モデルの表示。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> SELECT name, recovery_model_desc FROM sys.databases WHERE name = 'testdb'
2> GO

バックアップ(フル)

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> BACKUP DATABASE testdb TO DISK = 'D:\backup\testdb_full.bak' WITH INIT
2> GO

バックアップ(差分 : 前回フルバックアップ以降の更新分)

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> BACKUP DATABASE testdb TO DISK = 'D:\backup\testdb_diff.bak' WITH INIT,DIFFERENTIAL
2> GO

バックアップ(トランザクションログ : 前回ログバックアップ以降のログ)

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> BACKUP LOG testdb TO DISK = 'D:\backup\testdb_log_YYYYMMDDhhmmss.bak' WITH INIT
2> GO

バックアップ計画

  • 月の第一営業日の業務終了後に「バックアップ(フル)」を実行。
  • 月の第二営業日〜月末営業日の業務終了後に「バックアップ(差分)」を実行。
  • 一日の営業時間中に適当な間隔で「バックアップ(トランザクションログ)」を実行。バックアップ先のファイルは毎回別のファイルに取る。ファイル名は昇順に並ぶように適当なシーケンス(YYYYMMDDhhmmssのような?)を付けると良い。

リストア(フル+差分+ログ)

障害が発生した時点で、アクティブなログ(=ログの末端)のバックアップを試みる

WITH NORECOVERYを指定してバックアップを取得した時点で、データベースがリストア(復旧)を受け付ける状態になり、通常の利用は出来なくなる。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE master
2> BACKUP LOG testdb TO DISK = 'D:\backup\testdb_log_last.bak' WITH INIT,NORECOVERY
3> GO
上記ではバックアップできない場合は下記のいずれかの方法でバックアップを試みる(?)
sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE master
2> BACKUP LOG testdb TO DISK = 'D:\backup\testdb_log_last.bak' WITH INIT,CONTINUE_AFTER_ERROR
3> GO
sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE master
2> BACKUP LOG testdb TO DISK = 'D:\backup\testdb_log_last.bak' WITH INIT,NO_TRUNCATE
3> GO
その後、リストアを行う

以下の手順で、たとえばDROP DATABASE testdbされた様な状態からでも復旧可能。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLEXPRESS
1> USE master
2> RESTORE DATABASE testdb FROM DISK = 'D:\backup\testdb_full.bak' WITH NORECOVERY
3> RESTORE DATABASE testdb FROM DISK = 'D:\backup\testdb_diff.bak' WITH NORECOVERY
4> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_20090804080000.bak' WITH NORECOVERY
6> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_20090804083000.bak' WITH NORECOVERY
7> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_20090804090000.bak' WITH NORECOVERY
8> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_20090804093000.bak' WITH NORECOVERY
9> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_last.bak' WITH NORECOVERY
10> RESTORE DATABASE testdb WITH RECOVERY
11> GO
特定時刻の状態までリストアしたい場合

上記の例で、末端のログの2009年8月4日 9時45分時点の状態に戻すには以下のようにする。

9> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_last.bak' WITH NORECOVERY,STOPAT='2009/08/04 09:45:00'
ちょっとずつ確認しながら、特定時刻の状態までリストアしたい場合
9> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_last.bak' WITH STANDBY='standby_file.tmp',STOPAT='2009/08/04 09:31:00'
10> select * from testdb.dbo.確認対象のテーブル
11> GO
12> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_last.bak' WITH STANDBY='standby_file.tmp',STOPAT='2009/08/04 09:32:00'
13> select * from testdb.dbo.確認対象のテーブル
14> GO
15> RESTORE LOG testdb FROM DISK = 'D:\backup\testdb_log_last.bak' WITH STANDBY='standby_file.tmp',STOPAT='2009/08/04 09:33:00'
16> select * from testdb.dbo.確認対象のテーブル
17> GO
18> RESTORE DATABASE testdb WITH RECOVER
19> GO

ログからのリストアを、ちょっとずつ進めて、行きすぎても、時間を遡ってのリストアは出来ないので注意すること。その場合は再度最初からトライする...。

その他

実際業務で利用する場合は、コマンドをテキストファイルに打ち込んで -i オプションで実行するのが良いと思われる。打ち込んだテキストファイルは設定資料として、ファイル名に日時を入れて管理するとかどうだろう。

sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLExpress -s "," -W -i Hoge.sql

2009年07月31日 Java儂(わし)的解釈によるメモ(JDBC + Microsoft SQL Server 2005 Express Edition編) [長年日記]

_ Java儂(わし)的解釈によるメモ(JDBC + Microsoft SQL Server 2005 Express Edition編)

Windowsの事も知らんぷりできない状況になりつつある中、Microsoft SQL Server 2005 Express Editionという無償で使える MS SQL Serverが有る事を知り、早速試してみた。

基本的にはJava儂(わし)的解釈によるメモ(JDBC + MySQL編)の内容と大差無いが、やはり多少の方言と言うか違いは存在していた。

Windows機(IP=192.168.0.1)側にインストールする物

以上でサーバが起動する。

  • sqlcmd.exe(Windows側ツール)

sqlcmd.exeはWindows側でデータベースにアクセスするためのクライアント(コマンドライン版)。

インスタンス名はSQLExpressに固定。

ところでインスタンスてなんじゃという話だが、1個のインスタンスが1個のリスナーポートに対応していて、つまりこれが1個のデータベース(この中に多数のテーブルを抱える)サーバプロセスということらしい。(データベースはCREATE DATABASE testdb で作成する...)

sqlcmd -?
  ヘルプ表示
sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLExpress
  1> SQL命令文
  2> GO
  3> EXIT
sqlcmd -U sa -P SA-PASSWORD -S localhost\SQLExpress -s "," -W -i Hoge.sql

クライアント側(Linux or Windows)にインストールする物

Microsoft SQL Server JDBC Driver 2.0内のsqljdbc4.jarCLASSPATHに追加するか、実行時に

java -cp /somewhere/sqljdbc4.jar HogeHoge

の様に指定する。

サンプルプログラム

//
// 「jdbc mssql」テスト
//
// compile : javac -encoding utf-8 jdbc_mssql.java
// run     : java -cp .:sqljdbc4.jar jdbc_mssql
//
//import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

public class jdbc_mssql {

	static Connection conn = null;
	static Statement stmt = null;
	static PreparedStatement pstmt = null;
	static ResultSet rs = null;
	static ResultSetMetaData rsmd = null;

	public static void main(String[] args) {
		try {
//
// JDBC for MS SQL Serverのロード
//
			Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
			System.out.println("JDBCドライバをロードしました。");
//
// データベースへの接続
//
//			String url = "jdbc:sqlserver://192.168.0.1:1433";
//			conn = DriverManager.getConnection(url, "sa", "SA-PASSWORD");
			String url = "jdbc:sqlserver://192.168.0.1:1433;databaseName=testdb;user=sa;password=SA-PASSWORD;";
			conn = DriverManager.getConnection(url);
			System.out.println("jdbc:sqlserver://192.168.0.1:1433に接続しました。");
//
// 自動コミット有効
//
//   自動コミットを有効にしないと create index で、テーブル member を見つけられずに
//   例外が発生する。MS SQLServer特有の現象か?。
//
			conn.setAutoCommit(true);
			System.out.println("自動コミットをONにしました。");
//
// SQLステートメントオブジェクト生成
//
			stmt = conn.createStatement();
//
// テーブルの削除
//
			try {
				stmt.executeUpdate("drop table member");
				System.out.println("テーブル member を削除しました。");
			} catch(Exception e){
				System.out.println("テーブル member を削除できませんでした(" + e.getMessage() + ")");
			}
//
// テーブルの作成
//
			stmt.executeUpdate(
				"create table member (" +
					"id INT PRIMARY KEY," +
					"name VARCHAR(50)," +
					"job VARCHAR(50)" +
				")"
			);
			System.out.println("テーブル member を作成しました。");
//
// わざと2重にテーブル作成してみる
//
			try {
				stmt.executeUpdate(
					"create table member (" +
						"id INT PRIMARY KEY," +
						"name VARCHAR(50)," +
						"job VARCHAR(50)" +
					")"
				);
				System.out.println("テーブル member を作成しました(2)。");
			} catch(Exception e){
				System.out.println("テーブル member を作成できませんでした(2)(" + e.getMessage() + ")");
			}
//
// 2次インデックス作成
//
			stmt.executeUpdate("create index i_member_name on member(name)");
			System.out.println("インデックスを作成しました。");
//
// 自動コミット無効
//
			conn.setAutoCommit(false);
			System.out.println("自動コミットをOFFにしました(トランザクション開始)。");
//
// タプルの追加
//
			try {
				pstmt = conn.prepareStatement("insert into member (id, name, job) values (?, ?, ?)");
//
// 1件目
//
				pstmt.setInt(1, 1);
				pstmt.setString(2, "伊藤 太郎");
				pstmt.setString(3, "サラリーマン");
				pstmt.executeUpdate();
				System.out.println("インサートしました。");
//
// 2件目
//
				pstmt.setInt(1, 2);
				pstmt.setString(2, "山田 太郎");
				pstmt.setString(3, "野球選手");
				pstmt.executeUpdate();
				System.out.println("インサートしました。");
//
// 3件目
//
				pstmt.setInt(1, 3);
				pstmt.setString(2, "山田 花子");
				pstmt.setString(3, "タレント");
				pstmt.executeUpdate();
				System.out.println("インサートしました。");
//
// わざと3件目をもう一度追加してみる
//
				pstmt.setInt(1, 3);
				pstmt.setString(2, "山田 花子");
				pstmt.setString(3, "タレント");
				pstmt.executeUpdate();
				System.out.println("インサートしました。");
			} catch (Exception e) {
				System.out.println("インサートできませんでした(" + e.getMessage() + ")");
			}
//
// タプルの検索
//
			try {
//
// クエリの実行
//
				pstmt = conn.prepareStatement("select * from member where id >= ?");
				pstmt.setInt(1, 1);
				rs = pstmt.executeQuery();
//
// 1件目の取り出し
//
				rs.next();
				System.out.println("セレクトしました(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
//
// 2件目の取り出し
//
				rs.next();
				System.out.println("セレクトしました(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
//
// 3件目の取り出し
//
				rs.next();
				System.out.println("セレクトしました(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
//
// わざと存在しない4件目を取り出してみる
//
				rs.next();
				System.out.println("セレクトしました(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
			} catch (Exception e) {
				System.out.println("セレクトできませんでした(" + e.getMessage() + ")");
			}
//
// タプルの更新
//
			try {
//
// 更新ステートメント実行
//
				pstmt = conn.prepareStatement("update member set job = ? where name = ?");
				pstmt.setString(1, "裁判官");
				pstmt.setString(2, "山田 太郎");
				pstmt.executeUpdate();
				System.out.println("アップデートしました。");
//
// 更新結果を取り出すクエリの実行
//
				pstmt = conn.prepareStatement("select * from member where name = ?");
				pstmt.setString(1, "山田 太郎");
				rs = pstmt.executeQuery();
//
// クエリ結果の取り出し
//
				rs.next();
				System.out.println("アップデート結果(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
			} catch (Exception e) {
				System.out.println("アップデートできませんでした(" + e.getMessage() + ")");
			}
//
// タプルの削除
//
			try {
//
// 削除ステートメント実行
//
				pstmt = conn.prepareStatement("delete from member where name like ?");
				pstmt.setString(1, "山田%");
				pstmt.executeUpdate();
				System.out.println("デリートしました(" + pstmt.getUpdateCount() + "件)。");
//
// 削除後の状態の検索クエリ実行
//
				pstmt = conn.prepareStatement("select * from member");
				rs = pstmt.executeQuery();
//
// クエリ結果の取り出し
//
				while (rs.next()){
					System.out.println("デリート結果(id=" +
						rs.getInt("id") + ")(name=" +
						rs.getString("name") + ")(job=" +
						rs.getString("job") + ")。");
				}
			} catch (Exception e) {
				System.out.println("デリートできませんでした(" + e.getMessage() + ")");
			}
//
// メタデータの取得
//
			try {
//
// メタデータの取得
//
				rsmd = rs.getMetaData();
//
// カラム数の取得
//
				int numberOfColumns = rsmd.getColumnCount();
				System.out.print("メタデータを取得しました(");
				for (int i = 1; i <= numberOfColumns; i++) {
//
// カラム名称の取得
//
					String name = rsmd.getColumnName (i);
					System.out.print(name + "\t");
				}
				System.out.println(")。");
			} catch (Exception e) {
				System.out.println("メタデータを取得できませんでした(" + e.getMessage() + ")");
			}
//
// コミット(トランザクションの反映)
//
			try {
				conn.commit();
				System.out.println("コミットしました。");
			} catch (Exception e) {
				System.out.println("コミットできませんでした(" + e.getMessage() + ")");
			}
		} catch (SQLException e) {
			System.out.println("SQLException: " + e.getMessage());
			System.out.println("SQLState: " + e.getSQLState());
			System.out.println("VendorError: " + e.getErrorCode());
//
// ロールバック(トランザクションの破棄)
//
			try {
				conn.rollback();
			} catch(Exception e2){
				System.out.println(e2.getMessage());
			}
		} catch(Exception e){
			System.out.println(e.getMessage());
//
// ロールバック(トランザクションの破棄)
//
			try {
				conn.rollback();
			} catch(Exception e2){
				System.out.println(e2.getMessage());
			}
		}

		try {
//
// 検索クエリの結果セットオブジェクトを破棄
//
			rs.close();
//
// SQLステートメントオブジェクトを破棄
//
			stmt.close();
			pstmt.close();
//
// データベースからの切断
//
			conn.close();
		} catch(Exception e){
			System.out.println(e.getMessage());
		}
		System.out.println("mssqlserverから切断しました。");

	}
}

実行結果

JDBCドライバをロードしました。
jdbc:sqlserver://192.168.0.1:1433に接続しました。
自動コミットをONにしました。
テーブル member を削除しました。
テーブル member を作成しました。
テーブル member を作成できませんでした(2)(データベースに 'member' という名前のオブジェクトが既に存在します。)
インデックスを作成しました。
自動コミットをOFFにしました(トランザクション開始)。
インサートしました。
インサートしました。
インサートしました。
インサートできませんでした(制約 'PK__member__2E3BD7D3' の PRIMARY KEY 違反。オブジェクト 'dbo.member' には重複したキーを挿入できません。)
セレクトしました(id=1)(name=伊藤 太郎)(job=サラリーマン)。
セレクトしました(id=2)(name=山田 太郎)(job=野球選手)。
セレクトしました(id=3)(name=山田 花子)(job=タレント)。
セレクトできませんでした(ResultSet に現在の行がありません。)
アップデートしました。
アップデート結果(id=2)(name=山田 太郎)(job=裁判官)。
デリートしました(2件)。
デリート結果(id=1)(name=伊藤 太郎)(job=サラリーマン)。
メタデータを取得しました(id     name    job     )。
コミットしました。
mssqlserverから切断しました。

追記

  • stmt.executeUpdate(INSERT|DELETE|UPDATE) の戻り値は更新されたタプル数
  • stmt.executeUpdate(上記以外の更新系SQL) の戻り値は 0
  • エラー発生時は SQLExceptin 発生。getSQLState()にてエラーコードを取得できる。

MySQLとの違い

最初からAutoCommit=falseにしていると、create indexでテーブルが見つけられずに例外が発生した。create tableの直後に明示的にcommitを発行してもダメで、結局create indexまではAutoCommit=trueで実行し、それ以降をAutoCommit=falseで実行することで(無理矢理)解決した。

ショック

一応、サーバをSQL Server 2008 Express with Advanced Servicesに変えても、上記のサンプルは動いた。


2009年07月30日 MySQL-5.x 儂(わし)的解釈によるメモ(運用編) [長年日記]

_ MySQL-5.x 儂(わし)的解釈によるメモ(運用編)

Slackware-12.xに標準でインストールされるMySQL-5.xをそのまま運用する際に 最低限必要と思われる知識に関するメモ。いろんなページの切り貼り。

Java儂(わし)的解釈によるメモ(JDBC + MySQL編)と若干かぶってるのは御勘弁を。

前提条件

  • MySQLの管理者 root
  • MySQLの一般ユーザ兼管理者 m-ito

データベース領域の初期化

mysqldを起動するに当たって、一度だけ実行する必要がある。

# mysql_install_db --user=mysql

mysqld起動スクリプトの修正

ネットワーク越しにアクセス(JDBC経由も含む)するために起動オプションを修正する (/etc/rc.d/rc.mysqld)。

#SKIP="--skip-networking"  <-- コメントアウト

MySQLコンフィグファイル設定

デフォルト文字コード、デフォルトストレージエンジンの設定。

標準のストレージエンジンであるMyISAMは速度は早いが、トランザクションが サポートされていない。非標準のストレージエンジンであるInnoDBMyISAMに 比べると速度が劣るがトランザクションをサポートする。

汎用機畑で育った私としてはトランザクションが無い(すなわちcommitrollbackが無い)のは信じられないので、デフォルトのストレージエンジンを InnoDBに変更する。また、クライアント、サーバともにデフォルトの文字コー ドをujisとする。最近はutf8が主流になりつつあるそうですが...。

 # cp /etc/my-small.conf /etc/my.cnf
 # vi /etc/my.cnf
 [client]
 ##default-character-set = utf8
 default-character-set = ujis

 [mysqld]
 ##default-character-set = utf8
 default-character-set = ujis
 default-storage-engine=innodb

mysqld起動

# chmod +x /etc/rc.d/rc.mysqld; reboot

MySQL管理者(root)のパスワード設定

$ mysqladmin -u root password ROOT-PASSWORD

データベース(testdb)の作成

$ mysql -u root -p
Enter password: XXXXXXXXXXXXX <-- ROOT-PASSWORDを入力する
mysql> create database testdb character set ujis;
mysql> quit

一般ユーザ(m-ito)を作成

$ mysql -u root -p
Enter password: XXXXXXXXXXXXX <-- ROOT-PASSWORDを入力する
mysql> create user 'm-ito'@'localhost' identified by 'USER-PASSWORD';
mysql> quit

一般ユーザ(m-ito)にデータベースへのアクセス権を設定

$ mysql -u root -p testdb
Enter password: XXXXXXXXXXXXX <-- ROOT-PASSWORDを入力する
mysql> grant all on testdb.* to 'm-ito'@'localhost' identified by 'USER-PASSWORD';
mysql> quit

一般ユーザ用MySQLコンフィグファイル設定

パスワードの設定とデフォルト文字コードの設定。このあたりは必要に応じ て...。

$ cp /etc/my-small.conf ~m-ito/.my.cnf
$ chmod 600 ~m-ito/.my.cnf
$ vi ~m-ito/.my.cnf
[client]
password = USER-PASSWORD
##default-character-set = utf8
default-character-set = ujis

データベース、テーブル情報表示

$ mysqlshow -u m-ito -p testdb HogeTable

データベースのダンプ出力

$ msql -u root -p testdb
LOCK TABLES HogeTable READ;
CTRL-Z
$ mysqldump -u m-ito -p testdb HogeTable
$ mysqldump -u m-ito -p --databases testdb
$ mysqldump -u m-ito -p --all-databases
$ fg
UNLOCK TABLES;

ユーザ管理

$ mysql -u root -p
権限の種類
  • DELETE : DELETE構文を実行できる権限。
  • INSERT : INSERT構文を実行できる権限。
  • SELECT : SELECT構文を実行できる権限。
  • UPDATE : UPDATE構文を実行できる権限。
  • INDEX : インデックスの作成と削除が行える権限。
  • REFERENCES : テーブルのリファレンスが参照できる権限。
  • USAGE : すべての権限がない。
管理者の追加
GRANT ALL ON *.* TO 'm-ito'@'%' IDENTIFIED BY 'USER-PASSWORD' WITH GRANT OPTION;
GRANT ALL ON *.* TO 'm-ito'@'localhost' IDENTIFIED BY 'USER-PASSWORD' WITH GRANT OPTION;
FLUSH PRIVILEGES;
一般ユーザの追加
GRANT SELECT,INSERT,UPDATE,DELETE ON testdb.* TO 'm-ito'@'localhost' IDENTIFIED BY 'USER-PASSWORD';
FLUSH PRIVILEGES;
ユーザ権限の削除
REVOKE ALL ON testdb.* FROM 'm-ito';
FLUSH PRIVILEGES;
ユーザの削除

REVOKEにて全ての権限を削除後

DROP USER 'm-ito';
FLUSH PRIVILEGES;
ユーザの権限確認
SELECT * FROM mysql.user WHERE User='m-ito';

データベースの削除

mysql -u root -p
DROP DATABASE testdb;

パスワードの設定

mysql -u root -p
SET PASSWORD FOR 'm-ito'@'%' = PASSWORD('USER-PASSWORD');

CSVファイルの取り込み

mysql -u root -p
LOCK TABLES HogeTable WRITE;
LOAD DATA INFILE "Hoge.csv" INTO TABLE HogeTable FIELDS TERMINATED BY ',' ENCLOSED BY '"';
UNLOCK TABLES;
  • フィールド区切り文字のデフォルトは「タブ」。
  • 文字列囲み文字のデフォルトは「無し」。

CSVファイルへの書き出し

mysql -u root -p
LOCK TABLES HogeTable READ;
SELECT * FROM HogeTable INTO OUTFILE "Hoge.csv" FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"';
UNLOCK TABLES;
  • フィールド区切り文字のデフォルトは「タブ」。
  • 文字列囲み文字のデフォルトは「無し」。

_ BIND 9の脆弱性について

BIND 9にてDynamic DNS機能に関して脆弱性が報告されている。DoSの対称になってしまうとのこと。

JVNVU#725188 ISC BIND 9 におけるサービス運用妨害 (DoS) の脆弱性

早速、libretto100(myh.no-ip.org)のbindもバージョンアップ。

bind-9.4.3-P3


2009年07月25日 firefox-3.0.12, firefox-3.5.1 on Slackware-12.2 [長年日記]

_ firefox-3.0.12, firefox-3.5.1 on Slackware-12.2

.mozconfig

. $topsrcdir/browser/config/mozconfig
ac_add_options --disable-debug
ac_add_options --enable-optimize
ac_add_options --enable-default-toolkit=cairo-gtk2

build

nice make -f client.mk build
nice make package

2009年07月19日 libretto100(myh.no-ip.org server) harddisk crash! [長年日記]

_ libretto100(myh.no-ip.org server) harddisk crash!

4月にディスク交換したmyh.no-ip.orgのサーバであったが、見事にディスククラッシュ。

前日に異音を発したのでとりあえず再起動を行い、異音が消えたため即座にバックアップを取得し、そのまま継続運用していた。

翌日、仕事から帰ってみるとフリーズ状態。再起動して稼働することは確認するも、その後出かける用事があったので念のために(発熱で火災でも起こすと困るので)シャットダウンして出かける。

帰宅して電源入れるも、ハードディスクが異音を起てて起動せず。完全にクラッシュ状態となる。

はぁ〜...

予備のハードディスクにバックアップから戻し、復旧。

_ 教訓:ヤフオクの(中古)ハードディスクは信用できない。


2009年07月14日 Kernel Version UP 2.6.27.7 to 2.6.29.6 on Slackware-12.2 [長年日記]

_ Kernel Version UP 2.6.27.7 to 2.6.29.6 on Slackware-12.2

Libretto U100(Slackware-12.2)の無線LAN(ath5k Atheros AR2414)の調子があまり良くない。接続ができないわけでは無いけれども、速度が異常に遅い。/var/log/syslogに以下のメッセージが連続して記録されている。

Jul 13 04:55:31 lib190 kernel: ath5k phy0: noise floor calibration timeout (2462MHz)

上記のメッセージ(kernel: ath5k phy0: noise floor calibration timeout)で検索してみると、同様の報告が結構あって、カーネルのバージョンをアップすれば改善する様子。

そこで現行の 2.6.27.7 から 2.6.29.6 へバージョンアップすることにする。現時点での最新カーネルは 2.6.30.1 なのだが、Slackware-currentが 2.6.29.5 だったので、同系列の最新版を採用することにした。コンフィグ(config-huge-smp-2.6.29.5-smp)もSlackware-currentのものを利用できるし、安心。

# cd /usr/src
# rm linux
# tar xvjf linux-2.6.29.6.tar.bz2
# ln -s linux-2.6.29.6 linux
# cd linux
# make mrproper
# cp /anywhere/config-huge-smp-2.6.29.5-smp .config
# make oldconfig
# make menuconfig  <-- CPU TYPE を Pentium-M に変更
# make
# make modules_install
# make install

Cahngesを確認すると、e2fsprogs-1.41.4以上を求められているが、Slackware-12.2のは1.41.3だったので、これもバージョンアップする。Slackware-currente2fsprogsのビルドスクリプトを参考にして、

# tar xvzf  e2fsprogs-1.41.8.tar.gz
# cd e2fsprogs-1.41.8
# VERSION=1.41.8
# ./configure \
      --prefix=/usr \
      --libdir=/lib \
      --bindir=/usr/bin \
      --includedir=/usr/include \
      --datadir=/usr/share \
      --mandir=/usr/man \
      --infodir=/usr/info \
      --docdir=/usr/doc/e2fsprogs-$VERSION \
      --enable-elf-shlibs \
      --enable-dynamic-e2fsck \
      --enable-libblkid \
      --disable-uuidd
# make
# make install
# make install-libs

以上で、カーネルバージョンアップ+αの作業完了。あとはこれで無線LANが安定してくれれば...。

_ X.orgで日本語フォントが中国っぽくなる件

# cd /etc/fonts/conf.d
# mv 44-wqy-zenhei.conf 44-wqy-zenhei.conf.REMOVED

にて解決。


2009年07月11日 ruby(1.8.x)儂(わし)的解釈によるメモ(DBI + MySQL編) [長年日記]

_ ruby(1.8.x)儂(わし)的解釈によるメモ(DBI + MySQL編)

rubyからDBMS(MySQL)にDBI経由で接続してみる。例によって用語、用法等は思い込みである部分が見受けられると思うが、御容赦願う。

準備

dbi-0.4.1.tar.gzを取得する(http://rubyforge.org/frs/?group_id=234)。

# tar xvzf dbi-0.4.1.tar.gz
# cd dbi-0.4.1/
# gem install dbi
# gem install dbd-mysql

もし上記でdbiがうまくインストール出来なかった場合は、

# ruby setup.rb config
# ruby setup.rb setup
# ruby setup.rb install

を試してみるとよいかも...。

サンプルプログラム

#! /usr/bin/ruby
#
require 'rubygems'
require 'dbi'
#
# データベースへの接続
#
dbh = DBI.connect('DBI:Mysql:dbitestdb', 'm-ito', 'USER-PASSWORD')
puts("データベース(dbitestdb)に接続しました。")
#
# 文字コードの設定(MySQL依存)
#
dbh.do('SET NAMES ujis')
puts("日本語文字コードをujisに設定しました(MySQL依存設定)。")
#
# 自動コミットの停止
#
##dbh.do('SET AutoCommit = 0')
dbh['AutoCommit'] = false
puts("自動コミット停止しました(トランザクションの開始)。")
#
# トランザクション(1)
#
dbh.transaction {|dbh|
#
# テーブルの削除
#
	begin
		sql = <<SQL
			drop table member
SQL
		dbh.do(sql)
		puts "テーブルの削除に成功しました。"
	rescue => e
		puts "テーブルの削除に失敗しました(#{e.to_s})。"
	end
#
# テーブルの作成(engine = innodbによるストレージエンジンの
#                指定はMySQL依存機能)
#
	begin
		sql = <<SQL
			create table member (
				id INT PRIMARY KEY,
				name VARCHAR(50),
				job VARCHAR(50)
			) engine = innodb
SQL
		dbh.do(sql)
		puts "テーブルの作成に成功しました。"
	rescue => e
		puts "テーブルの作成に失敗しました(#{e.to_s})。"
	end
#
# わざと2重にテーブルを作成してみる
#
	begin
		sql = <<SQL
			create table member (
				id INT PRIMARY KEY,
				name VARCHAR(50),
				job VARCHAR(50)
			)
SQL
		dbh.do(sql)
		puts "テーブルの作成に成功しました(2)。"
	rescue => e
		puts "テーブルの作成に失敗しました(2)(#{e.to_s})。"
	end
#
# インデックスの作成
#
	sql = <<SQL
		create index i_member_name on member(name)
SQL
	dbh.do(sql)
	puts "インデックスの作成に成功しました。"
}
#
# トランザクション(2)
#
dbh.transaction {|dbh|
#
# データの追加
#
	sql = <<SQL
		insert into member (id, name, job) values (?, ?, ?)
SQL
	sth = dbh.prepare(sql)
	sth.execute(1, '伊藤 太郎', 'サラリーマン')
	puts "インサートに成功しました。"
	sth.execute(2, '山田 太郎', '野球選手')
	puts "インサートに成功しました。"
	sth.execute(3, '山田 花子', 'タレント')
	puts "インサートに成功しました。"
#
# わざと2重キーで登録してみる
#
	begin
		sth.execute(3, '山田 花子', 'タレント')
		puts "インサートに成功しました。"
	rescue => e
		puts "インサートに失敗しました(#{e.to_s})。"
	end
	sth.finish
}
#
# データの検索
#
sql = <<SQL
	select * from member where id >= ?
SQL
sth = dbh.prepare(sql)
sth.execute(1)
while (row = sth.fetch)
	puts "セレクトに成功しました(id=#{row['id']})(name=#{row['name']})(job=#{row['job']})"
end
sth.finish
#
# トランザクション(3)
#
dbh.transaction {|dbh|
#
# データの更新
#
	sql = <<SQL
		update member set job = ? where name = ?
SQL
	sth = dbh.prepare(sql)
	sth.execute('裁判官', '山田 太郎')
	puts ("アップデートに成功しました。")
	sth.finish
}
#
# 更新結果の確認
#
sql = <<SQL
	select * from member where name = ?
SQL
sth = dbh.prepare(sql)
sth.execute('山田 太郎')
while (row = sth.fetch)
	puts "アップデートの確認(id=#{row['id']})(name=#{row['name']})(job=#{row['job']})"
end
sth.finish
#
# トランザクション(4)
#
dbh.transaction {|dbh|
#
# データの削除
#
	sql = <<SQL
		delete from member where name like ?
SQL
	sth = dbh.prepare(sql)
	sth.execute('山田%')
	puts ("デリートに成功しました。")
	sth.finish
}
#
# 削除の確認
#
sql = <<SQL
	select * from member
SQL
sth = dbh.prepare(sql)
sth.execute()
while (row = sth.fetch)
	puts "デリートの確認(id=#{row['id']})(name=#{row['name']})(job=#{row['job']})"
end
sth.finish
#
# メタデータの取得
#
sql = <<SQL
	select * from member
SQL
sth = dbh.prepare(sql)
sth.execute()
puts "メタデータ カラム数=#{sth.column_names.size}"
print "メタデータ カラム名="
sth.column_names.each {|name|
	print "#{name}\t"
}
puts ""
#
sth.column_info.each_with_index {|info, i|
        print "項番 = #{i} / "
        print "カラム名 = #{info.name} / "
        print "精度 = #{info.precision} / "
        print "スケール = #{info.scale}\n"
}
sth.finish
#
# (手動で)のコミット(またはロールバック)の実行
#
#dbh.rollback
#puts "ロールバックしました。"
dbh.commit
puts "コミットしました。"
#
# データベースからの切断
#
dbh.disconnect
puts("データベース(dbitestdb)から切断しました。")

実行結果

データベース(dbitestdb)に接続しました。
日本語文字コードをujisに設定しました(MySQL依存設定)。
自動コミット停止しました(トランザクションの開始)。
テーブルの削除に成功しました。
テーブルの作成に成功しました。
テーブルの作成に失敗しました(2)(Table 'member' already exists)。
インデックスの作成に成功しました。
インサートに成功しました。
インサートに成功しました。
インサートに成功しました。
インサートに失敗しました(Duplicate entry '3' for key 1)。
セレクトに成功しました(id=1)(name=伊藤 太郎)(job=サラリーマン)
セレクトに成功しました(id=2)(name=山田 太郎)(job=野球選手)
セレクトに成功しました(id=3)(name=山田 花子)(job=タレント)
アップデートに成功しました。
アップデートの確認(id=2)(name=山田 太郎)(job=裁判官)
デリートに成功しました。
デリートの確認(id=1)(name=伊藤 太郎)(job=サラリーマン)
メタデータ カラム数=3
メタデータ カラム名=id  name    job
項番 = 0 / カラム名 = id / 精度 = 11 / スケール = 0
項番 = 1 / カラム名 = name / 精度 = 150 / スケール = 0
項番 = 2 / カラム名 = job / 精度 = 150 / スケール = 0
コミットしました。
データベース(dbitestdb)から切断しました。

_ googleearth on Libretto U100(Slackware-12.2)

googleearthを入れてみた。十分な速度で動いてくれた。ただし、日本語メニューが化けている。

どうやらパッケージに同梱されている libQt*.so.4 が国際化対応でビルドされた物ではないようだ。そこで qt-x11-opensource-src-4.5.2.tar.gzを取得して ./configure && make && make install でインストールし、 /etc/ld.so.conf に /usr/local/Trolltech/Qt-4.5.2/lib を追加して ldconfig した後、念のために ~/google-earth/配下にある、

$ ls -al google-earth/libQt*
-rwxr-xr-x 1 m-ito m-ito 2244156 2009-07-09 20:38 google-earth/libQtCore.so.4
-rwxr-xr-x 1 m-ito m-ito 7305864 2009-07-09 20:38 google-earth/libQtGui.so.4
-rwxr-xr-x 1 m-ito m-ito  774340 2009-07-09 20:38 google-earth/libQtNetwork.so.4
-rwxr-xr-x 1 m-ito m-ito 7265852 2009-07-09 20:38 google-earth/libQtWebKit.so.4

を削除するなり、リネームするなりして参照されないようにする。

これで無事、日本語メニューも出るようになった。


2009年07月10日 Java儂(わし)的解釈によるメモ(JDBC + MySQL編) [長年日記]

_ Java儂(わし)的解釈によるメモ(JDBC + MySQL編)

JavaからDBMS(MySQL)にJDBC経由で接続してみる。例によって用語、用法等は思い込みである部分が見受けられると思うが、御容赦願う。

準備

Slackware-12.xに標準でインストールされるMySQL-5.xをそのまま利用する。

JDBCドライバの取得

mysql-connector-java-5.0.8.tar.gzを取得(http://dev.mysql.com/downloads/connector/j/)

$ tar xvzf mysql-connector-java-5.0.8.tar.gz
$ cp mysql-connector-java-5.0.8/mysql-connector-java-5.0.8-bin.jar .

mysql-connector-java-5.0.8-bin.jarをどこかグローバルな場所(例えば/usr/local/jdk/みたいな)に置いて、

CLASSPATH=${CLASSPATH}:/usr/local/jdk/mysql-connector-java-5.0.8-bin.jar; export CLASSPATH

しておくのも良いかも。

データベース領域の初期化

mysqldを起動するに当たって、一度だけ実行する必要がある。

# mysql_install_db --user=mysql
mysqld起動スクリプトの修正

JDBC経由でアクセスするために起動オプションを修正する(/etc/rc.d/rc.mysqld)。

#SKIP="--skip-networking"  <-- コメントアウト
MySQLコンフィグファイル設定

デフォルト文字コード、デフォルトストレージエンジンの設定。

標準のストレージエンジンであるMyISAMは速度は早いが、トランザクションがサポートされていない。非標準のストレージエンジンであるInnoDBMyISAMに比べると速度が劣るがトランザクションをサポートする。

汎用機畑で育った私としてはトランザクションが無い(すなわちcommit、rollbackが無い)のは信じられないので、デフォルトのストレージエンジンをInnoDBに変更する。

# cp /etc/my-small.conf /etc/my.cnf
# vi /etc/my.cnf

[client]
##default-character-set = utf8
default-character-set = ujis
[mysqld]
##default-character-set = utf8
default-character-set = ujis
default-storage-engine=innodb
mysqld起動
# chmod +x /etc/rc.d/rc.mysqld; reboot
MySQL管理者(root)のパスワード設定
# mysqladmin -u root password ROOT-PASSWORD
データベース(jdbctestdb)の作成
# mysql -u root -p
Enter password: XXXXXXXXXXXXX <-- ROOT-PASSWORDを入力する
mysql> create database jdbctestdb character set ujis;
mysql> quit
一般ユーザ(m-ito)にデータベースへのアクセス権を設定
# mysql -u root -p jdbctestdb
Enter password: XXXXXXXXXXXXX <-- ROOT-PASSWORDを入力する
mysql> grant all on jdbctestdb.* to 'm-ito'@'localhost' identified by 'USER-PASSWORD';
mysql> quit
一般ユーザ用MySQLコンフィグファイル設定

パスワードの設定とデフォルト文字コードの設定。このあたりは必要に応じて...。

$ cp /etc/my-small.conf ~m-ito/.my.cnf
$ chmod 600 ~m-ito/.my.cnf
$ vi ~m-ito/.my.cnf

[client]
password = USER-PASSWORD
##default-character-set = utf8
default-character-set = ujis

サンプルプログラム

//
// 「jdbc mysql」テスト
//
// compile : javac -encoding utf-8 jdbc_mysql.java
// run     : java -cp .:mysql-connector-java-5.0.8-bin.jar jdbc_mysql
//
//import java.sql.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

public class jdbc_mysql {

	static Connection conn = null;
	static Statement stmt = null;
	static PreparedStatement pstmt = null;
	static ResultSet rs = null;
	static ResultSetMetaData rsmd = null;

	public static void main(String[] args) {
		try {
//
// JDBC for MySQLのロード
//
			Class.forName("com.mysql.jdbc.Driver").newInstance();
			System.out.println("JDBCドライバをロードしました。");
//
// データベースへの接続
//
//			String url = "jdbc:mysql://localhost/jdbctestdb?useUnicode=true&characterEncoding=SJIS";
			String url = "jdbc:mysql://localhost/jdbctestdb?useUnicode=true&characterEncoding=EUC_JP";
			conn = DriverManager.getConnection(url, "m-ito", "USER-PASSWORD");
			System.out.println("jdbctestdbに接続しました。");
//
// 自動コミット停止(トランザクションの開始)
//
			conn.setAutoCommit(false);
			System.out.println("自動コミットをOFFにしました。");
//
// SQLステートメントオブジェクト生成
//
			stmt = conn.createStatement();
//
// テーブルの削除
//
			try {
				stmt.executeUpdate("drop table member");
				System.out.println("テーブル member を削除しました。");
			} catch(Exception e){
				System.out.println("テーブル member を削除できませんでした(" + e.getMessage() + ")");
			}
//
// テーブルの作成
//
			stmt.executeUpdate(
				"create table member (" +
					"id INT PRIMARY KEY," +
					"name VARCHAR(50)," +
					"job VARCHAR(50)" +
				") engine = innodb"
			);
			System.out.println("テーブル member を作成しました。");
//
// わざと2重にテーブル作成してみる
//
			try {
				stmt.executeUpdate(
					"create table member (" +
						"id INT PRIMARY KEY," +
						"name VARCHAR(50)," +
						"job VARCHAR(50)" +
					")"
				);
				System.out.println("テーブル member を作成しました(2)。");
			} catch(Exception e){
				System.out.println("テーブル member を作成できませんでした(2)(" + e.getMessage() + ")");
			}
//
// 2次インデックス作成
//
			stmt.executeUpdate("create index i_member_name on member(name)");
			System.out.println("インデックスを作成しました。");
//
// タプルの追加
//
			try {
				pstmt = conn.prepareStatement("insert into member (id, name, job) values (?, ?, ?)");
//
// 1件目
//
				pstmt.setInt(1, 1);
				pstmt.setString(2, "伊藤 太郎");
				pstmt.setString(3, "サラリーマン");
				pstmt.executeUpdate();
				System.out.println("インサートしました。");
//
// 2件目
//
				pstmt.setInt(1, 2);
				pstmt.setString(2, "山田 太郎");
				pstmt.setString(3, "野球選手");
				pstmt.executeUpdate();
				System.out.println("インサートしました。");
//
// 3件目
//
				pstmt.setInt(1, 3);
				pstmt.setString(2, "山田 花子");
				pstmt.setString(3, "タレント");
				pstmt.executeUpdate();
				System.out.println("インサートしました。");
//
// わざと3件目をもう一度追加してみる
//
				pstmt.setInt(1, 3);
				pstmt.setString(2, "山田 花子");
				pstmt.setString(3, "タレント");
				pstmt.executeUpdate();
				System.out.println("インサートしました。");
			} catch (Exception e) {
				System.out.println("インサートできませんでした(" + e.getMessage() + ")");
			}
//
// タプルの検索
//
			try {
//
// クエリの実行
//
				pstmt = conn.prepareStatement("select * from member where id >= ?");
				pstmt.setInt(1, 1);
				rs = pstmt.executeQuery();
//
// 1件目の取り出し
//
				rs.next();
				System.out.println("セレクトしました(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
//
// 2件目の取り出し
//
				rs.next();
				System.out.println("セレクトしました(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
//
// 3件目の取り出し
//
				rs.next();
				System.out.println("セレクトしました(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
//
// わざと存在しない4件目を取り出してみる
//
				rs.next();
				System.out.println("セレクトしました(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
			} catch (Exception e) {
				System.out.println("セレクトできませんでした(" + e.getMessage() + ")");
			}
//
// タプルの更新
//
			try {
//
// 更新ステートメント実行
//
				pstmt = conn.prepareStatement("update member set job = ? where name = ?");
				pstmt.setString(1, "裁判官");
				pstmt.setString(2, "山田 太郎");
				pstmt.executeUpdate();
				System.out.println("アップデートしました。");
//
// 更新結果を取り出すクエリの実行
//
				pstmt = conn.prepareStatement("select * from member where name = ?");
				pstmt.setString(1, "山田 太郎");
				rs = pstmt.executeQuery();
//
// クエリ結果の取り出し
//
				rs.next();
				System.out.println("アップデート結果(id=" +
					rs.getInt("id") + ")(name=" +
					rs.getString("name") + ")(job=" +
					rs.getString("job") + ")。");
			} catch (Exception e) {
				System.out.println("アップデートできませんでした(" + e.getMessage() + ")");
			}
//
// タプルの削除
//
			try {
//
// 削除ステートメント実行
//
				pstmt = conn.prepareStatement("delete from member where name like ?");
				pstmt.setString(1, "山田%");
				pstmt.executeUpdate();
				System.out.println("デリートしました(" + pstmt.getUpdateCount() + "件)。");
//
// 削除後の状態の検索クエリ実行
//
				pstmt = conn.prepareStatement("select * from member");
				rs = pstmt.executeQuery();
//
// クエリ結果の取り出し
//
				while (rs.next()){
					System.out.println("デリート結果(id=" +
						rs.getInt("id") + ")(name=" +
						rs.getString("name") + ")(job=" +
						rs.getString("job") + ")。");
				}
			} catch (Exception e) {
				System.out.println("デリートできませんでした(" + e.getMessage() + ")");
			}
//
// メタデータの取得
//
			try {
//
// メタデータの取得
//
				rsmd = rs.getMetaData();
//
// カラム数の取得
//
				int numberOfColumns = rsmd.getColumnCount();
				System.out.print("メタデータを取得しました(");
				for (int i = 1; i <= numberOfColumns; i++) {
//
// カラム名称の取得
//
					String name = rsmd.getColumnName (i);
					System.out.print(name + "\t");
				}
				System.out.println(")。");
			} catch (Exception e) {
				System.out.println("メタデータを取得できませんでした(" + e.getMessage() + ")");
			}
//
// コミット(トランザクションの反映)
//
			try {
				conn.commit();
				System.out.println("コミットしました。");
			} catch (Exception e) {
				System.out.println("コミットできませんでした(" + e.getMessage() + ")");
			}
		} catch (SQLException e) {
			System.out.println("SQLException: " + e.getMessage());
			System.out.println("SQLState: " + e.getSQLState());
			System.out.println("VendorError: " + e.getErrorCode());
//
// ロールバック(トランザクションの破棄)
//
			try {
				conn.rollback();
			} catch(Exception e2){
				System.out.println(e2.getMessage());
			}
		} catch(Exception e){
			System.out.println(e.getMessage());
//
// ロールバック(トランザクションの破棄)
//
			try {
				conn.rollback();
			} catch(Exception e2){
				System.out.println(e2.getMessage());
			}
		}

		try {
//
// 検索クエリの結果セットオブジェクトを破棄
//
			rs.close();
//
// SQLステートメントオブジェクトを破棄
//
			stmt.close();
			pstmt.close();
//
// データベースからの切断
//
			conn.close();
		} catch(Exception e){
			System.out.println(e.getMessage());
		}
		System.out.println("jdbctestdbから切断しました。");

	}
}

実行結果

JDBCドライバをロードしました。
jdbctestdbに接続しました。
自動コミットをOFFにしました。
テーブル member を削除しました。
テーブル member を作成しました。
テーブル member を作成できませんでした(2)(Table 'member' already exists)
インデックスを作成しました。
インサートしました。
インサートしました。
インサートしました。
インサートできませんでした(Duplicate entry '3' for key 1)
セレクトしました(id=1)(name=伊藤 太郎)(job=サラリーマン)。
セレクトしました(id=2)(name=山田 太郎)(job=野球選手)。
セレクトしました(id=3)(name=山田 花子)(job=タレント)。
セレクトできませんでした(After end of result set)
アップデートしました。
アップデート結果(id=2)(name=山田 太郎)(job=裁判官)。
デリートしました(2件)。
デリート結果(id=1)(name=伊藤 太郎)(job=サラリーマン)。
メタデータを取得しました(id     name    job     )。
コミットしました。
jdbctestdbから切断しました。

追記

  • stmt.executeUpdate(INSERT|DELETE|UPDATE) の戻り値は更新されたタプル数
  • stmt.executeUpdate(上記以外の更新系SQL) の戻り値は 0
  • エラー発生時は SQLExceptin 発生。getSQLState()にてエラーコードを取得できる。

about Microsoft SQL Server(情報のみ)

Microsoft SQL Server 2005 JDBC Driver

JDBCドライバ(msbase.jar、mssqlserver.jar)を使用した場合(SQLServer2000以前)

Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
Connection con = DriverManager.getConnection("jdbc:microsoft:sqlserver://サーバ名:1433","ユーザID","パスワード");

JDBCドライバ(sqljdbc.jar)を使用した場合(SQLServer2005以降)

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection con = DriverManager.getConnection("jdbc:sqlserver://サーバ名:1433","ユーザID","パスワード");

about Oracle(情報のみ)

Oracle JDBC Driver ダウンロード

Class.forName("oracle.jdbc.driver.OracleDriver");
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@サーバ名:1521:OracleSID","ユーザID","パスワード");

OracleSID : tnsnames.ora に記述がある。


2009年07月06日 myh.no-ip.org(libretto 100) linux-2.4.37.2 Version UP [長年日記]

_ myh.no-ip.org(libretto 100) linux-2.4.37.2 Version UP

サーバ(myh.no-ip.org on Libretto 100)のカーネルをlinux-2.4.37.2にバージョンアップ。すると以前から出ていた

request_module[net-pf-10]: waitpid(3788,...) failed, errno 1

のメッセージが出なくなっていた(^o^)/。さらに、modprobe.oldがゾンビプロセスになってた件も解決していた(^O^)/。

_ fnfxd breaks Wireless LAN

fnfxdを使うと輝度コントロール等ができると書いて喜んでいたのだが、Libretto U100では、なぜか無線LANがつながらなくなる現象が頻発。とりあえず使用を中止することに...。