SQL表的senquenced标识符的内在缺点是最终用户可以轻松遍布整个表。有时这是一个问题。
一种解决方案是创建一个非序列的id,这对于每一行都是不可猜测的。
显然,这个id必须是一个独特的字段。我可以使用随机函数为每一行生成独特的id,但它有可能与先前设置的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!
它强迫我每次想要一个新的id时至少生成一个SELECT语句。
那么,这个问题有更好的,被广泛接受的解决方案吗?
或者,是否存在id的优化长度,通过使碰撞概率可忽略(对于3,000,000行表)来使该问题无关紧要?
答案 0 :(得分: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的新自定义ID代码,并使用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);
}
}
这里的问题是我不认为它提供了完全的可移植性。