こんにちは!
ナビゲータのEVEです。
本日は、レコード追加メソッドの解説をしていきます。
[レコード追加メソッドの解説]
ここ数日、ブログに掲載していた、メソッドです。昨日お話ししたとおり、処理で異常が発生した場合のrollback処理を追加しました。加えて、その話とは別に、コミット処理の一部の仕様を変更しましたので、解説でご確認ください。
/*************************************************
*【メソッド名】レコード追加メソッド
*【 引 数 】tbName :テーブル名
* i_Clum :カラム名(配列)
* i_Data :データ(配列)
*【返 却 値】なし
*【製 造 者】EVE
*【製造年月日】2023年3月3日
*【更新年月日】2023年3月6日
*【 概 要 】
* [2023/03/03]
* レコードを追加する
*<注意>
*@トランザクションを開始したくない場合は、開始前に
*トランザクション開始プロパティにoffを設定
*Aコミットしたい場合は、本メソッド開始前に、
*処理確定プロパティにonを設定
*************************************************/
//レコードを追加する
public function recInsert(string $tbName, //テーブル名
array $i_Clum, //追加用項目
array $i_Data) { //追加データ
//❶変数定義
static $i; //ループインデックス
static $i_array = array(); //追加用配列
static $strSql; //SQL文
//❷引数の判定を行う
if ( count( $i_Clum ) != count($i_Data) ) {
//引数の指定に誤りがある場合
$this->processMessage = "引数の指定に誤りがあります";
//呼び出し元へ制御を移す
return false;
}
//❸トランザクションを開始フラグを判定する
if ( $this->setTran == "on" ) {
//トランザクション開始する
$this->setTran();
//トランザクション開始プロパティを実行中にステータスを変更する
$this->setTran = "exe";
}
//❹SQL文を編集する
$i_array[] = "insert into ";
$i_array[] = $tbName;
$i_array[] = " (";
//カラム配列終了まで以下の処理を実行する
for ( $i = 0; $i < count( $i_Clum ); $i++ ) {
//カラムを編集する
$i_array[] = $i_Clum[$i];
//最終処理かどうか判定する
if ( count( $i_Clum ) == $i + 1 ) {
//最終処理の場合
$i_array[] = ")";
//forを終了する
break;
} else {
//最終処理でない場合
$i_array[] = ",";
}
}
//データの編集を開始する
$i_array[] = " value (";
//データ終了まで以下の処理を実行する
for ( $i = 0; $i < count( $i_Data ); $i++ ) {
//データを編集を開始する
$i_array[] = "?";
//最終処理かどうか判定する
if ( count( $i_Data ) == $i + 1 ) {
//最終処理の場合
$i_array[] = ");";
//forを終了する
break;
} else {
//最終処理でない場合
$i_array[] = ",";
}
}
//SQL文を編集する
$strSql = implode( "",$i_array );
//❺プリシェアードステートメント設定する
$this->stmt = $this->getDbConnect->prepare($strSql);
//SQL文実行処理
try {
//❻バインド変数終了まで以下の処理を実行する
for ( $i = 0; $i < count($i_Data); $i++ ) {
//データをSQL文へ設定する
$this->stmt->bindParam($i+1,$i_Data[$i]);
}
//❼レコード追加メソッドを実行する
$this->stmt->execute();
} catch (PDOException $e) {
//❽処理をロールバックする
$this->setRollback();
//検索が失敗した場合
//❾異常処理結果のメッセージを設定する
$this->processMessage = $e->getMessage();
//返却値を設定して呼び出し元へ制御を移す
return false;
}
//❿コミットするかどうか判定する
$this->setCommit();
//返却値を設定し呼び出し元へ制御を移す
return true;
}
❶当メソッドだけで使用するプロパティをすべて定義しています。なお、もし、プログラムの途中に変数が使われているのに、ここに定義していないのは、ただ、忘れているだけです。後で、こっそりとプログラムを修正するかもしれません(笑)。
❷入力データチェックをしています。なお、ここでは、登録カラム名配列と、その追加データ配列の個数を比較し、違った場合、異常終了させています。今までの経験上、このような箇所で一番間違いやすいのは、カラムとデータとの不整合です。そのため、ここでは配列の個数の確認だけをしていますが、今から考えると、引数をすべてチェックしてもいいかもしれません。今までシステム関数とか使用していますが、エラーメッセージは返すものがなかなかありません。それに合わせると必要最低限でいいということになるかもしれませんが・・・?
❸トランザクションを開始しています。今、このロジックを解説してみると、この位置が適切だったかな?っとは思います。通常トランザクションを開始するのは、Insert、Update、Deleteなどの処理の直前です。見直したほうがいいかもしれません。まっ、本日は、悪い見本ということで、放置します。
❹ここからSQL文を編集しています。配列の頭からSQL文のパーツを登録していって、その配列を最後で結合してSQL文を編集するというやり方です。このやり方、インターネットで時々見ますが、現在の現場では、ちょっと、違ったやり方をしていました。どのようになっていたかは、話すのを差し控えさせていただきますが、あまりいいやり方とはいえないと考えています。保守性が非常に悪いのです。多分セキュリティ重視で同方法を採用しているのだと考えていますが、このやり方でも十分セキュリティは確保できると思います。まっ、1人で製造しているので、これ以外の方法は考えられませんが・・・。
❺プリシアードステートメントとして、編集したSQL文を設定しています。先ほど話した、トランザクションの開始ですが、この直後ぐらいがいいかもしれませんね?
❻プリシアードステートメントに設定したSQL文に、取得した変数、追加データを設定しています。SQL文の編集時にデータを紛らせるという方法もありますが、以下の観点からこの方法を採用しています。
1)セキュリティ
2)データの正確性
1)プリシアードステートメントって、SQLインジェクション対応用関数って言ってもよいと思います。その関数に、本来のやり方でデータセットすることにより、セキュリティを高めています。
2)多分、stringのデータは、stringとして、integerのデータは、integerとして正しく扱ってくれるかなって期待して使用してます。マニュアルには、そこまで書いてないので、予想が外れている可能性がありますが、セキュリティの副次的な機能として期待です。
❼Insert文を実行しています。
❽これ以降は異常処理になりますが、catch直後にロールバックしています。
❾Exceptionで取得したシステムメッセージを、処理メッセージプロパティへ設定しています。
❿try〜catchを抜けて、最終処理になります。ここでコミット処理を定義しています。昨日までのプログラムでは、ここで、トランザクション開始プロパティを判定していましたが、それは、プロセス確定メソッドの中で判定することにしました。
[あとがき]
このプログラムの特長は、トランザクションの開始、確定は、このクラスの中ですべて完結しています。Prototype EVEは、すべて呼び出し元で実施していたのですが、長いプログラムでは、最後の確認作業に時間がかかります。どこでトランザクションを開始して、どこでコミットしてと、呼び出し元のプログラムの頭から最後まで見て正しく行われているのか最終的なチェックをしていました。それでは、プログラミングの効率が落ちるので、このやり方を採用しました。
トランザクションは、暗黙のうちに開始してくれますが、確定処理は明示しなくてはいけないので、思った程の効果が上がるかどうか微妙ですが・・・?
では、また!
【このカテゴリーの最新記事】