Open棟梁 wiki
目次 †
概要 †
データアクセス関連の処理方式についてまとめる。
コネクション管理方式 †
ConnectionのOpen/Close †
- コネConnectionのOpen/Close処理の実装は、”Open棟梁”のB層の「ベースクラス2」(業務コード親クラス2)上に共通処理として実装できる。
- メソッド毎に共通処理の動作を変更する場合は、「メソッド属性」などを利用すると良い。
Connection Pooling †
コネクション プーリングに関しては、通常データ プロバイダが保有するコネクション プーリング機能をそのまま使用する。
トランザクション制御方式 †
自動トランザクション †
- TransactionのBeginとCommit/Rollback処理の実装は、”Open棟梁”のB層の「業務コード親クラス1、2」によって共通化される。
- このため、APサーバを用いた処理方式の場合、DBMSトランザクションは、B層(Tx Root)開始から終了時までとなる(2層C/S方式対応B層を使用している場合はこの限りではない)。
手動トランザクション †
1回のB層呼び出しに対して、複数のコネクション、トランザクションが必要となる要件が発生した場合は、
手動トランザクションを検討する(”Open棟梁”は手動トランザクションもサポートしている)。
排他方式 †
DBMSトランザクションの範囲は、DBMSの分離レベルに従った排他制御の動作を理解し、
必要に応じて更新ロック(OracleであればFor Update Wait・NoWait?、SQLServerであればWith (UpdLock?))など、個別にロックを適用する 。
※「HTTP」リクエストを跨ぐトランザクションの排他処理については後述する。
通信処理(リクエスト)を跨いだ排他制御方式 †
通常、通信処理(リクエスト)を跨いでDBMSトランザクションを持続できないので、リクエストを跨いで排他(ロック)を掛けるには、下記の排他方式を適用する。
楽観排他方式(タイムスタンプを使用する) †
楽観排他方式(タイムスタンプを使用する)は、
- データの取得時に、タイムスタンプを取得し、
- データの更新時に、Where句に主キーとタイムスタンプ列を指定する。
排他方式である。
全列比較方式 †
.NETでは、DataTable?がサポートするDataRowVersion?を使用した楽観方式
- 具体的には、Where句で全列のAnd = DataRowVersion?.Originalを指定する方式。
も一般的であるが、クエリが無用に長くなる等の問題もあるのでタイムスタンプ方式を推奨する。
”Open棟梁”のD層自動生成機能 †
なお、”Open棟梁”のD層自動生成機能では、
楽観排他(ロック)対応のDao生成が可能で、
- タイムスタンプ更新の自動化、
- タイムスタンプ指定の強制
などが可能である。
悲観排他方式(ロック管理テーブル) †
以下のケースで、ロック管理テーブルなどを使用して悲観排他を実現する。
- DBMSトランザクションを維持できない、サーバアプリケーションにおいて、
タイムスタンプを使用した楽観排他(ロック)ではなく、悲観排他(ロック)を実装する必要がある場合
- 若しくは、業務的に子レコードの更新の際に親レコードの悲観排他(ロック)実装する必要がある場合
行単位の悲観排他(ロック)を必要とするテーブル毎に「行ロック管理テーブル」を用意しておく。
行ロック管理テーブル †
「行ロック管理テーブル」は次のように設計すると良い。
キー(ユニーク) | ロック ユーザ | ロック取得時間 |
aaa | User1 | yyyy/MM/dd HH:mm:ss.SSS |
bbb | User2 | yyyy/MM/dd HH:mm:ss.SSS |
ccc | User3 | yyyy/MM/dd HH:mm:ss.SSS |
処理シーケンス †
行単位の悲観排他(ロック)方式の処理シーケンスを以下に示す。
- トランザクションを開始して更新先テーブルを参照し、更新ロックをかけた状態で更新対象データ行を取得する。
- 同一トランザクション内で「行ロック管理テーブル」に、上記の更新対象データ行の主キーを追加する。
追加の際、主キーは「キー(ユニーク)」列へ、ユーザ名は「ロック ユーザ」列へセットする。
- 追加に失敗した場合は、悲観排他(ロック)取得に失敗したものとし、処理を中断する。
- 追加に成功した場合は、悲観排他(ロック)取得に成功したものとし、処理を続行する(トランザクションをコミット)。
- 取得した更新対象データ行をクライアントにレスポンス、画面に表示し、編集処理を行う。
- トランザクションを開始して
- 更新先テーブルを参照し、更新ロックをかける。
- 「行ロック管理テーブル」の更新対象データに対応するレコードを参照し、更新ロックをかける。
- 上記の2つのレコードのうち、
- どちらか一方 or 双方が存在しない場合は、処理に失敗したものとし、処理を中断する。
- 双方が存在する場合は、処理に成功したものとし、処理を続行する。
- 「行ロック管理テーブル」に更新ロックをかけた状態で、更新対象データ行の更新を行う。
- 同一トランザクション内で「行ロック管理テーブル」のレコードを削除する(トランザクションをコミット) 。
- テーブル単位に管理テーブルを分割するため、負荷は軽減できている。
- ログアウトの際に「行ロック管理テーブル」のロック ユーザの条件に一致するレコードは削除するようにする。
- 必要であれば、他のロック解除を忘れた場合にもユーザが悲観排他(ロック)を取得できるようにするため、
ロック取得時間にタイムアウトを儲けるか、「行ロック管理テーブル」のレコードを消去するメンテナンス機能を実装するなどする。
テーブル設計 †
ID採番方式 †
SEQUENCE・IDENTITY †
必ず、連番にならなくても良ければ、
DBMSに実装されているSEQUENCEやIDENTITYを使用する。
以下、主要DBMSの採番機構を表に纏めた。
項番 | DBMS | 採番機構 | 確認方法 |
1 | Oracle | SEQUENCEオブジェクト | SEQUENCE.CURRVALを確認する。 |
2 | SQL Server | オート インクリメント列(IDENTITYプロパティ) | INSERTに続けてSCOPE_IDENTITYを確認する。 INSERT xxx(…) VALUES(…); SELECT SCOPE_IDENTITY (); ※ パラメタライズド・クエリではsp_executesql経由で実行されるので別のスコープで実行される。 このため、上記の様に、INSERTとSELECTを連続して記述する必要がある。 |
3 | DB2 | SEQUENCEオブジェクト | ・・・ |
4 | MySQL | オート インクリメント列(AUTO_INCREMENT属性) | ・・・ |
5 | PostgreSQL | SEQUENCEオブジェクト | ・・・ |
6 | HiRDB | SEQUENCEオブジェクト | ・・・ |
Windows Server 2008 R2から、SEQUENCEオブジェクトがサポートされたらしい。
連番採番方式 †
必ず連番にする連番採番方式は、要件に合わせて個別に設計する。
- 連番採番(追い越しを不許可):
- 採番テーブルをテーブルロック → 同時実行性 低
- 例えば、採番テーブルにはテーブルロックをかけて業務トランザクション内に含める必要があるので、当該トランザクションの同時実行性は低くなる。
- 連番採番(追い越しを許可):
- 「予約通番」を用いて追い越しを許可 → 同時実行性 高
- 連番採番(追い越しを不許可)方式ではロックが長くなり同時実行性の低下が問題になる場合は、「予約通番」を用いて追い越しを許可した連番採番を行う(初めに予約採番し、確定時に連番採番し、予約通番を実際の連番に変更する)。
レコード更新履歴の記録 †
”Open棟梁”では直接サポートしていないが、
「ベースクラス2」(データアクセス親クラス2)上に共通処理を実装できる。
方式は色々あるので、プロジェクト毎に方式を決めること。
履歴情報 †
全テーブル共通項目などを用意して、
- ユーザ名、データ追加日時
- ユーザ名、データ更新日時
- ユーザ名、データ削除日時(論理削除 → 論理削除方式は別途検討)
の情報を保持するなど(このような処理はDaoで共通化できる)。
SQL(DML)の記録 †
プロジェクト対応で、「ベースクラス2」(データアクセス親クラス2)上にSQLトレースログをDB上に出力する共通処理などを実装したケースはある。
更新前データの記録 †
また、DBMSのトリガを使用することで更新前のデータを別テーブルに記録することもできる。