Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP红豆存储bean(如果不存在)_Php_Mysql_Database_Orm_Redbean - Fatal编程技术网

PHP红豆存储bean(如果不存在)

PHP红豆存储bean(如果不存在),php,mysql,database,orm,redbean,Php,Mysql,Database,Orm,Redbean,我有点困惑。我在我的直邮服务中积极地使用PHP RedBean作为ORM,我遇到了一个奇怪的情况——我有一个具有唯一键约束(即订户id、传递id)的表和两个将数据写入该表的脚本。 有正在插入或更新表的源代码: public static function addOpenPrecedent($nSubscriberId, $nDeliveryId) { $oOpenStatBean = \R::findOrDispense('open_stat', 'delivery_id = :did

我有点困惑。我在我的直邮服务中积极地使用PHP RedBean作为ORM,我遇到了一个奇怪的情况——我有一个具有唯一键约束(即订户id、传递id)的表和两个将数据写入该表的脚本。 有正在插入或更新表的源代码:

public static function addOpenPrecedent($nSubscriberId, $nDeliveryId)
{
    $oOpenStatBean = \R::findOrDispense('open_stat', 'delivery_id = :did AND subscriber_id = :sid', array(':did' => $nDeliveryId, ':sid' => $nSubscriberId));

    $oOpenStatBean = array_values($oOpenStatBean);
    if (1 !== count($oOpenStatBean)) {
        throw new ModelOpenStatException(
            "Ошибка при обновлении статистики открытий: пара (delivery_id,
            subscriber_id) не является уникальной: ($nDeliveryId, $nSubscriberId).");
    }

    $oOpenStatBean = $oOpenStatBean[0];
    if (!empty($oOpenStatBean->last_add_dt)) {
        $oOpenStatBean->precedent++;
    } else {
        $oOpenStatBean->delivery_id   = $nDeliveryId;
        $oOpenStatBean->subscriber_id = $nSubscriberId;
    }

    $oOpenStatBean->last_add_dt = time('Y-m-d H:i:s');
    \R::store($oOpenStatBean);
}

它从两个脚本中同时调用。我周期性地对这个表的唯一约束有问题,因为竞争条件会发生。我知道SQL“重复密钥更新时插入”功能。但是,我怎样才能纯粹使用ORM获得相同的结果呢?

我知道如果Redbean不发布

INSERT ON DUPLICATE KEY UPDATE
正如上面评论中引用的讨论所表明的,Redbean的开发人员认为upsert是一个业务逻辑问题,它会污染ORM的界面。也就是说,如果一个人用一个自定义的查询编写器或插件来扩展Redbean,那么很可能是可以实现的。我没有尝试过这种方法,因为下面的方法很容易实现这种行为,而不会弄乱ORM的内部和插件,但是,它确实需要使用事务和模型以及一些额外的查询

基本上,在调用R::store()之前,使用R::transaction()或R::begin()启动事务。然后在“FUSE”d模型中,使用“update”FUSE方法运行一个查询,该查询检查重复并检索现有id,同时锁定必要的行(即选择进行更新)。若并没有返回id,那个么就好了,让常规模型验证(或缺少验证)像往常一样继续并返回。如果找到id,只需将$this->bean->id设置为返回值,Redbean将更新而不是插入。因此,对于这样的模型:

class Model_OpenStat extends RedBean_SimpleModel{
  function update(){
     $sql = 'SELECT * FROM `open_stat` WHERE `delivery_id`=? AND 'subscriber_id'=? LIMIT 1 FOR UPDATE';
     $args = array( $this->bean->deliver_id, $this->bean->subscriber_id );
     $dupRow = R::getRow( $sql, $args );
     if( is_array( $dupRow ) && isset( $dupRow['id'] ) ){
        foreach( $this->bean->getProperties() as $property => $value ){
          #set your criteria here for which fields
          #should be from the one in the database and which should come from this copy
          #this version simply takes all unset values in the current and sets them
          #from the one in the database
          if( !isset( $value ) && isset( $dupRow[$property] ) )
            $this->bean->$property = $dupRow[$property];
        }
        $this->bean->id = $dupId['id']; #set id to the duplicates id
     }
     return true;
  }
}
然后修改R::store()调用,如下所示:

\R::begin();
\R::store($oOpenStatBean);
\R::commit();

事务将导致“FOR UPDATE”子句锁定找到的行,或者在没有找到行的情况下,锁定索引中新行的位置,这样就不会出现并发问题


现在,这并不能解决一个用户更新记录时对另一个用户造成重创的问题,但这是一个完全不同的主题。

您试图做的就是所谓的“升级”。试试谷歌搜索。我发现了关于它的讨论:它不像集成的ORM支持那样优雅。不,不幸的是,根据引用的讨论,真正的upsert功能被认为是业务逻辑,没有集成到红豆核心中。但是,您可以编写自己的自定义查询编写器或插件,将此类内容移动到orm中。关于写这些的信息在感谢中,但是我在一年多前问过这个问题。我知道。我有同样的问题,引用的讨论对您的原始问题进行了评论,这是唯一的来源。我一直在断断续续地寻找答案,通过提供我在这里能找到的唯一一个答案,有这个问题的人可以得到比“它不受支持”的答案多一点的答案,并看到一个工作,如果稍微不那么优雅,解决方案。我认为,若你们更新你们的答案,并写下不可能直接通过ORM完成的事情,那个么答案就会变得正确。
\R::transaction( function() use ( $oOpenStatBean ){ R::store( $oOpenStatBean ); } );