質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

PHP 常識的な採番マスタの使い方を教えてください。番号繰上(更新)と採用の手順を一まとめにする方法

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 3,512

score 176

ある業務テーブルのプライマリキーを番号体系にしていて、当該テーブルへのレコード挿入時は逐次、番号管理用の別テーブルから番号を採取(1行しかありません)して これを用いる仕様で考えています。
自分が考えたのは以下コーディングです。

新たに番号管理テーブルで番号を採取する(一つ繰り上げる)処理と、今しがた採取した番号を他テーブルに用いる処理が分かれてしまう以上は、他ユーザが同じ操作をしている場合 相応のリスクが伴うのでは??と危惧していますが 間違いありませんか??

一つのトランザクションにしたところで(以下は一つのトランザクションの認識です...)、次のSELECT文で必ず自分が採取した番号をひいてくるとは限らない、この2ステップの間レコードロックをするようなことをしなければならない、と解釈しています。

これは間違いありませんか?
この2ステップ(星印で囲んだ部分)を一まとまりにしてレコードロックするような記述を、PHPではできるのでしょうか?

function initial($BIID) {
    try {

        //DBへ接続    【php_etc/dbconnect.phpに接続先は書いてあります】
        $err_stage = "err#051";
        $db = new ms0connect();
        $conn = $db->dbconnect();
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $conn->beginTransaction();

    //☆★☆★
        $err_stage = "err#052";
        $SQL = "UPDATE ATOZ_FINALSEQ SET FINALSEQ=FINALSEQ + 1 WHERE SYSTEMTYPE='".$BIID."'";
        $conn->exec($SQL);

        $err_stage = "err#053";
        $SQL = "SELECT TOP 1 FINALSEQ FROM ATOZ_FINALSEQ WHERE SYSTEMTYPE='".$BIID."'";
        $stmt=$conn->prepare($SQL);
        $stmt->execute();
    //☆★☆★

        $row = null;
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($row == null) {
            $err_stage = "err#054";
            throw new Exception();
        } else {     
            $appno = substr(strval(1000000000 + $row["FINALSEQ"]),-9);
            $appno = $BIID.$appno;
        }

        $err_stage = "err#055";
        $SQL = "INSERT ATOZ_PLNROUT
        SELECT A.BIID, A.ORNO, A.FIN, '".$appno."' AS WID, A.STID, B.STNAME, A.USEDPT, NULL AS ACTOP FROM V_ATOZ_BIROUT A LEFT OUTER JOIN
        (SELECT STID, MAX(STNAME) AS STNAME FROM V_ATOZ_STAGE GROUP BY STID) B
        ON B.STID=A.STID WHERE A.BIID='".$BIID."'";
        $stmt=$conn->prepare($SQL);
        $stmt->execute();


        $err_stage = "err#056";
        $SQL = "INSERT ATOZ_PLNSTAGE
        SELECT '".$BIID."' AS BIID, '".$appno."' AS WID, A.STID, A.DPTID, A.STNAME, A.USERID, A.SUB, A.USEEXTCON, A.EXTCON FROM V_ATOZ_STAGE A
        WHERE A.STID IN (SELECT DISTINCT STID FROM V_ATOZ_BIROUT WHERE BIID='".$BIID."')";
        $stmt=$conn->prepare($SQL);
        $stmt->execute();

        $conn->commit();
        $err_stage = null;

    } catch (PDOException $e) {
        error_log("### SQL Serverデータ取得失敗 ⇒".$SQL."###".$e->getMessage(),0);
    } catch (Exception $e) {
        error_log("### SQL Serverデータ取得失敗 ⇒".$SQL."###".$e->getMessage(),0);
    }
    $conn = null;
    return $err_stage;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2019/02/07 17:42

    んん?どのような通知が来ましたか?少なくともこの質問には↑のコメントだけですが

    キャンセル

  • saya24

    2019/02/07 17:57

    https://teratail.com/questions/173105 にて「後半追記していますが」との記載でしたので、どこに追記されているのだろう?と模索していたもので。こちらじゃないとすると やはり
    https://teratail.com/questions/173105 のほうへ追記頂いているのですかね??

    キャンセル

  • m.ts10806

    2019/02/07 18:02

    あ、ええ、そうですね。「回答の後半」ですね。言葉足らずでした。
    ただ、そちらにコメントいただく前に元々書いてました

    キャンセル

回答 2

checkベストアンサー

+2

常識的な採番マスタの使い方を教えてください

何が何でも完璧な連番を作らなければならないという特別の必要がない限り、採番マスタを使わず、IDはデータベースの連番機能に任せる、というのが「常識的」な気がします。

SQL Serverの場合、IDENTITYとして利用可能です(MSDN)。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/05 19:57

    いつもご見解をありがとうございます。
    頭がとても固く私の達成したいことに発想を転換できないので、引き続き教えて頂けますでしょうか?

    メインとなるテーブルに採取されるキーは、同一レコードの関連情報を蓄積するその他周囲テーブルにも格納していく考えです。上のコーディングもそう表していますガ、採取したキーはその他テーブルとのデータ結合用に収め、のちのちのデータ結合を容易にしようと考えています。
    こういったことを考えているケースでもDBMS側のキー取得機能に頼るのが一般的でしょうか?

    一気に複数のテーブルへINSERTすることなどできない筈・一トランザクションで複数テーブルの一連を紐付けるためのアイテムが必要。そういう場合の考え方を教えて頂けたら非常に助かります!

    キャンセル

  • 2019/02/05 19:59

    1つ目にinsertしてから、PDO::lastInsertIdでそのIDを取得できます。

    キャンセル

  • 2019/02/05 20:33

    ありがとうございます。ご紹介された技術があること、初めて知りました。良い機能のがあるのですね。これを把握した上での回答だったのですかね、皆さん。
    <https://teratail.com/questions/68723>で紹介された記事をみる限り、同一トランザクションで取得したIDのようで安心できるようですね(決して「直近」という、誰が取得したかも分からないIDではなく)

    キャンセル

-2

idを繰り上げるって発想が常識と離れすぎてて意味が分からない。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/05 19:27

    回答後の質問はご覧にならない方なので、訪問者に誤解がないようマイナスしました。
    idを繰り上げるのではなくauto incrementを自前で実装する話。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • PHPに関する質問
  • PHP 常識的な採番マスタの使い方を教えてください。番号繰上(更新)と採用の手順を一まとめにする方法