Nat*_*n H 7 php mysql yii on-duplicate-key yii-cmodel
我正在开发一个Yii项目.在Yii模型上执行save()时,如何使用MySQL的ON DUPLICATE功能(http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html)?
我的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;
Run Code Online (Sandbox Code Playgroud)
我的PHP是如下:
$cache = new SpaceCalendarCache();
$cache->attributes = $day; //Some array with attributes
$cache->save();
Run Code Online (Sandbox Code Playgroud)
如果我的主键(sapce_id,day)中有重复项,我不希望它抱怨,我只是希望它使用最新数据进行更新.
我知道如何在原始SQL中执行它,我只是想知道是否有一个干净的Yii方法来做它.
Uda*_*ant 14
你正在使用Yii中的模型,它非常简单..尝试加载你怀疑有重复条目的模型,如果你发现模型被加载的条目,则返回null.现在,如果您的模型为null,则只需创建新模型.rest是插入新记录的常规代码.
//try to load model with available id i.e. unique key
$model = someModel::model()->findByPk($id);
//now check if the model is null
if(!$model) $model = new someModel();
//Apply you new changes
$model->attributes = $attributes;
//save
$model->save();
Run Code Online (Sandbox Code Playgroud)
请参阅示例应用程序Yii博客中的post controllers update方法.对于函数名称的拼写我可能有问题,对不起.
我重复以前的答案中的两个要点,我认为你应该保留:
txyoji指出,不要(尝试)使用"重复密钥更新",因为它只支持MySQL.
喜欢Uday Sawant所展示的
select->if未找到的insert->else插入物.
不过,这里还有另外一点:并发.虽然对于流量较低的应用程序,您遇到麻烦的可能性很小(仍然不会为零),我想我们总是要小心这一点.
从事务的角度来看,"INSERT .. ON DUPLICATE UPDATE"并不等同于选择应用程序的内存然后插入或更新.第一个是单个交易,第二个不是.
这是一个糟糕的情况:
- 您选择使用
findByPk()哪个记录返回null- 某些其他事务(来自其他一些用户请求)会插入一条记录,其中包含您未能选择的ID
- 在下一瞬间,您尝试再次插入它
在这种情况下,您将获得一个例外(如果您使用唯一键,就像您在这里一样)或重复条目.重复的条目更难以获取(在用户看到重复记录之前,通常没什么好看的).
这里的解决方案是设置严格的隔离级别,例如"serializable",然后开始一个事务.
这是yii的一个例子:
Yii::app()->db->createCommand('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
$trn = Yii::app()->db->beginTransaction();
try {
// Try to load model with available id i.e. unique key
// Since we're in serializable isolation level, even if
// the record does not exist the RDBMS will lock this key
// so nobody can insert it until you commit.
// The same shold for the (most usual) case of findByAttributes()
$model = someModel::model()->findByAttributes(array(
'sapce_id' => $sapceId,
'day' => $day
));
//now check if the model is null
if (!$model) {
$model = new someModel();
}
//Apply you new changes
$model->attributes = $attributes;
//save
$model->save();
// Commit changes
$trn->commit();
} catch (Exception $e) {
// Rollback transaction
$trn->rollback();
echo $e->getMessage();
}
Run Code Online (Sandbox Code Playgroud)
您可以在以下链接中看到有关隔离级别的更多信息,并查看每个隔离级别在数据完整性方面提供的内容以换取并发性
http://technet.microsoft.com/en-us/library/ms173763.aspx
http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
我重写了 beforeValidate() ,检查是否存在重复项。如果有人这样做,我设置$this->setIsNewRecord(false);
似乎有效。不确定它的性能如何。
| 归档时间: |
|
| 查看次数: |
30621 次 |
| 最近记录: |