2012-07-04

MySQL Workbench の EER モデリングツールでリレーションシップ検証 1 (Identifying と Non identifying)

MySQL Workbench の便利な機能に EER モデリングツールがあります。


MySQL Workbench の EER モデリング例 


EER モデリングツールを使うことによって、データベースの基本設計を行い、それを使って MySQL  データベース本体を生成したり(フォワードエンジニアリング)、既存の MySQL データベースを EER モデリングツールに読み込ませて(リバースエンジニアリング)設計内容を修正した後で再び MySQL データベースに同期(シンクロナイジング)させたりすることができます。

EER モデリングツールの魅力は、何といってもデータベース設計を視覚的に行えるところにあることでしょう。
テーブル定義、列定義はもちろんのこと、テーブルオブジェクトの配置、リレーションシップの設定などもマウスクリックや簡単な入力作業である程度の設計が可能です。

MySQL Workbench は、MySQL の公式サイトからダウンロードできます。

ダウンロード先:MySQL Workbench 5.2


今回より、MySQL Workbench の EER モデリング機能で設定可能なリレーションシップの種類と、その動作の違いについて数回に分けて説明します。

リレーションシップの種類には、一対一、一対多、多対多、自己リレーションなどがありますが、それらの基本的な概念は他のサイトでも多く触れられているため、本記事では省略します。


【Identifying と Non identifying】

EER でリレーションシップ設定を行い、外部キーの設定情報を確認したときに以下のようなチェックボックスが気になった方もいらっしゃるのではないでしょうか。



そこで、今回は、上記のリレーションの外部キー属性となる、identifying と non identifying の違いについて説明します。


Identifying relationship (依存リレーションシップ)--- 子テーブルの外部キーの一部に親テーブルの主キーが組み込まれた形となり、親テーブルなしでは成り立たない関係。


たとえば、ブランド契約で販売する商品が、撤退時に商品の取扱いも同時に終了するように、ブランドテーブルと取扱い商品テーブルを関連づける場合、[商品ID] および[ブランドID] の組み合わせで外部キーを作り、[ブランドID]  が存在しなければその商品は存在し得ないような厳密な設計を行います。



本来、子テーブル側の主キーは一つ([商品ID])ですが、依存型リレーションシップの場合は親テーブル側のIDを識別するための列([ブランドID])も主キー扱いとなりますので、上図のように子テーブルの主キーは二つとなります(どちらも欠かせません)。
 
 EERモデリングでは、identifying リレーションのコネクタは、上図のように実線で表現されます。

 この場合、外部キー設定がされている取扱商品テーブル構成をダンプ(SQL表記)させると、以下のようになります。
 太字表記の部分が今回のチェック項目になりますが、特に赤字の部分に注目してください。[商品ID] および [ブランドID] の両方が主キー となっています。

--
-- Table structure for table `取扱商品`
--

DROP TABLE IF EXISTS `取扱商品`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `取扱商品` (
  `ブランドID` int(11) NOT NULL,
  `商品ID` int(11) NOT NULL AUTO_INCREMENT,
  `商品名` varchar(45) CHARACTER SET utf8 DEFAULT NULL,
  PRIMARY KEY (`商品ID`,`ブランドID`),
  KEY `fk_取扱商品_ブランド` (`ブランドID`),
  CONSTRAINT `fk_取扱商品_ブランド` FOREIGN KEY (`ブランドID`) REFERENCES `ブランド` (`ブランドID`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
SET character_set_client = @saved_cs_client;


Non identifying relationship(非依存リレーションシップ)--- 親テーブルの主キーと子テーブルの外部キーでリレーションシップを構築するが、子テーブルに外部キーとは独立した主キーを持っている関係。


前述のモデルの応用例として、ブランド管理が廃止され商品だけが残った場合にも、在庫商品を処分(販売)できるように、ブランドを問わず商品を管理して扱う場合は、親テーブルが削除された場合にも、子テーブルの商品だけは残して管理できるように設計します。





EERモデリングでは、non-identifying リレーションのコネクタは、上図のように破線で表現されます。


この場合、外部キー設定がされている取扱商品テーブル構成をダンプ(SQL表記)させると、以下のようになります。
太字表記の部分が今回のチェック項目になりますが、特に赤字の部分に注目してください。[商品ID] のみが主キー となっています。
--
-- Table structure for table `取扱商品`
--


DROP TABLE IF EXISTS `取扱商品`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `取扱商品` (
  `ブランドID` int(11) NOT NULL,
  `商品ID` int(11) NOT NULL AUTO_INCREMENT,
  `商品名` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`商品ID`),
  KEY `fk_取扱商品_ブランド` (`ブランドID`),
  CONSTRAINT `fk_取扱商品_ブランド` FOREIGN KEY (`ブランドID`) REFERENCES `ブランド` (`ブランドID`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET character_set_client = @saved_cs_client;



【関連リンク】
MySQL Workbench 基礎講習コース


2012-06-16

『売上猫くん on MySQL』開発日記 - 番外25 - 行ロックについて

小社主催の「FileMaker+MySQL開発の講習」の受講者の方から「FileMakerとMySQLのシステムで、FileMaker(単体システム)のような行ロックってできないの?」との質問を講習前に頂いた。
FileMaker単体のシステムでは、ユーザがあるレコードを編集中に他のユーザが同レコードを編集しようとしても「他のユーザが編集中」旨が表示され、他のユーザは先行するユーザが編集を終了するまで編集することができなくなる。質問の趣旨はこれをFileMaker/MySQLのシステムでも実現したいということ。 
FileMaker標準機能では、FileMaker/MySQL 環境下で排他的行ロックはできない。 が、方法としては2つある。一つはMySQLのロック機能(select for update)を使用する方法(MySQLの排他的行ロック)、もう一つはMySQLテーブルにロックフラグを用意し、最初に編集を開始したユーザがそのフラグに自分のIDを書き込み、後続の他ユーザの編集を禁じるようにごりごりスクリプトで制御方法(FileMaker単体の行ロックと似ているという意味で、FileMakerライクなロック)。 以下はこの2つのロックの実装方法について。

1.MySQLの排他的行ロック
まず、MySQLの排他的行ロック機能を使うと、FileMakerはどのように反応するのか、試してみる。

MySQLコマンドラインで、

  begin;
  select 売上No from 売上ヘッダ where 売上No=1 for update;


を実行する。 次にFileMakerの売上画面で売上No=1のレコードを開いてみると、何事もなく表示される。次にこのレコードの任意のフィールド値を変更してみると普通に変更できる。 さらに、レコードをCommitすると… 出た、必殺のコーヒーマーク! これがMySQLの排他的行ロックである。 ここで、MySQLコマンドラインで、


 commit;


を実行すると、コヒーマークは消えて、レコードがCommitされた。 MySQLの排他的行ロック(select for update)は他ユーザがレコードをselectすることを妨げず、よってFileMakerのレイアウト上にも表示される。 また一旦表示されたレコードは、他のユーザが編集していたとしても、後発ユーザの編集を妨げるよなFileMaker的ロックは行われない。 しかし、いざCommitを実行しようとすると、コーヒーマックが出て、select for update を実行したユーザのトランザクションがCommitかRollbackされるまで、コヒーマークが出たまま、つまりロックされた状態となる。
【FileMakerとMySQLコマンドライン】
select ~ for update 後にFMで編集→確定ボタンすると、コーヒーカップが… 
注:
通常、ロックが発生から60秒後に、「[MySQL][ODBC 5.1 Driver][mysqld-5.1.58-community]Lock wait timeout exceeded; try restarting transaction」というエラーが返る。レコード確定ステップ実行後に後処理がある場合は、このエラーをトラップして処理を中止するなど適切な処理を行わないと、システムが暴走する可能性があるので要注意
FileMakerからも「SQLを実行」スクリプトステップに上記内容を直書きしたり、ストアドプロシージャをCALLすれば、ロックやトランザクションを利用できる。試しに


BEGIN
start transaction;
 select * from 売上ヘッダ where 売上No=1 for update;
 select sleep(60);
 rollback;
END;


というストアドプロシージャを作成して、「SQLを実行」ステップからこれをCALLしてみる。 問題なく実行でき、結果、60秒の間そのレコードは更新できなくなる。しかし 「SQLを実行」 ステップはクライアントPCにDSN登録がないと実行できない、という問題があるため、FileMakerからMySQLトリガを発生させてストアドを実行したい(この方法については『売上猫くん on MySQL』開発日記 - 3 - FMからストアド、トリガを参照)。 ということでトリガから上記のストアドを実行しようとすると、「 Not allowed to return a result set from a trigger」というエラーが出るので、レコードセットが返らないように下記のようにストアドを書きなおした。

BEGIN
    declare temp int;
    start transaction;
        select Count(*) into temp from 売上ヘッダ where  売上No =1 for update;
        select sleep (60) into temp;
        update appliasons set ret="OK" where ID=appId;
    commit;
END
ところが残念なことが重なる。今度は「Explicit or implicit commit is not allowed in stored function or trigger.」というエラーが返ってくる。 これでMySQLのトリガではトランザクションが使用できないことがわかった。まえに小生が書いた記事『売上猫くん on MySQL』開発日記 - 番外12 - トリガの制約に、この件をちらっと書いていた(恥)。 
結論としては、ストアドを直接実行すればMySQLのロックを実行できるが、トリガを介したストアド実行によるロックは不可、ということになる。

尚、FM12の新関数ExecuteSQL関数では、MySQLのロックは利用できない(つか、この関数、相当中途半端な上、意味不明なクエリを発する。書いた通りの動きをしないこともあるし…。この辺りは後日機会があれば)。


2.FileMakerライクなロック
次にFileMakerライクなロック。これは開発者が自分でゴリゴリ書かなくてはならないのでかなり面倒だ。 以下は小社のFileMaker/MySQL講習テキストから実装方法を引用する。
【実装】
“編集”ボタンを用意し、レコードを変更する必要があるユーザには“編集”ボタンを実行して「編集モード」にすることを義務付ける。編集モードでなければレコードの変更は実行できないよう制御するとともに、“編集”ボタン実行時には、当該レコードのロックフラグフィールド(cntLockId)にユーザ固有のIDをセット。このフラグが解除されない間は他ユーザが当該レコードの変更を行えないように制御。ユーザがレコードの更新を終えCommitした瞬間にこのロックフラグフィールドを解除するように設計する。
名称
種類
仕様
cntLockId
フィールド
(
テキスト)
編集ボタンを実行するとこのフィールドにユーザ固有のID=Get ( 持続 ID )が入力され、このIDを持たない他ユーザは編集不可となる。 
cntLockTiime
フィールド
(
タイムスタンプ)
編集ボタン実行時に[cntLockId]とともに本フィールドにはサーバのタイムスタンプ(現日時)が入力される。 このタイムスタンプによりデッドロックになっていないかを判断し、管理者は適切な処理をおこなう。
cntLockAC
フィールド
(
テキスト)
必要に応じて作成。編集ボタン実行時にGet ( アカウント名 )が入力される。 これを利用すれば、編集実行者を画面上に表示することができる。
(ユーザが手入力可能なフィールド)
フィールド
OnObjectEnterスクリプトトリガを用いて、[cntLockId<> Get ( 持続 ID )の場合は、フィールドに入れない(フィールド値を変更できない)ように制御。
編集
ボタン
上記のcntLockId/ cntLockTiime/ cntLockAC参照。左記3フィールドに値を入力後にレコードを確定する。これによりそのレコードは他ユーザによる編集が不可となる。
確定
ボタン
上記のcntLockId/ cntLockTiime/ cntLockACの値をクリア(ロックを解除)後、レコードを確定する。
復帰
ボタン
デッドロックしないよう([cntLockId]の値が残らない)ように制御。
他のボタン
ボタン
削除ボタン、削ボタン(売上明細削除用)など、当該レコードを変更する可能性があるボタン、スクリプトは[cntLockId]に他ユーザのIDがある場合は、実行出来ないように制御する。

【編集ボタンによるFileMakerライクなロック】

[cntLockId]と同じGet(持続ID)を持つユーザのみが編集可となり、確定ボタンが完了すると[cntLockId][cntLockTime][cntLockAC]はnullとなり、他のユーザも編集可能となる。


注:
サーバのRemote Desktop Service を介して複数人でFileMakerを使用する場合、Get(持続ID)は重複すると思われる。この場合、他の方法で個別IDを取得すること。

(土屋)

2012-06-08

SQL関連記事と『売上猫くん on MySQL』開発日記の一覧








【FileMaker/MySQL環境での大容量データ取扱(英語のみ/動画による実例あり)】
Big Table Handling Model in FileMaker/MySQL Environment ― Tentative one
FileMaker vs Access 実行速度比較検証


【FMEasy在庫 on MySQL関連】
『FMEasy在庫』 のバックエンドを MySQL に変える (1) ― 概要
『FMEasy在庫』 のバックエンドを MySQL に変える (2) ― 在庫1
 


【その他のFileMaker/MySQL関連】
 ファイル起動時にFileMakerからMySQLに投げられるクエリ



【MySQL Workbench関連】
MySQL Workbench の EER モデリングツールでリレーションシップ検証 1 (Identifying と Non identifying)
MySQL Workbench の EER モデリングツールでリレーションシップ検証 2 (外部キー制約の種類と動作)

MySQL Workbench の EER モデリングツールでリレーションシップ検証 3 (リレーションシップアイコンの種類と使い方)
 



【売上猫くん開発日記 ― 番外編】
番外1 -全データベース削除→リストア
番外2 - MySQLミラーサイト
番外3 - 0を書き込みできない
番外4 - mysqldump で文字化け?
番外5 - ポータルで検索できない
番外6 - リモートのログを mysqlbinlog できない
番外7 - FileMaker内にMySQLの一般ログを表示する
番外8 - insert...select構文とODBC
番外9 - 外部キー制約設定でのたうちまわる
番外10 - 開発再開
番外11 - 外部キー ってさぁ… orz
番外12 - トリガの制約
番外13 - MySQL Workbenchの憂鬱(ほぼ私的メモ)
番外14 - テーブル毎に権限を設定する(ほぼ私的メモ)
番外15 - 再び権限(私的メモ)
番外16 - FMで大きなSQLテーブルは扱えるのか? ― その1
番外17 - FMで大きなSQLテーブルは扱えるのか? ― その2
番外18 - FMで大きなSQLテーブルは扱えるのか? ― その3
番外19 - FMで大きなSQLテーブルは扱えるのか? ― その4
番外20 - ウィンドウ内容の再表示ステップ実行時のクエリ
番外21 - βリリースしまつた
番外22 -SQL SECURITY の DEFINER/INVOKER指定
番外23 - FileMaker vs Access ~ 実行速度編 ~
番外24 - MySQL 5.5は使用できるのか?
番外25 - 行ロックについて


【売上猫くん開発日記 ― 本篇】(←メインになる筈が、見捨てられた哀れな本編)
1 (題目無)
2 - 開発環境
3 - FMからストアド、トリガ