2012-10-29 36 views
2

大家好,我是StackOverflow的粉丝,帮助我摆脱了无数的坑。但是这次我似乎没有在这里或其他地方找到答案,我的问题是这样的:我正在开发一个Yii框架应用程序来处理数据库中的数据,保持一致性和一切。基本上,我正在创建一个处理数据库信息的界面。我正在使用MySQL 5.0(定时更新到5.5)和InnoDB。触发器没有被Yii应用程序激活

我的开发即将支持已经存在的模式(我将其称为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.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(与两个DB模式托管在同一服务器中)发送时触发。我已经看到了以下内容:

MySQL 5.0 documentation

MySQL的触发器仅SQL语句激活。它们不会被API所做的表中的更改所激活,这些API不会将SQL语句传送到MySQL服务器;特别是,它们不会被使用NDB API进行的更新激活。

任何帮助或指导是高度赞赏。提前致谢。

编辑: Yii使用PDO来执行插入/更新语句,并且插入被成功反映,更新仍然失败。

回答

0

首先:尝试使用yii应用程序使用的相同mysql用户从控制台/工作台调试它。

Yii仍然使用常规SQL语句,而不是您引用的文档中提到的api调用。

继续,并把你的配置/主。PHP文件

组件/ DB部分:

'enableParamLogging' => true 

和组件/测井部分:

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

,然后看SQL命令在保护/运行/ db.log得到执行

$ tail -f db.log 

另外,你确定你没有进入无限循环这里更新主触发updati ng阴影触发器更新主触发器更新阴影触发器....?

+0

使用同一用户进行调试:它在工作台上工作,它从命令行cliend运行,它不能从yii工作。 我不熟悉那个unix(是它的unix?)命令,但我手动检查db.log,发现很多select查询(对应于fk参考验证等,一切顺利)... – Snivs

+0

只有更新日志中的行是这样的: '2012/10/29 23:46:38 [trace] [system.db.CDbCommand]执行SQL:UPDATE“tbl_device”SET“Id”=:yp0,“SerialNumber”= :yp1,“State”=:yp2,“ProviderId”=:yp3,“OwnerId”=:yp4,“ProfileId”=:yp5,“ChipId”=:yp6,“IMEI”=:yp7,“ModelNumber”=: yp8,“FirstUsed”=:yp9,“Brand”=:yp10,“Agreement”=:yp11,“LastUpdated”=:yp12 WHERE“tbl_device”。“Id”= 670。绑定:yp0 = 670,:yp1 ='ADSF564ASD9F132CX1',::yp2 ='ReciénLlegado',:yp3 = 12,:yp4 = 5,:yp5 = NULL,:yp6 = 11,:yp7 ='123',: yp8 ='AD3F48C135',:yp9 = NULL,:yp10 ='Skywave',::yp11 ='没有Establecido',::yp12 ='2012-10-29 15:33:37'' – Snivs

+0

而且没有其他重要行,只需选择验证和相关的记录格式显示。这些更改没有反映到主模式,所以我猜'shadow.tbl_device'上的'shadow.trg_device_after_update_reflect_changes'显然没有激活.. – Snivs

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$$ 

好像New.LastUpdated <> Old.LastUpdated是假的,只要从Yii的更新,但从CLI或WorkBench更新时为true。因为在Yii应用程序上,我没有收到tbl_device.LastUpdated的输入(我期待MySQL为我完成这项工作,现在我觉得有点笨,我可以使用beforeSave()方法更正它,以更新时间戳字段我用于验证是否对记录进行了实际更改......)

+2

很好的捕获。请查看[CTimestampBehavior](http://www.yiiframework.com/doc/api/1.1/CTimestampBehavior)了解如何填充时间戳字段。 –