MDB検索更新異常時のロールバック方法
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/8/22 23:17:24
何度か同じ投稿を繰り返しているので訝しんでいたのですが、
投稿内容が微妙に異なっていたんですね。
> VBによる
VBA や VB6 ではなく、.NET 版の方でしょうか。
古い記事ですが、下記の最後の方(下から 7 つ目)にある
『連載:VS 2005によるWindows DBプログラミング』などは、体系立てて
説明されているので、一通り手順通りに進めていくと、
データベースを使用したアプリ開発に必要な知識が得られると思います。
https://www.atmarkit.co.jp/ait/subtop/dotnet/app/
> ①MBDで検索・更新時に異常事態がおきた場合のロールアップ方法
> ①MBDで検索・更新時に異常事態がおきた場合のロールバック方法
mdb のロールバック(巻き戻し)、ということでよろしいでしょうか。
検索においてロールバックということは無いと思うので、
更新・追加・削除といったデータ編集の話と仮定します。
異常事態というのが、ファイルの破損等の物理要因だとしたら
バックアップファイルから差し戻すしかありませんが、
実行時エラーということなら、VBA なら On Error ステートメント、
VB.NET なら Try~Catch ステートメントでエラーを捉えます。
エラーで失敗した段階で、その更新処理はキャンセルされますが、
オートナンバーに関しては、採番された値は巻き戻らず、欠番扱いとなります。
単一の更新処理ではなく、複数回の INSERT / DELETE / UPDATE 操作を
まとめてロールバックする必要がある場合は、その一連の操作範囲を
トランザクションとして指定する必要があります。
ADODB で接続している場合:
Connection オブジェクトの BeginTrans メソッドで開始
Connection オブジェクトの CommitTrans メソッドで確定
Connection オブジェクトの Rollback メソッドで巻き戻し
DAO で接続している場合:
Workspace オブジェクトの BeginTrans メソッドで開始
Workspace オブジェクトの CommitTrans メソッドで確定
Workspace オブジェクトの Rollback メソッドで巻き戻し
System.Data.OleDb で接続している場合:
OleDbConnection オブジェクトの BeginTrans メソッドで開始 (OleDbTransaction オブジェクトを取得)
OleDbTransaction オブジェクトの Commit メソッドで確定
OleDbTransaction オブジェクトの Rollback メソッドで巻き戻し
> VBによるMDBの検索・更新方法は<初心者です>先輩のご質問でよく解りました
> ②MBDで検索時の table への読み込み方
「検索・更新方法」は理解済みなのですよね?
table というのは、データベース上の表のことではなく、
System.Data.DataTable でしょうか。
DataTable への読み込みだとしたら、デザイン時に
TableAdapter を生成しておくのが手っ取り早いです。
もしも、実行時に動的に SQL を構築するようなケースでは
System.Data.OleDb.OleDbDataAdapter オブジェクトの Fill メソッドを使います。
https://www.adonetvb.com/AdoNetDataAdapterDataGridViewOle.html
OleDbDataAdapter の Fill メソッドは、上記のように、System.Data.OleDb.OleDbConnection での
接続時に用いられることが多いですが、ADODB での接続時にも利用できます。
(Fill メソッドの引数に、埋め込む先の DataTable と、取得元の Recordset の 2 つを渡せばよい)
そうして、DataTable に取り込んだデータから、必要なデータを
さらに絞り込む必要があるような場合には、Linq to DataSet を使う方法や、
DataView を使う方法、BindingSource を使う方法などがありますが、
これは質問範囲から外れるので割愛。
> importsなども必要なら教えて下さい
System.Data 名前空間などは、既定で Imports 済みのはずですが、必要に応じて
System.Data.OleDb 名前空間も Imports しておきましょう。
もし、今まで使ったことのないクラスやメソッドを利用するにあたり、
どのファイルを参照設定したり、何という名前空間を Imports すべきなのかが
分からなかった場合には、まずはドキュメントを調べてみてください。
https://docs.microsoft.com/ja-jp/dotnet/api/system.data.oledb.oledbdataadapter.fill?view=netframework-4.7.2
例えば上記は「OleDbDataAdapter.Fill メソッド」の解説ですが、その冒頭に
> 名前空間: System.Data.OleDb
> アセンブリ: System.Data.dll
と書かれています。
これはつまり、参照設定に System.Data.dll が必要であり、かつ、
「Imports System.Data.OleDb」を書けばよいということを意味しています。
(実際のところ、参照設定は必須事項ですが、Imports は必ずしも必要ではないこともあります)
投稿内容が微妙に異なっていたんですね。
> VBによる
VBA や VB6 ではなく、.NET 版の方でしょうか。
古い記事ですが、下記の最後の方(下から 7 つ目)にある
『連載:VS 2005によるWindows DBプログラミング』などは、体系立てて
説明されているので、一通り手順通りに進めていくと、
データベースを使用したアプリ開発に必要な知識が得られると思います。
https://www.atmarkit.co.jp/ait/subtop/dotnet/app/
> ①MBDで検索・更新時に異常事態がおきた場合のロールアップ方法
> ①MBDで検索・更新時に異常事態がおきた場合のロールバック方法
mdb のロールバック(巻き戻し)、ということでよろしいでしょうか。
検索においてロールバックということは無いと思うので、
更新・追加・削除といったデータ編集の話と仮定します。
異常事態というのが、ファイルの破損等の物理要因だとしたら
バックアップファイルから差し戻すしかありませんが、
実行時エラーということなら、VBA なら On Error ステートメント、
VB.NET なら Try~Catch ステートメントでエラーを捉えます。
エラーで失敗した段階で、その更新処理はキャンセルされますが、
オートナンバーに関しては、採番された値は巻き戻らず、欠番扱いとなります。
単一の更新処理ではなく、複数回の INSERT / DELETE / UPDATE 操作を
まとめてロールバックする必要がある場合は、その一連の操作範囲を
トランザクションとして指定する必要があります。
ADODB で接続している場合:
Connection オブジェクトの BeginTrans メソッドで開始
Connection オブジェクトの CommitTrans メソッドで確定
Connection オブジェクトの Rollback メソッドで巻き戻し
DAO で接続している場合:
Workspace オブジェクトの BeginTrans メソッドで開始
Workspace オブジェクトの CommitTrans メソッドで確定
Workspace オブジェクトの Rollback メソッドで巻き戻し
System.Data.OleDb で接続している場合:
OleDbConnection オブジェクトの BeginTrans メソッドで開始 (OleDbTransaction オブジェクトを取得)
OleDbTransaction オブジェクトの Commit メソッドで確定
OleDbTransaction オブジェクトの Rollback メソッドで巻き戻し
> VBによるMDBの検索・更新方法は<初心者です>先輩のご質問でよく解りました
> ②MBDで検索時の table への読み込み方
「検索・更新方法」は理解済みなのですよね?
table というのは、データベース上の表のことではなく、
System.Data.DataTable でしょうか。
DataTable への読み込みだとしたら、デザイン時に
TableAdapter を生成しておくのが手っ取り早いです。
もしも、実行時に動的に SQL を構築するようなケースでは
System.Data.OleDb.OleDbDataAdapter オブジェクトの Fill メソッドを使います。
https://www.adonetvb.com/AdoNetDataAdapterDataGridViewOle.html
OleDbDataAdapter の Fill メソッドは、上記のように、System.Data.OleDb.OleDbConnection での
接続時に用いられることが多いですが、ADODB での接続時にも利用できます。
(Fill メソッドの引数に、埋め込む先の DataTable と、取得元の Recordset の 2 つを渡せばよい)
そうして、DataTable に取り込んだデータから、必要なデータを
さらに絞り込む必要があるような場合には、Linq to DataSet を使う方法や、
DataView を使う方法、BindingSource を使う方法などがありますが、
これは質問範囲から外れるので割愛。
> importsなども必要なら教えて下さい
System.Data 名前空間などは、既定で Imports 済みのはずですが、必要に応じて
System.Data.OleDb 名前空間も Imports しておきましょう。
もし、今まで使ったことのないクラスやメソッドを利用するにあたり、
どのファイルを参照設定したり、何という名前空間を Imports すべきなのかが
分からなかった場合には、まずはドキュメントを調べてみてください。
https://docs.microsoft.com/ja-jp/dotnet/api/system.data.oledb.oledbdataadapter.fill?view=netframework-4.7.2
例えば上記は「OleDbDataAdapter.Fill メソッド」の解説ですが、その冒頭に
> 名前空間: System.Data.OleDb
> アセンブリ: System.Data.dll
と書かれています。
これはつまり、参照設定に System.Data.dll が必要であり、かつ、
「Imports System.Data.OleDb」を書けばよいということを意味しています。
(実際のところ、参照設定は必須事項ですが、Imports は必ずしも必要ではないこともあります)
投稿者 (削除されました)  ()
投稿日時
2020/8/22 23:40:20
(削除されました)
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/8/22 23:42:16
> 全くの初心者なので(バージョン2.0時代に少しやった中高年COBOL人間です)
Micro Focus の Visual COBOL 2.0 のこととも、
Microsoft の Visual Basic 2.0J のこととも読み取れますね…。
.NET 対応の COBOL もありますね。
Fujitsu の NetCOBOL とか、 Micro Focus の Net Express とか。
> ①MBDで検索・更新時に異常事態がおきた場合のロールアップ方法
> ①MBDで検索・更新時に異常事態がおきた場合のロールバック方法
再投稿後にも typo があったようですが、似た名前の用語と混ざって覚えると
後が大変なので、雑談ついでに一応メモ書き。
ロールアップ:
複数の修正差分プログラム群を一つにまとめた
累積的なパッケージのこと。
ロールフォワード:
障害発生時に、バックアップの復元位置から
障害発生直前までの更新データを反映させること。
ロールバック:
未完了の更新処理を取り消して、更新を始める前の
状態にまでデータを巻き戻すこと。
MBD:
モデルベース開発(Model Based Development)。
要求・制約に基づいたモデルを作成し、
分析・シミュレーションなどを行いながら、
ソフトウェアを作りこんでいく開発手法。
MDD:
モデル駆動開発(Model Driven Development)。
モデルを使用してシステムの分析・設計を行い、
それを詳細化してソフトウェアを作りこんでいく開発手法。
MDB:
JET Database (JET Red) Engine 用ファイル。
※ JET は Joint Engine Technology の略。
Microsoft Access や VB3 以降などで使用されていた、
旧式のデータベースフォーマット。
16bit 版と 32bit 版があるが 64bit には非対応。
ESE:
Extensible Storage (JET Blue) Engine 用ファイル。
Exchange Server や Active Direcotry や Internet Explorer などで
内部的に使用されている軽量の ISAM 型データベースフォーマット。
主な拡張子は .edb。
ACCDB
ACE Database Engine 用ファイル。
※ ACE は Access Connectivity Engine の略。
MDB の後継として、Microsoft Access などで使用されているデータベースフォーマット。
32bit 版と 64bit 版があるが 16bit には非対応。
Micro Focus の Visual COBOL 2.0 のこととも、
Microsoft の Visual Basic 2.0J のこととも読み取れますね…。
.NET 対応の COBOL もありますね。
Fujitsu の NetCOBOL とか、 Micro Focus の Net Express とか。
> ①MBDで検索・更新時に異常事態がおきた場合のロールアップ方法
> ①MBDで検索・更新時に異常事態がおきた場合のロールバック方法
再投稿後にも typo があったようですが、似た名前の用語と混ざって覚えると
後が大変なので、雑談ついでに一応メモ書き。
ロールアップ:
複数の修正差分プログラム群を一つにまとめた
累積的なパッケージのこと。
ロールフォワード:
障害発生時に、バックアップの復元位置から
障害発生直前までの更新データを反映させること。
ロールバック:
未完了の更新処理を取り消して、更新を始める前の
状態にまでデータを巻き戻すこと。
MBD:
モデルベース開発(Model Based Development)。
要求・制約に基づいたモデルを作成し、
分析・シミュレーションなどを行いながら、
ソフトウェアを作りこんでいく開発手法。
MDD:
モデル駆動開発(Model Driven Development)。
モデルを使用してシステムの分析・設計を行い、
それを詳細化してソフトウェアを作りこんでいく開発手法。
MDB:
JET Database (JET Red) Engine 用ファイル。
※ JET は Joint Engine Technology の略。
Microsoft Access や VB3 以降などで使用されていた、
旧式のデータベースフォーマット。
16bit 版と 32bit 版があるが 64bit には非対応。
ESE:
Extensible Storage (JET Blue) Engine 用ファイル。
Exchange Server や Active Direcotry や Internet Explorer などで
内部的に使用されている軽量の ISAM 型データベースフォーマット。
主な拡張子は .edb。
ACCDB
ACE Database Engine 用ファイル。
※ ACE は Access Connectivity Engine の略。
MDB の後継として、Microsoft Access などで使用されているデータベースフォーマット。
32bit 版と 64bit 版があるが 16bit には非対応。
投稿者 COBOLプログラマ  (社会人)
投稿日時
2020/8/26 20:31:33
ご指導ありがとうございます
ロールバックは
ADODB かDAOかSystem.Data.OleDbを使用しないといけ
ないわけですね
<初心者です>先輩はまた違う訳ですね
例えばDAOを利用したSQLでMDBを検索
更新したプログラムのHP、どこかに無いでしょうか?
それを参考にロールバックをしてみます。
ロールバックは
ADODB かDAOかSystem.Data.OleDbを使用しないといけ
ないわけですね
<初心者です>先輩はまた違う訳ですね
例えばDAOを利用したSQLでMDBを検索
更新したプログラムのHP、どこかに無いでしょうか?
それを参考にロールバックをしてみます。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/8/27 11:00:28
> 例えばDAOを利用したSQLでMDBを検索
> 更新したプログラムのHP、どこかに無いでしょうか?
幾つかありますよ。たとえば Access のヘルプにも記載がありますが、
それがCOBOLプログラマさんの求める物かは分かりません。
具体例が欲しければ、サンプルを書いても良いですが、そもそも開発環境は何でしょうか?
それによってもしかしたら、DAO を使うことが正しい選択ではない可能性もあります。
> <初心者です>先輩はまた違う訳ですね
ん? どういう意味でしょうか。
初心者ですさんの投稿は、このあたりでしたね。
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=30486
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=30486
> ロールバックは
> ADODB かDAOかSystem.Data.OleDbを使用しないといけ
> ないわけですね
そうですね。通常は先の回答のメソッドを使うのが一般的です。
ただ、他の選択肢もあります。SQL ステートメント(ANSI-92 モード)としての
トランザクション構文もあるので、メソッドの代わりに SQL からの指定も一応可能です。
https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/transaction-statement-microsoft-access-sql
トランザクションの指定が無かった場合は、自動コミットモードとなります。
正常時には即時反映され、失敗時にはロールバックされる状態ですね。
★この状態を、暗黙のトランザクション(implicit transaction) と言います。
ただ即時反映とはいいつつも、キャッシュの都合上、ファイルへの書き込みは
非同期的に行われる点に注意が必要です。実際にファイルに書き込まれるまでには、
最大で500ミリ秒の書き込み遅延が発生します。(レジストリ設定で変更可能)
暗黙のトランザクションで実装した場合、マルチユーザー環境においては、
新たに追加したレコードが、キャッシュがフラッシュされるまでの間、
他のユーザーから見えない状態になるなど、望ましくない結果を生んでしまいます。
そのため通常は、明示的に BeginTrans / Commit(CommitTrans) を呼んで
トランザクション範囲を明示するようにするのが安全です。マルチユーザーの場合はほぼ必須。
この場合、コミット時のファイルへの反映が同期的となり、上記の遅延問題が生じなくなります。
☆この状態を、明示的トランザクション(explicit transaction) と言います。
明示的トランザクションの場合、Commit(CommitTrans) メソッドを呼びだすまでは
ファイルへの書き込みは保留された状態となります。
実行時エラーになった場合には、もちろん処理結果は反映されません。
編集を諦めてそのままデータベースとの接続を閉じてしまっても良いですし、
あるいはロールバックして、正しい値で処理をやり直してみるのも良いでしょう。
> 更新したプログラムのHP、どこかに無いでしょうか?
幾つかありますよ。たとえば Access のヘルプにも記載がありますが、
それがCOBOLプログラマさんの求める物かは分かりません。
具体例が欲しければ、サンプルを書いても良いですが、そもそも開発環境は何でしょうか?
それによってもしかしたら、DAO を使うことが正しい選択ではない可能性もあります。
> <初心者です>先輩はまた違う訳ですね
ん? どういう意味でしょうか。
初心者ですさんの投稿は、このあたりでしたね。
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=30486
http://rucio.cloudapp.net/ThreadDetail.aspx?ThreadId=30486
> ロールバックは
> ADODB かDAOかSystem.Data.OleDbを使用しないといけ
> ないわけですね
そうですね。通常は先の回答のメソッドを使うのが一般的です。
ただ、他の選択肢もあります。SQL ステートメント(ANSI-92 モード)としての
トランザクション構文もあるので、メソッドの代わりに SQL からの指定も一応可能です。
https://docs.microsoft.com/ja-jp/office/client-developer/access/desktop-database-reference/transaction-statement-microsoft-access-sql
トランザクションの指定が無かった場合は、自動コミットモードとなります。
正常時には即時反映され、失敗時にはロールバックされる状態ですね。
★この状態を、暗黙のトランザクション(implicit transaction) と言います。
ただ即時反映とはいいつつも、キャッシュの都合上、ファイルへの書き込みは
非同期的に行われる点に注意が必要です。実際にファイルに書き込まれるまでには、
最大で500ミリ秒の書き込み遅延が発生します。(レジストリ設定で変更可能)
暗黙のトランザクションで実装した場合、マルチユーザー環境においては、
新たに追加したレコードが、キャッシュがフラッシュされるまでの間、
他のユーザーから見えない状態になるなど、望ましくない結果を生んでしまいます。
そのため通常は、明示的に BeginTrans / Commit(CommitTrans) を呼んで
トランザクション範囲を明示するようにするのが安全です。マルチユーザーの場合はほぼ必須。
この場合、コミット時のファイルへの反映が同期的となり、上記の遅延問題が生じなくなります。
☆この状態を、明示的トランザクション(explicit transaction) と言います。
明示的トランザクションの場合、Commit(CommitTrans) メソッドを呼びだすまでは
ファイルへの書き込みは保留された状態となります。
実行時エラーになった場合には、もちろん処理結果は反映されません。
編集を諦めてそのままデータベースとの接続を閉じてしまっても良いですし、
あるいはロールバックして、正しい値で処理をやり直してみるのも良いでしょう。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/8/27 11:28:56
> 具体例が欲しければ、サンプルを書いても良いですが、そもそも開発環境は何でしょうか?
どのライブラリで接続すべきかは、使用する開発環境によって変わりますので、
次回以降の質問では、VB のバージョン等も明示して頂けると助かります。
そうすれば、具体的なコード例を提示しやすいです。
先の回答で、
> > > VBA や VB6 ではなく、.NET 版の方でしょうか。
という断り書きを入れておいたのもそれが理由です。
いずれにせよ、google などで
「VB mdb rollback」
などのキーワードで検索すれば、具体的なサンプルが幾つか見つかるでしょう。
たとえば VB.NET 向けなら
https://jehupc.exblog.jp/9216997/
http://www.asahi-net.or.jp/~ef2o-inue/vbnet/sub13_02_040.html
とか、VBA 向けなら
https://kosapi.com/post-3862/
http://www.k1simplify.com/vba/practical/database06.html
http://www7b.biglobe.ne.jp/~cbcnet/DAO/record5.html
とか。他にも色々。
ロールバックは、更新がエラーで失敗した時だけではなく、たとえば
3 行更新しようとしたが、2 行しか更新されなかった。
⇒特にエラーが出たわけではなく、処理自体は成功している。
⇒他のユーザーが 1 行書き換えていたので、ヒットしなかったようだ。
⇒同時更新による不整合が出ないよう、更新された 2 行もロールバックして、元の状態に戻そう。
のような状況でも必要となりますね。
> > ロールバックは
> > ADODB かDAOかSystem.Data.OleDbを使用しないといけ
> > ないわけですね
>
そういう書き方をするということは、
それぞれの違いまでは、恐らくご存知ないのだと推察しました。
ひとまず、それぞれの違いをざっくり説明しておくと:
🔷『System.Data.OleDb』は、「ADO.NET」と呼ばれる .NET ライブラリの一つです。
その名の通り、.NET 専用のライブラリだと思ってください。
VB.NET からデータベースの読み書きを行うのであれば、ADO.NET の習得はほぼ必須です。
先に紹介した連載記事は System.Data.SqlClient という、SQL Server 向けの記事ですが、
扱うデータベースと接続情報が異なるだけで、ADO.NET としての基本的な考え方は
ほぼそのまま応用できますし、連載の最後に、トランザクション処理への言及もあります。
Visual Basic 中学校のデータベース講座は、対 mdb 向けなので良いかと思ったのですが、
こちらはトランザクション処理に入る前に連載が中断されてしまいました…。
※ADO.NET には、SQL Server 用の「System.Data.SqlClient」など、
データベースごとに異なる幾つかのライブラリがあります。
.NET ではない Visual Basic の場合は ADO.NET を使用できません。
.NET な Visual Basic の場合は通常、ADO.NET を使うようにします。
VB.NET から mdb にアクセスするなら、ほぼコレ一択なのですが、
これでできるのは単純なデータの読み書きなど、基本的な機能に限定されています。
mdb ファイルの最適化や照合順序の変更といった固有機能は
ADO.NET からでは呼び出せないため、そうした機能を利用したい場合には、
ADO.NET と併せて、DAO が併用されることがあります。
🔶『ADODB』は、「ADO」と呼ばれる COM ライブラリの一つです。
名前から想像できるかと思いますが、ADO.NET の前身にあたります。
※ ADO = ActiveX Data Objects
これは .NET が登場する前に使われていた AcitiveX 系のライブラリであり、
VB6 / VBA で開発する場合は、これがよく利用されます。
一方、ADO を VB.NET から利用することは稀です(通常は ADO.NET を使います)。
先日の回答で述べた通り、System.Data.OleDb.OleDbDataAdapter を使えば、
ADO で読み取ったデータを、.NET の DataTable へ変換することが
できるのですが、その逆に、DataTable の内容を読み取って
データベースに書き戻す機能は存在しないためです。
DataTable を一切使わずに操作するのであれば良いですが、その場合、
VB.NET で使えるデータバインド等の便利機能も使えない事になりますので、
どうしても実装コストが高くなりがちです。
また、VB.NET からの AcitiveX(COM) オブジェクトの呼び出しはボトルネックに
なりえますし、オブジェクト解放の手間も増えてしまうのもデメリットです。
ちなみに mdb ファイルの最適化や照合順序の変更といった機能が必要な場合、
ADO の一種である『ADOX』という拡張ライブラリが必要になります。
※ ADOX = ActiveX Data Objects Extensions for Data Definition Language and Security
◆『DAO』およびその後継の『ACEDAO』も、COM ライブラリです。
Microsoft Access に組み込まれている VBA (Visual Basic for Applications) から
呼び出す場合においては、最良の選択肢の一つです。
単純に mdb の読み書き速度という観点だけで見た場合、
Access VBA から DAO / ACEDAO を使うのが最速と言えます。
しかし DAO は、ADO 同様の理由から、VB.NET との相性があまり良くありません。
.NET からだとオブジェクトの解放処理の手間が煩雑になります。
しかも ADODB で使えていた DataTable への変換機能も使えないため、
ADODB 以上に実装コストが高くなります。
ただ、ADO / ADO.NET では直接利用することができず、
DAO / ACEDAO からでないと呼び出せない機能もいくつかあります。
そういった特別な場合には、必よVB.NET からこれを利用することもあります。
(動的プロパティ、ANSI-89 モード、添付ファイル型フィールドなど)
どのライブラリで接続すべきかは、使用する開発環境によって変わりますので、
次回以降の質問では、VB のバージョン等も明示して頂けると助かります。
そうすれば、具体的なコード例を提示しやすいです。
先の回答で、
> > > VBA や VB6 ではなく、.NET 版の方でしょうか。
という断り書きを入れておいたのもそれが理由です。
いずれにせよ、google などで
「VB mdb rollback」
などのキーワードで検索すれば、具体的なサンプルが幾つか見つかるでしょう。
たとえば VB.NET 向けなら
https://jehupc.exblog.jp/9216997/
http://www.asahi-net.or.jp/~ef2o-inue/vbnet/sub13_02_040.html
とか、VBA 向けなら
https://kosapi.com/post-3862/
http://www.k1simplify.com/vba/practical/database06.html
http://www7b.biglobe.ne.jp/~cbcnet/DAO/record5.html
とか。他にも色々。
ロールバックは、更新がエラーで失敗した時だけではなく、たとえば
3 行更新しようとしたが、2 行しか更新されなかった。
⇒特にエラーが出たわけではなく、処理自体は成功している。
⇒他のユーザーが 1 行書き換えていたので、ヒットしなかったようだ。
⇒同時更新による不整合が出ないよう、更新された 2 行もロールバックして、元の状態に戻そう。
のような状況でも必要となりますね。
> > ロールバックは
> > ADODB かDAOかSystem.Data.OleDbを使用しないといけ
> > ないわけですね
>
そういう書き方をするということは、
それぞれの違いまでは、恐らくご存知ないのだと推察しました。
ひとまず、それぞれの違いをざっくり説明しておくと:
🔷『System.Data.OleDb』は、「ADO.NET」と呼ばれる .NET ライブラリの一つです。
その名の通り、.NET 専用のライブラリだと思ってください。
VB.NET からデータベースの読み書きを行うのであれば、ADO.NET の習得はほぼ必須です。
先に紹介した連載記事は System.Data.SqlClient という、SQL Server 向けの記事ですが、
扱うデータベースと接続情報が異なるだけで、ADO.NET としての基本的な考え方は
ほぼそのまま応用できますし、連載の最後に、トランザクション処理への言及もあります。
Visual Basic 中学校のデータベース講座は、対 mdb 向けなので良いかと思ったのですが、
こちらはトランザクション処理に入る前に連載が中断されてしまいました…。
※ADO.NET には、SQL Server 用の「System.Data.SqlClient」など、
データベースごとに異なる幾つかのライブラリがあります。
.NET ではない Visual Basic の場合は ADO.NET を使用できません。
.NET な Visual Basic の場合は通常、ADO.NET を使うようにします。
VB.NET から mdb にアクセスするなら、ほぼコレ一択なのですが、
これでできるのは単純なデータの読み書きなど、基本的な機能に限定されています。
mdb ファイルの最適化や照合順序の変更といった固有機能は
ADO.NET からでは呼び出せないため、そうした機能を利用したい場合には、
ADO.NET と併せて、DAO が併用されることがあります。
🔶『ADODB』は、「ADO」と呼ばれる COM ライブラリの一つです。
名前から想像できるかと思いますが、ADO.NET の前身にあたります。
※ ADO = ActiveX Data Objects
これは .NET が登場する前に使われていた AcitiveX 系のライブラリであり、
VB6 / VBA で開発する場合は、これがよく利用されます。
一方、ADO を VB.NET から利用することは稀です(通常は ADO.NET を使います)。
先日の回答で述べた通り、System.Data.OleDb.OleDbDataAdapter を使えば、
ADO で読み取ったデータを、.NET の DataTable へ変換することが
できるのですが、その逆に、DataTable の内容を読み取って
データベースに書き戻す機能は存在しないためです。
DataTable を一切使わずに操作するのであれば良いですが、その場合、
VB.NET で使えるデータバインド等の便利機能も使えない事になりますので、
どうしても実装コストが高くなりがちです。
また、VB.NET からの AcitiveX(COM) オブジェクトの呼び出しはボトルネックに
なりえますし、オブジェクト解放の手間も増えてしまうのもデメリットです。
ちなみに mdb ファイルの最適化や照合順序の変更といった機能が必要な場合、
ADO の一種である『ADOX』という拡張ライブラリが必要になります。
※ ADOX = ActiveX Data Objects Extensions for Data Definition Language and Security
◆『DAO』およびその後継の『ACEDAO』も、COM ライブラリです。
Microsoft Access に組み込まれている VBA (Visual Basic for Applications) から
呼び出す場合においては、最良の選択肢の一つです。
単純に mdb の読み書き速度という観点だけで見た場合、
Access VBA から DAO / ACEDAO を使うのが最速と言えます。
しかし DAO は、ADO 同様の理由から、VB.NET との相性があまり良くありません。
.NET からだとオブジェクトの解放処理の手間が煩雑になります。
しかも ADODB で使えていた DataTable への変換機能も使えないため、
ADODB 以上に実装コストが高くなります。
ただ、ADO / ADO.NET では直接利用することができず、
DAO / ACEDAO からでないと呼び出せない機能もいくつかあります。
そういった特別な場合には、必よVB.NET からこれを利用することもあります。
(動的プロパティ、ANSI-89 モード、添付ファイル型フィールドなど)
投稿者 COBOLプログラマ  (社会人)
投稿日時
2020/8/27 19:39:09
ご指導有難うございます
具体例が欲しければ、サンプルを書いても良いですが、そもそも開発環境は何でしょうか?
言語は VB.NET2013 office 2013 OSはwin10です (あと1月で office 365です)
よろしくお願いします
「検索・更新方法」は理解済みなのですよね?
との事ですが SQLは大体理解しましたが
ADO(DAO) でのつなぎ方がわかりません
<初心者です>殿のページで
Dim Cn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data SourceC:\=Database\Animals.mdb")
Dim SQLCm As OleDbCommand = Cn.CreateCommand
SQLCm.CommandText = "INSERT INTO T_目マスタ VALUES (999, 'テスト', 'てすと', 1, 'これはテストです。')"
Cn.Open()
SQLCm.ExecuteNonQuery()
Cn.Close()
は理解し、実際に動きましたが、質問前にROOLLBACKを組み込んでも動きませんでした
ご指摘の通りでした
ADOのページをいくつか検索しましたが、どうも =Database\Animals.mdb
の記載とかがなく、よくわかりませんでした。
申し訳ありません
具体例が欲しければ、サンプルを書いても良いですが、そもそも開発環境は何でしょうか?
言語は VB.NET2013 office 2013 OSはwin10です (あと1月で office 365です)
よろしくお願いします
「検索・更新方法」は理解済みなのですよね?
との事ですが SQLは大体理解しましたが
ADO(DAO) でのつなぎ方がわかりません
<初心者です>殿のページで
Dim Cn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data SourceC:\=Database\Animals.mdb")
Dim SQLCm As OleDbCommand = Cn.CreateCommand
SQLCm.CommandText = "INSERT INTO T_目マスタ VALUES (999, 'テスト', 'てすと', 1, 'これはテストです。')"
Cn.Open()
SQLCm.ExecuteNonQuery()
Cn.Close()
は理解し、実際に動きましたが、質問前にROOLLBACKを組み込んでも動きませんでした
ご指摘の通りでした
ADOのページをいくつか検索しましたが、どうも =Database\Animals.mdb
の記載とかがなく、よくわかりませんでした。
申し訳ありません
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/8/27 21:20:24
> Dim Cn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data SourceC:\=Database\Animals.mdb")
投稿ミスでしょうか。パスの指定が間違っているようですが、正しくはこうですね。
ADO や ADO.NET では、Provider= 句で OLE DB プロバイダーを指定する必要があります。
Microsoft.Jet.OLEDB.4.0 や Microsoft.Jet.OLEDB.3.51 は開発が打ち切られており、
32bit 版しか存在していません。x64 ビルドだと使えないのでご注意ください。
現在は後継の、Microsoft.ACE.OLEDB.12.0 ~ Microsoft.ACE.OLEDB.16.0 も入手できますが、
対 mdb であれば、Microsoft.Jet.OLEDB.4.0 のままでも良いでしょう。
> 言語は VB.NET2013 office 2013 OSはwin10です (あと1月で office 365です)
> よろしくお願いします
ADO.NET でのトランザクション処理は、具体例の書かれた URL を
既に紹介済みですが…今回の例になぞらえるとこんな感じ。
オブジェクトの解放処理が確実に行われるよう、Using ステートメントも併用してみました。
> ADO(DAO) でのつなぎ方がわかりません
必要ならサンプルを書きますが… .NET が登場する前の古い技術なので、
VB.NET で開発していくのであれば、ADO / DAO / RDO などを覚える必要は無いと思いますよ。
投稿ミスでしょうか。パスの指定が間違っているようですが、正しくはこうですね。
Dim Cn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Database\Animals.mdb")
ADO や ADO.NET では、Provider= 句で OLE DB プロバイダーを指定する必要があります。
Microsoft.Jet.OLEDB.4.0 や Microsoft.Jet.OLEDB.3.51 は開発が打ち切られており、
32bit 版しか存在していません。x64 ビルドだと使えないのでご注意ください。
現在は後継の、Microsoft.ACE.OLEDB.12.0 ~ Microsoft.ACE.OLEDB.16.0 も入手できますが、
対 mdb であれば、Microsoft.Jet.OLEDB.4.0 のままでも良いでしょう。
> 言語は VB.NET2013 office 2013 OSはwin10です (あと1月で office 365です)
> よろしくお願いします
ADO.NET でのトランザクション処理は、具体例の書かれた URL を
既に紹介済みですが…今回の例になぞらえるとこんな感じ。
オブジェクトの解放処理が確実に行われるよう、Using ステートメントも併用してみました。
Using connection As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Database\Animals.mdb")
Dim command As New OleDbCommand()
Dim transaction As OleDbTransaction = Nothing
command.Connection = connection
Try
connection.Open()
' トランザクションを開始
transaction = connection.BeginTransaction()
' トランザクション割り当て
command.Connection = connection
command.Transaction = transaction
' SQL 実行
command.CommandText = "INSERT INTO T_目マスタ VALUES (900, 'テスト', 'てすと', 1, 'テストです。')"
command.ExecuteNonQuery()
' コミット処理
transaction.Commit()
Catch ex As Exception
' connection.Open() 時のエラーかもしれないし、
' command.ExecuteNonQuery() 時のエラーかもしれない。
MsgBox(ex.Message)
If transaction IsNot Nothing Then
' ロールバック処理
transaction.Rollback()
End If
End Try
End Using
> ADO(DAO) でのつなぎ方がわかりません
必要ならサンプルを書きますが… .NET が登場する前の古い技術なので、
VB.NET で開発していくのであれば、ADO / DAO / RDO などを覚える必要は無いと思いますよ。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/8/28 10:21:12
>> ADO(DAO) でのつなぎ方がわかりません
> 必要ならサンプルを書きますが… .NET が登場する前の古い技術なので、
> VB.NET で開発していくのであれば、ADO / DAO / RDO などを覚える必要は無いと思いますよ。
同じ処理の DAO (Microsoft Data Access Objects) 版です。
参照設定に、COM の "Microsoft DAO 3.6 Object Library" を加えてください。
> 必要ならサンプルを書きますが… .NET が登場する前の古い技術なので、
> VB.NET で開発していくのであれば、ADO / DAO / RDO などを覚える必要は無いと思いますよ。
同じ処理の DAO (Microsoft Data Access Objects) 版です。
参照設定に、COM の "Microsoft DAO 3.6 Object Library" を加えてください。
'Imports System.Runtime.InteropServices
Dim engine As New DAO.DBEngine()
Dim wss As DAO.Workspaces = engine.Workspaces
'既定のワークスペース
Dim ws As DAO.Workspace = wss(0)
Dim db As DAO.Database = Nothing
Try
db = ws.OpenDatabase("C:\Database\Animals.mdb", False, False)
' トランザクションを開始
ws.BeginTrans()
' SQL 実行
Dim sql As String = "INSERT INTO T_目マスタ VALUES (800, 'テスト', 'てすと', 1, 'DAO: Data Access Objects')"
'
' 更新や削除の失敗を検出できるよう、オプション引数で
' dbSeeChanges (他のユーザーに既に更新されていた場合にエラーとする) や
' dbFailOnError (エラー時に更新をロールバックする) を指定します。
'
Dim opt As DAO.RecordsetOptionEnum = DAO.RecordsetOptionEnum.dbFailOnError _
Or DAO.RecordsetOptionEnum.dbSeeChanges
'
' 第 2 引数の指定が無い場合、dbInconsistent (矛盾した更新を許可) が指定されたことになり、
' キー競合等があっても Execute がエラーにならないことに注意が必要です。
db.Execute(sql, opt)
' コミット処理
ws.CommitTrans(DAO.CommitTransOptionsEnum.dbForceOSFlush)
Catch ex As Exception
' OpenDatabase() 時のエラーかもしれないし、
' Execute() 時のエラーかもしれない。
MsgBox(ex.Message)
If db IsNot Nothing Then
' ロールバック処理
ws.Rollback()
End If
Finally
If db IsNot Nothing Then
db.Close()
' COM オブジェクトの解放処理
Marshal.ReleaseComObject(db)
db = Nothing
End If
End Try
' COM オブジェクトの解放処理
Marshal.ReleaseComObject(ws)
Marshal.ReleaseComObject(wss)
Marshal.ReleaseComObject(engine)
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/8/28 11:10:17
>> ADO(DAO) でのつなぎ方がわかりません
> 同じ処理の DAO (Microsoft Data Access Objects) 版です。
今度は ADO (Microsoft ActiveX Data Objects) 版です。
参照設定に、COM の
"Microsoft ActiveX Data Objects 6.x Library"
を加えてください。このライブラリは ADODB とも呼ばれます。
ADO 系列のライブラリには、名前のよく似たサブセットの
"Microsoft ActiveX Data Objects Recordset 6.x Library"
があります(ADOR)ので間違えないようにしましょう。
> 同じ処理の DAO (Microsoft Data Access Objects) 版です。
今度は ADO (Microsoft ActiveX Data Objects) 版です。
参照設定に、COM の
"Microsoft ActiveX Data Objects 6.x Library"
を加えてください。このライブラリは ADODB とも呼ばれます。
ADO 系列のライブラリには、名前のよく似たサブセットの
"Microsoft ActiveX Data Objects Recordset 6.x Library"
があります(ADOR)ので間違えないようにしましょう。
Dim conn As New ADODB.Connection()
Dim level As Integer = 0
Try
conn.Open("Provider=Microsoft.JET.OLEDB.4.0; Data Source=C:\Database\Animals.mdb")
' "Jet OLEDB:Transaction Commit Mode" パラメーターは、
' DAO でいうところの dbForceOSFlush オプションに相当します。
'
' この指定は必須というわけではありませんが、
' 未設定時の既定値が 0 (コミット時に非同期的に書き込み)ですので、
' 今回は意図的に 1 (コミット時に同期的に書き込み) を指定してみました。
Dim props As ADODB.Properties = Nothing
Dim prop As ADODB.Property = Nothing
Try
props = conn.Properties
prop = props("Jet OLEDB:Transaction Commit Mode")
prop.Value = 1
Catch
Finally
If prop IsNot Nothing AndAlso Marshal.IsComObject(prop) Then
Marshal.ReleaseComObject(prop)
prop = Nothing
End If
If props IsNot Nothing AndAlso Marshal.IsComObject(props) Then
Marshal.ReleaseComObject(props)
props = Nothing
End If
End Try
'; Jet OLEDB:Transaction Commit Mode=1
' トランザクションを開始
level = conn.BeginTrans()
' SQL 実行
Dim sql As String = "INSERT INTO T_目マスタ VALUES (700, 'テスト', 'てすと', 1, 'ADO: ActiveX Data Objects')"
'
' 第 2 引数は出力引数であり、更新処理の影響を受けた行数が格納されます。
'
Dim affected As Object = -1
'
' 第 3 引数で、コマンドの処理方法を指定できます。
'
Dim opt As Integer = ADODB.ExecuteOptionEnum.adExecuteNoRecords _
Or ADODB.CommandTypeEnum.adCmdText
' 1 行分の INSERT なので、affected には 1 がセットされます。
conn.Execute(sql, affected, opt)
' 今回の SQL だと、affected の結果を判断する必要は無いので、
' いきなりコミットしても問題は無いのですが、説明のために記述。
If CInt(affected) = 1 Then
' コミット処理
conn.CommitTrans()
Else
' 今回、ここに来ることはないはず。
MsgBox("失敗。INSERT された件数が 1 ではありませんでした。: " & CStr(affected))
' ロールバック処理
conn.RollbackTrans()
level -= 1
End If
Catch ex As Exception
' Open() 時のエラーかもしれないし、
' Execute() 時のエラーかもしれない。
MsgBox(ex.Message)
If level > 0 Then
' ロールバック処理
conn.RollbackTrans()
level -= 1
End If
Finally
If CBool(conn.State And ADODB.ObjectStateEnum.adStateOpen) Then
conn.Close()
End If
End Try
Marshal.ReleaseComObject(conn)
投稿者 COBOLプログラマ  (社会人)
投稿日時
2020/8/28 21:58:06
上手くいきました
ありがとうございます
お世話になりました
ありがとうございます
お世話になりました
投稿者 COBOLプログラマ  (社会人)
投稿日時
2020/8/28 21:58:08
上手くいきました
ありがとうございます
お世話になりました
ありがとうございます
お世話になりました
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/8/29 15:34:55
ADO 版のコードを修正。
> Else
> MsgBox("失敗。INSERT された件数が 1 ではありませんでした。: " & CStr(affected))
> ' ロールバック処理
> conn.RollbackTrans()
> level -= 1
> End If
この部分は、下記のようにするべきかもしれません。
Else
MsgBox("失敗。INSERT された件数が 1 ではありませんでした。: " & CStr(affected))
' ロールバック処理
conn.RollbackTrans()
End If
level -= 1
この場合の level 変数は入れ子のトランザクションのネスト数を差しており、
JET の場合、最大で 5 段階までのネストをサポートしているそうです。
一番外側のトランサクションがコミットされるまで、データベースには反映されません。
ただし入れ子のトランザクションを許可していないデータベースもあります。
また、内側のトランクションでロールバックした場合の動作は、
データベースによって実装が異なる点に注意が必要です。
https://qiita.com/yuba/items/9b5b86bc3e128a84db5e
> Else
> MsgBox("失敗。INSERT された件数が 1 ではありませんでした。: " & CStr(affected))
> ' ロールバック処理
> conn.RollbackTrans()
> level -= 1
> End If
この部分は、下記のようにするべきかもしれません。
Else
MsgBox("失敗。INSERT された件数が 1 ではありませんでした。: " & CStr(affected))
' ロールバック処理
conn.RollbackTrans()
End If
level -= 1
この場合の level 変数は入れ子のトランザクションのネスト数を差しており、
JET の場合、最大で 5 段階までのネストをサポートしているそうです。
一番外側のトランサクションがコミットされるまで、データベースには反映されません。
ただし入れ子のトランザクションを許可していないデータベースもあります。
また、内側のトランクションでロールバックした場合の動作は、
データベースによって実装が異なる点に注意が必要です。
https://qiita.com/yuba/items/9b5b86bc3e128a84db5e
VBによるMDBの検索・更新方法は<初心者です>先輩のご質問でよく解りました
お伺いしたいのは
①MBDで検索・更新時に異常事態がおきた場合のロールバック方法
②MBDで検索時の table への読み込み方
です。
全くの初心者なので(バージョン2.0時代に少しやった中高年COBOL人間です)
importsなども必要なら教えて下さい