2

StackOverflow の皆さん、こんにちは。私はこのサイトのファンで、数え切れないほどの穴から助けてくれました。しかし、今回はここでも他の場所でも答えが見つからないようです。私の問題は次のとおりです。

データベース内のデータを処理し、一貫性とすべてを維持するための Yii Framework アプリケーションを開発しています。基本的には、DB 情報を操作するためのインターフェイスを作成しています。MySQL 5.0 (5.5 への更新予定) と InnoDB を使用しています。

私の開発は、いくつかの設計上の問題がある既存のスキーマ (私はそれをmainと呼びます) をサポートしようとしています。古いスキーマを、適切に設計された新しいスキーマに置き換えることを目指しています (これをshadowと呼びます)。しかし当面は、新しいスキーマをメインのスキーマのシャドウ スキーマとして実装し、トリガーを介して変更の一貫性を維持しようとしています。

重要な変更はすべてシャドウ スキーマに対して行われ、トリガーを使用してメイン スキーマに反映されます。両方のスキーマは同じサーバーでホストされており、トリガーは、コマンド ライン クライアントまたは MySQL Workbench を使用して変更が行われるたびに、データの変更をシャドウからメインに反映してうまく機能しますが、Yii アプリケーションを使用してデータをシャドウするために変更を加えると、...変更はシャドウ スキーマに対してのみ行われ、メイン スキーマには反映されません。

これはshadow.tbl_deviceの説明であり、DDL をトリガーします。

mysql> use shadow;
mysql> describe tbl_device;
+--------------+-------------+------+-----+-------------------+-----------------------------+
| Field        | Type        | Null | Key | Default           | Extra                       |
+--------------+-------------+------+-----+-------------------+-----------------------------+
| Id           | int(11)     | NO   | PRI | NULL              | auto_increment              |
| SerialNumber | varchar(40) | NO   |     | NULL              |                             |
| State        | varchar(20) | NO   | MUL | Recién Llegado    |                             |
| ProviderId   | int(11)     | NO   | MUL | NULL              |                             |
| OwnerId      | int(11)     | NO   | MUL | NULL              |                             |
| ProfileId    | int(11)     | YES  | MUL | NULL              |                             |
| ChipId       | int(11)     | YES  | UNI | NULL              |                             |
| IMEI         | varchar(15) | YES  |     | NULL              |                             |
| ModelNumber  | varchar(20) | YES  |     | NULL              |                             |
| FirstUsed    | date        | YES  |     | NULL              |                             |
| Brand        | varchar(45) | NO   | MUL | No Definida       |                             |
| Agreement    | varchar(20) | NO   | MUL | No Establecido    |                             |
| LastUpdated  | timestamp   | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+--------------+-------------+------+-----+-------------------+-----------------------------+
13 rows in set (0.01 sec)

-- Trigger DDL Statements

USE `shadow`$$

CREATE
DEFINER=`root`@`localhost`
TRIGGER `shadow`.`trg_device_after_insert_produce_location_and_register_device`
AFTER INSERT ON `shadow`.`tbl_device`
FOR EACH ROW
BEGIN
    DECLARE NumCel VARCHAR(10) DEFAULT NULL;
    INSERT INTO tbl_location(DeviceId) values (New.Id);
    IF New.ChipId IS NOT NULL THEN
        SELECT CONCAT(AreaCode,Phone) INTO NumCel FROM tbl_chip WHERE Id = New.ChipId;
    END IF;

    IF New.Brand = 'Navcel' THEN
        INSERT INTO navcel.detalle_aplicacion(apId, pdRadioId, adActivo) values (1,CAST(New.SerialNumber as UNSIGNED), 1);
    END IF;
    IF New.Brand = 'Calamp' Then
        INSERT INTO main.equipos(eqId,eqNumCel,shadowDeviceId) values (CONV(SUBSTRING(New.SerialNumber,-6),16,10),NumCel,New.Id);
    ELSE
        INSERT INTO main.equipos(eqId,eqNumCel,shadowDeviceId) values (CAST(New.SerialNumber as UNSIGNED),NumCel,New.Id);
    END IF;
END$$

CREATE
DEFINER=`root`@`localhost`
TRIGGER `shadow`.`trg_device_after_update_reflect_changes`
AFTER UPDATE ON `shadow`.`tbl_device`
FOR EACH ROW
BEGIN
    DECLARE acuerdo TINYINT(4);
    DECLARE NumCel VARCHAR(10);
    DECLARE eqIdToUpdate INT;
    IF New.LastUpdated <> Old.LastUpdated THEN
        /* UPDATING THE REFLECTION OF THIS DEVICE IN THE main SCHEMA */
        IF New.Agreement = 'Renta' THEN set acuerdo := 1;
            ELSEIF New.Agreement = 'Venta' THEN set acuerdo := 2;
            ELSEIF New.Agreement = 'Prestamo' THEN set acuerdo := 3;
            ELSE set acuerdo := 0;
        END IF;
        IF New.ChipId IS NULL THEN 
            SET NumCel = NULL;
        ELSE 
            Select CONCAT(AreaCode,Phone) INTO NumCel FROM tbl_chip WHERE Id = New.ChipId;
        END IF;
        UPDATE main.equipos SET 
            eqId := New.SerialNumber,
            eqInstalado := 1,
            eqAcuerdo := acuerdo,
            eqNumCel := NumCel
        WHERE shadowDeviceId = New.id;
    END IF;
END$$

DDL のトリガーは、main への変更を反映するためのトリガーです。main.equiposの説明は次のとおりです (現在、トリガーは使用されていません)。

+-----------------------+------------------+------+-----+---------+-------+
| Field                 | Type             | Null | Key | Default | Extra |
+-----------------------+------------------+------+-----+---------+-------+
| eqId                  | int(10) unsigned | NO   | PRI | 0       |       |
| shadowDeviceId        | int(11)          | YES  | UNI | NULL    |       |
| eqNumCel              | varchar(20)      | YES  |     | NULL    |       |
| stId                  | int(10) unsigned | NO   |     | 0       |       |
| TIPO_EQUIPOS_tpId     | int(10) unsigned | YES  |     | NULL    |       |
| eqNombre              | varchar(100)     | YES  |     | NULL    |       |
| eqNUI                 | varchar(50)      | YES  |     | NULL    |       |
| eqModelo              | varchar(20)      | YES  |     | NULL    |       |
| eqPlacas              | varchar(20)      | YES  |     | NULL    |       |
| eqLatitud             | decimal(9,6)     | YES  |     | NULL    |       |
| eqLongitud            | decimal(9,6)     | YES  |     | NULL    |       |
| eqAltitud             | float            | YES  |     | NULL    |       |
| eqSatelite            | varchar(20)      | YES  |     | NULL    |       |
| eqFechaActEq          | datetime         | YES  |     | NULL    |       |
| eqFechaActSer         | datetime         | YES  |     | NULL    |       |
| eqNivelGPRS           | float            | YES  |     | NULL    |       |
| eqIcono               | varchar(200)     | YES  |     | NULL    |       |
| eqTiempoRep           | datetime         | YES  |     | NULL    |       |
| eqVersion             | varchar(20)      | YES  |     | NULL    |       |
| eqLatDinGeo           | float            | YES  |     | NULL    |       |
| eqLonDinGeo           | float            | YES  |     | NULL    |       |
| eqTiempoGeo           | datetime         | YES  |     | NULL    |       |
| eqNumEconomico        | varchar(20)      | YES  |     | NULL    |       |
| eqNumPedido           | varchar(20)      | YES  |     | NULL    |       |
| eqVelocidad           | int(10)          | YES  |     | NULL    |       |
| eqNumSerie            | varchar(45)      | YES  |     |         |       |
| EsGeocercaId          | int(10) unsigned | YES  |     | NULL    |       |
| eqPuntoCercano        | int(10)          | NO   |     | 1       |       |
| eqDistanciaCercano    | float            | NO   |     | 0       |       |
| eqIconoActual         | varchar(100)     | NO   |     | 0       |       |
| eqStatusDBS           | varchar(45)      | YES  |     |         |       |
| eqTieneDBS            | int(1)           | NO   |     | 1       |       |
| eqFechaDBS            | datetime         | YES  |     | NULL    |       |
| eqEnAlarma            | tinyint(1)       | NO   |     | 0       |       |
| eqTipoMascara         | int(11)          | NO   |     | 1       |       |
| eqAdvComunicacion     | int(11)          | NO   |     | 120     |       |
| eqFallaComunicacion   | int(11)          | NO   |     | 300     |       |
| eqStComs              | int(11)          | YES  |     | 0       |       |
| eqCiudadCercana       | int(11)          | YES  |     | NULL    |       |
| eqDistCiudadCercana   | float(11,0)      | YES  |     | NULL    |       |
| eqUsaGeocercaDinamica | int(1)           | NO   |     | 0       |       |
| eqUcStatus            | tinyint(4)       | NO   |     | 0       |       |
| eqOdometro            | float            | NO   |     | 0       |       |
| eqBoletin             | int(11)          | YES  |     | 0       |       |
| eqPaseSalida          | int(11)          | YES  |     | 0       |       |
| eqMedioTx             | varchar(20)      | YES  |     | 0       |       |
| eqDigInputs           | int(11)          | YES  |     | 0       |       |
| eqFechaActEqLocal     | datetime         | YES  |     | NULL    |       |
| eqLatitudCruda        | decimal(9,6)     | YES  |     | NULL    |       |
| eqLongitudCruda       | decimal(9,6)     | YES  |     | NULL    |       |
| eqVelocidadCruda      | int(11)          | YES  |     | NULL    |       |
| eqIconoWeb            | varchar(20)      | YES  |     | car     |       |
| eqUsaAnalogicas       | tinyint(4)       | NO   |     | 0       |       |
| eqInstalado           | tinyint(4)       | YES  |     | 0       |       |
| eqAcuerdo             | tinyint(4)       | YES  |     | NULL    |       |
| idEntidad             | int(11)          | YES  |     | NULL    |       |
| eqFallaECM            | tinyint(4)       | YES  |     | 0       |       |
+-----------------------+------------------+------+-----+---------+-------+

この表 (トリガーによって参照される) も関連性があると思います。

mysql> describe shadow.tbl_chip;
+--------------+-------------+------+-----+---------+----------------+
| Field        | Type        | Null | Key | Default | Extra          |
+--------------+-------------+------+-----+---------+----------------+
| Id           | int(11)     | NO   | PRI | NULL    | auto_increment |
| ProviderId   | int(11)     | NO   | MUL | NULL    |                |
| OwnerId      | int(11)     | YES  | MUL | NULL    |                |
| ChipState    | varchar(15) | NO   | MUL | Nuevo   |                |
| AreaCode     | varchar(3)  | NO   |     | NULL    |                |
| Phone        | varchar(7)  | NO   |     | NULL    |                |
| SerialNumber | varchar(45) | NO   |     | NULL    |                |
| PIN          | varchar(4)  | YES  |     | NULL    |                |
| PUK          | varchar(45) | YES  |     | NULL    |                |
+--------------+-------------+------+-----+---------+----------------+
9 rows in set (0.02 sec)

したがって、基本的に...トリガーは、クエリがコマンドライン/mysql-workbench 経由で送信されるたびに起動しますが、yii (2 つの DB スキーマと同じサーバーでホストされている) 経由で送信されるときはいつでも起動しません。私は以下を見てきました:

MySQL 5.0 のドキュメントによると

MySQL トリガーは、SQL ステートメントによってのみアクティブ化されます。これらは、SQL ステートメントを MySQL サーバーに送信しない API によって行われたテーブルの変更によってアクティブ化されません。特に、NDB API を使用して行われた更新によってアクティブ化されません。

ヘルプやガイドラインは大歓迎です。前もって感謝します。

編集: Yii は PDO を使用して挿入/更新ステートメントを実行し、挿入は正常に反映されますが、更新は引き続き失敗します。

4

2 に答える 2

1

私が使用しAFTER UPDATEているトリガーには、トリガー内で変更が行われないようにする句があります(実際には常に起動されます)。

CREATE
DEFINER=`root`@`localhost`
TRIGGER `shadow`.`trg_device_after_update_reflect_changes`
AFTER UPDATE ON `shadow`.`tbl_device`
FOR EACH ROW
BEGIN
    DECLARE acuerdo TINYINT(4);
    DECLARE NumCel VARCHAR(10);
    DECLARE eqIdToUpdate INT;
    IF New.LastUpdated <> Old.LastUpdated THEN
        ...
    END IF;
END$$

Yiiから更新する場合は常にfalseのようNew.LastUpdated <> Old.LastUpdatedに見えますが、CLIまたはWorkBenchから更新する場合は常にtrueです。Yiiアプリケーションでは、tbl_device.LastUpdatedの入力を受け取らないため(MySQLがこのジョブを実行することを期待していましたが、今は少し馬鹿げていると感じています。使用してbeforeSave()いるタイムスタンプフィールドを更新するメソッドを使用して修正できます。レコードに実際に変更が加えられたかどうかを検証するには...)

于 2012-10-30T00:29:35.823 に答える
0

まず、あなたの yii アプリが使用しているのと同じ mysql ユーザーで、コンソール/ワークベンチからデバッグしてみてください。

Yii は、参照したドキュメントに記載されている API 呼び出しではなく、通常の SQL ステートメントを引き続き使用します。

config/main.php ファイルに入力してください

components/db セクション:

'enableParamLogging' => true

コンポーネント/ログセクション:

    'log' => array(
        'class' => 'CLogRouter',
        'routes' => array(
            array(
                'class'=>'CFileLogRoute',
                'levels'=>'trace,log',
                'categories' => 'system.db.CDbCommand',
                'logFile' => 'db.log',
            ),
        ),
    ),

次に、protected/runtime/db.log で SQL コマンドが実行されるのを確認します。

$ tail -f db.log

また、メイン トリガーの更新 シャドウ トリガーの更新 メイン トリガーの更新 シャドウ トリガーの更新の際に、ここでエンドレス ループに陥っていませんか?

于 2012-10-29T20:45:05.893 に答える