大家好,StackOverflow中的每个人,我都是这个网站的粉丝,帮助我摆脱了无数的困境。但是这次我似乎没有在这里或其他任何地方找到答案,我的问题是:
我正在开发一个Yii框架应用程序来处理数据库中的数据,保持一致性和一切。基本上,我正在创建一个用于操纵数据库信息的界面。我正在使用MySQL 5.0(预定更新到5.5)和InnoDB。
我的开发工作将支持已经存在的架构(我将其称为 main ),这有几个设计问题。我们的目标是用一个新的,正确设计的模式替换旧模式(我称之为阴影)。但与此同时,我们正在尝试将新模式实现为主模式的影子模式,并通过触发器保持变化一致。
对影子架构进行了所有重要更改,影子架构使用触发器将其反映到主架构。两个模式都托管在同一个服务器中,并且只要通过命令行客户端或使用MySQL Workbench进行更改,触发器就能很好地反映从shadow到main的数据更改,但每当我使用我的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(与两个数据库模式托管在同一服务器中)发送时触发。我见过以下内容:
MySQL触发器仅由SQL语句激活。它们不会被不会将SQL语句传输到MySQL服务器的API所做的更改激活;特别是,它们不会被使用NDB API进行的更新激活。
非常感谢任何帮助或指南。提前谢谢。
编辑:Yii使用PDO执行插入/更新语句,并且插入成功反映,更新仍然失败。
答案 0 :(得分: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更新时,New.LastUpdated <> Old.LastUpdated
似乎都是假的,但每当从CLI或WorkBench更新时都是如此。因为在Yii应用程序上我没有收到tbl_device.LastUpdated的输入(我期待MySQL为我做这个工作,现在我觉得有点愚蠢,我可以使用beforeSave()
方法更正时间戳字段我用来验证是否实际对记录进行了更改...)
答案 1 :(得分:0)
首先:尝试使用yii应用程序使用的相同mysql用户从console / workbench进行调试。
Yii仍然使用常规SQL语句,而不是您引用的文档中提到的api调用。
继续并输入config / main.php文件
components / db section:
'enableParamLogging' => true
和components / log部分:
'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
另外,在更新主要触发器更新阴影触发器更新主触发器更新阴影触发器时,你确定你没有进入无限循环....?