2015-10-10 2 views
3

Внутренний недостаток с идентификатором senquenced для таблицы SQL - это возможность для конечного пользователя легко перемещаться по всем вашим таблицам. Иногда это проблема.Каков наилучший способ избежать уникальных столкновений с учениями?

Одним из решений является создание непересекаемого идентификатора, что не допускается для каждой строки.

Этот идентификатор должен быть уникальным полем, очевидно. Я могу использовать случайную функцию для генерации thoses uniques ids для каждой строки, но есть вероятность, что она столкнется с ранее установленным id. Если он сталкивается, конечный пользователь будет воспринимать его как случайную ошибку ...

Вот одно простое решение, чтобы преодолеть эту проблему:

$keyValid = false; 
while(!$keyValid) { 
    // Create a new random key 
    $newKey = generateKey(); 

    // Check if the key already exists in database 
    $existingPotato = $em->getRepository('Potato')->findOneBy(array('key' => $newKey)); 
    if (empty($existingPotato)) { 
     $keyValid = true; 
    } 
} 

// Hooray, key is unique! 

Это заставляет меня сделать хотя бы один ЗЕЬЕСТ каждый раз я хочу новый идентификатор.

Итак, есть ли лучшее, общепринятое решение этой проблемы?

В качестве альтернативы, существует ли оптимизированная длина идентификатора, что делает эту проблему неуместной, делая вероятность столкновений несущественной (для таблицы из 3000 000 строк)?

+0

им нехорошо с учением, но почему вы не используете идентификатор auto_increment? – ncm

+0

Возможно ли генерировать нестрочные (шестнадцатеричные случайные) идентификаторы auto_increment? –

+0

Вы ищете 'guid' или' uuid'? Большинство баз данных поддерживают такой тип. –

ответ

3

Вы можете добавить Custom id generation strategy, чтобы сделать это. Вы можете реализовать его, создав класс, который расширяет AbstractIdGenerator:

use Doctrine\ORM\Id\AbstractIdGenerator; 

class NonSequencedIdGenerator extends AbstractIdGenerator 
{ 
    public function generate(\Doctrine\ORM\EntityManager $em, $entity) 
    { 
     $class = $em->getClassMetadata(get_class($entity)); 
     $entityName = $class->getName(); 

     do { 
      // You can use uniqid(), http://php.net/manual/en/function.uniqid.php 
      $id = generateKey(); 
     } while($em->find($entityName, $id)); 


     return $id; 
    } 
} 

Затем добавьте его с помощью аннотаций в классе сущностей:

/** 
* @ORM\Id 
* @ORM\GeneratedValue(strategy="CUSTOM") 
* @ORM\CustomIdGenerator(class="NonSequencedIdGenerator") 
*/ 
private $id; 

Но если ваш generateKey не возвращает уникальный идентификатор, который должен проверить если он уже существует. Чтобы этого избежать, вы можете использовать генератор UUID для первичных ключей в вашей сущности.

/** 
* @ORM\Id 
* @ORM\Column(type="guid", unique=true) 
* @ORM\GeneratedValue(strategy="UUID") 
*/ 
private $id; 

Если вам не нравится это, вы можете создать новое поколение пользовательских идентификаторов, которые используют UUID_SHORT, а также использовать функцию как this, чтобы сделать его короче.

use Doctrine\ORM\Id\AbstractIdGenerator; 

class UuidShortGenerator extends AbstractIdGenerator 
{ 
    public function generate(EntityManager $em, $entity) 
    { 
     $conn = $em->getConnection(); 
     return $conn->query('SELECT UUID_SHORT()')->fetchColumn(0); 
    } 
} 

Проблема в том, что я не думаю, что она обеспечивает полную переносимость.

+0

Это работает. Поскольку я не хотел делать это своим основным ключом по причинам производительности, я использовал «PrePersist()» для генерации ключа. –