symfony2如何保证序列号未被使用

symfony2 how to guarante serial number not in use

我在symfony2中有一个文档管理系统。 一旦用户建立了我的文档实体,它将被分配一个序列号。

这就是我找到要分配的序列号的方式 1)检查数据库中使用的最高序列号 2)分配它并刷新实体。

我使用这个序列作为这个实体的多个版本的标识符,所以它不是数据库唯一的。

如何保证分配的号码是真正唯一的?我会把表锁定在平面 php 但不确定如何或它是否是 symfony2 中的最佳实践。

/**
 * Establishes a analysi entity.
 *
 */
public function establishAction(Request $request, Analysis $analysi)
{

    ...

    $analysi->setSerial( $this->getNewSerial() );//set a new serial number
    //TODO: How to confirm this is really not in use since there is no transaction locking going on here?
    $em->flush($analysi);

    ...

}


private function getNewSerial()
{            
    $em = $this->getDoctrine()->getManager();

    //get highest serial nb from established analysises
    $results = $em->createQuery("SELECT MAX(a.serial) FROM HazardlogBundle:Analysis a WHERE a.currentVersion = true")->getResult();
    $temp = $results[0];
    $max_serial = $temp[1];

    $new_serial = $max_serial + 1;

    return $new_serial;
}

----------------更新

我必须明确说明: 我可以有...

entity A with serial 123 and version 1
entity B with serial 123 and version 2
entity C with serial 124 and version 1
entity D with serial 125 and version 1

我担心的是用户同时创建实体C和D,所以我的控制器可以获取当前用于创建实体C的最高序列号,并且在实体C被刷新到DB之前,线程服务在将序列号为 124 的实体 C 写入数据库之前,创建实体 D 的用户将从数据库中读取最高编号 123。因此,我最终会得到序列号为 124 的实体 C 和 D。

也许我可以定义一个由序列号和版本号组成的唯一索引来避免这个问题?

我认为您必须将唯一性逻辑放在带有注释的实体上。

src/HazardlogBundle/Entity/Analysis.php

    /**
     * @var string
     *
     * @ORM\Column(name="serial", type="integer", unique=true)
     */
    private $serial;

如果您使用 MySQL - 您可以在单独的 table 上使用 AUTO_INCREMENT。您可以在 mysql 文档中找到更多信息:http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id,请参阅 "simulate sequences" 部分。

如果您使用的是 PostgreSQL / Oracle / 等,您可以使用序列:https://www.postgresql.org/docs/9.5/static/functions-sequence.html

此外,您可以使用 uuid4 并在 php 中生成它。这里获得重复密钥的机会非常低。

所有案例(mysql 一个案例除外)都可以编码为单独的代码或学说的 @GeneratedValuehttp://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#identifier-generation-strategies
MySQL 已排除,因为每个 table 只有一个 AUTO_INCREMENT,而且您可能已经将其用作主键。

我找到了一种通过组合两列来创建唯一索引的方法,如下所示:

/**
 * Analysis
 *
 * @ORM\Table(name="analysis",uniqueConstraints={@ORM\UniqueConstraint(name="unique_version_serial", columns={"Version", "serial"})})
 * @ORM\Entity(repositoryClass="HazardlogBundle\Repository\AnalysisRepository")
 */
class Analysis

...