对SQL表使用顺序标识符的内部缺点是最终用户可能很容易遍历所有表。有时这是一个问题。
一种解决方案是为每一行创建一个非顺序id,这是不可猜测的。
显然,这个id必须是唯一的字段。我可以使用随机函数为每行生成唯一的id但它有可能与之前设置的id相冲突。如果它发生碰撞,最终用户会将其视为随机bug…
这里有一个简单的解决方案来克服这个问题:
$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!
每当我想要一个新的id时,它迫使我至少执行一个SELECT语句。
那么,有没有更好的、被广泛接受的解决方案来解决这个问题呢?或者,是否存在一个优化的id长度,使碰撞概率可以忽略不计(对于一个3,000,000行表),使这个问题无关?
您可以添加自定义id生成策略来完成此操作。您可以通过创建扩展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;
如果你不喜欢这样,你可以创建一个新的使用uid_short的自定义id生成,并使用像这样的函数使其更短。
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);
}
}
这里的问题是我不认为它提供了完全的可移植性