我最近为我所有的 sql 函数制作了一个 sql 驱动程序,获得随机记录就是其中之一。
阅读评论后,我从这个博客改编了解决方案#3,这就是我想出的:
<?php
class MyDatabaseDriver {
protected $DBC;
protected $SEL_RANDOM_OFFSET;
protected $SEL_RANDOM_IMAGE;
function __construct($uname, $password, $table="my_table") {
$this->DBC = new mysqli('localhost', $uname, $password, $table);
if ($this->DBC->connect_errno) {
printf("Connect failed: %s\n", $this->DBC->connect_error);
exit;
}
$this->initialize();
}
function __destruct() { $this->close(); }
protected function initialize() {
$this->SEL_RANDOM_OFFSET = $this->DBC->prepare("SELECT ROUND(RAND() * COUNT(*), 0) AS `offset` FROM `images` WHERE `albumid` = ?");
$this->SEL_RANDOM_IMAGE = $this->DBC->prepare("SELECT `filename` FROM `images` LIMIT ?, 1");
}
function close() {
if (!$this->DBC) return;
$this->SEL_RANDOM_OFFSET->close();
$this->SEL_RANDOM_IMAGE->close();
$this->DBC->close();
$this->DBC = false;
}
function SelectRandomImage($gid) {
$result = false;
$this->SEL_RANDOM_OFFSET->bind_param("i", $gid);
$this->SEL_RANDOM_OFFSET->execute();
$this->SEL_RANDOM_OFFSET->bind_result($result);
if (!$this->SEL_RANDOM_OFFSET->fetch()) {
printf("Select random offset failed: %s\n", $this->SEL_RANDOM_OFFSET->error);
$result = false;
$this->SEL_RANDOM_OFFSET->reset();
return $result;
}
$this->SEL_RANDOM_OFFSET->reset();
$this->SEL_RANDOM_IMAGE->bind_param("i", $result);
$this->SEL_RANDOM_IMAGE->execute();
$this->SEL_RANDOM_IMAGE->bind_result($result);
if (!$this->SEL_RANDOM_IMAGE->fetch()) {
printf("Select random image failed: %s\n", $this->SEL_RANDOM_IMAGE->error);
$result = false;
$this->SEL_RANDOM_IMAGE->reset();
return $result;
}
$this->SEL_RANDOM_IMAGE->reset();
return $result;
}
} ?>
afaik,这是目前在不同虚拟主机之间具有最佳兼容性的解决方案(从本地迁移到远程主机时,我在使用“get_result”等时遇到了一些问题)。它还考虑到准备好的语句可以以更高的效率重复多次(这是关于 #3 的抱怨之一是它必须重复才能获得多个结果),因此对象被重置并保持活动状态,直到类超出范围或直接调用close。
编辑:在我的偏移选择中,我使用“ROUND”,因为我的数据库 ID 列以 1 开头,如果您的 ID 列以 0 开头,您可能想要使用“FLOOR”