我正在做一个Yii项目,如何使用MySQL(http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html)的ON DUPLICATE功能在Yii模型上执行保存()?
我的MySQL如下:
CREATE TABLE `ck_space_calendar_cache` (
`space_id` int(11) NOT NULL,
`day` date NOT NULL,
`available` tinyint(1) unsigned NOT NULL DEFAULT '0',
`price` decimal(12,2) DEFAULT NULL,
`offer` varchar(45) DEFAULT NULL,
`presale_date` date DEFAULT NULL,
`presale_price` decimal(12,2) DEFAULT NULL,
`value_x` int(11) DEFAULT NULL,
`value_y` int(11) DEFAULT NULL,
PRIMARY KEY (`space_id`,`day`),
KEY `space` (`space_id`),
CONSTRAINT `space` FOREIGN KEY (`space_id`) REFERENCES `ck_space` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我的PHP是一个如下:
$cache = new SpaceCalendarCache();
$cache->attributes = $day; //Some array with attributes
$cache->save();
如果我的主键(sapce_id,day)中有重复项,我不希望它抱怨,我只希望它用最新的数据更新。
我知道如何在原始SQL中做它,我只是想知道是否有一个干净的Yii方式来做它。
7条答案
按热度按时间vm0i2vca1#
您正在使用Yii中的模型,它很简单..尝试加载您的模型,你怀疑有重复的条目,如果你找到的条目,模型被加载,否则返回null.现在,如果您的模型为null,只需创建新的模型.
请参考示例应用Yii博客中的post controllers更新方法。我可能对函数名称的拼写有错误,很抱歉。
o2g1uqev2#
我在此重复之前回答中的两个要点,我认为您应该保留:
1.正如txyoji指出的那样,不要(尝试)使用“on duplicate key update”,因为它只适用于MySQL。
1.更喜欢没有发现的
select->if
,而不是Uday Sawant演示的insert->else
插入。不过,这里还有一点:虽然对于低流量的应用程序,遇到麻烦的可能性是最小的(仍然不会为零),但我认为我们总是要小心这一点。
从事务性的Angular 来看,
"INSERT .. ON DUPLICATE UPDATE"
并不等同于选择应用程序的内存,然后插入或更新。下面是一个糟糕的场景:
1.您确实使用
findByPk()
选择了记录,这将返回空值1.其他某个事务(来自其他某个用户请求)插入了一个记录,该记录具有您刚才未能选择的ID
1.下一瞬间你又试着把它插入
在这种情况下,你要么会得到一个异常(如果你使用的是一个唯一键,就像这里所做的那样),要么会得到一个重复的条目。重复的条目很难被发现(通常在你的用户看到重复的记录之前,没有什么是奇怪的)。
这里的解决方案是设置一个严格的隔离级别,例如“serializable”,然后开始一个事务。
这里有一个yii的例子:
您至少可以在以下链接中看到有关隔离级别的更多信息,并了解每种隔离级别在数据完整性方面提供了什么以换取并发性
http://technet.microsoft.com/en-us/library/ms173763.aspx
http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
xoshrz7s3#
我重写了beforeValidate(),检查是否存在重复项。如果存在,则设置
$this->setIsNewRecord(false);
看起来很有效,不确定它的性能如何。
mzillmmw4#
“On Duplicate Key Update”特性是MySQL特有的SQL方言。它不太可能在任何数据抽象层中实现。ZendDB和Propel没有等价的特性。
您可以尝试在try/catch中插入,并在插入失败并显示正确的错误码(重复索引键错误)时进行更新,以仿真此行为。
2wnc66cl5#
我同意@txyoji对这个问题的分析,但我会使用不同的解决方案。
您可以扩展模型的
save()
方法来查找现有记录,并更新它,或者如果没有,则插入新行。brjng4g36#
您必须像这样使用try catch:
ifsvaxew7#
不好意思...这是yii2的答案
如果你不使用yii模型,这个函数会在重复键更新时生成mysql语法插入。
将该函数放入某个可重用的类中,并且不要忘记使用
在那个班级
该函数可以在关键字更新时插入、更新增量、更新减量、从值更新多个值以及从选择更新
用法: