Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/241.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 我需要交易吗?_Php_Mysql - Fatal编程技术网

Php 我需要交易吗?

Php 我需要交易吗?,php,mysql,Php,Mysql,我有一个web应用程序,用户在其中创建存储在MySQL数据库中的对象。每个对象都有一个存储在表中的全局唯一标识符 DROP TABLE IF EXISTS `uidlist`; CREATE TABLE IF NOT EXISTS `uidlist` ( `uid` varchar(9) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `chcs` varchar(16) DEFAULT NULL, UNIQUE KEY `uid` (`

我有一个web应用程序,用户在其中创建存储在MySQL数据库中的对象。每个对象都有一个存储在表中的全局唯一标识符

DROP TABLE IF EXISTS `uidlist`;
CREATE TABLE IF NOT EXISTS `uidlist` (
`uid` varchar(9) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`chcs` varchar(16) DEFAULT NULL,
 UNIQUE KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=ascii;
当要创建和存储一个新对象时,我会生成一个新的uid,并确保它在uidlist表中不存在。我应该提到,碰撞是罕见的,因为我拥有的UID的潜在范围非常大

这里没有问题-它工作得很好。然而,随着越来越多的用户希望同时创建+存储对象,检查uidlist的需要很可能成为一个瓶颈

为了避免这个问题,我做了如下工作:

我有一张二等桌

DROP TABLE IF EXISTS `uidbank`;
CREATE TABLE IF NOT EXISTS `uidbank` (
`uid` varchar(9) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`used` tinyint(1) NOT NULL DEFAULT '0'
 ) ENGINE=InnoDB DEFAULT CHARSET=ascii;
我通过CRON作业以很短的时间间隔预先填充这个表,这确保它始终有1000个uid值,这些值都经过唯一性测试

当实时用户需要新UID时,我会执行以下操作:

function makeUID()
{
 global $dbh;
 $sql = "DELETE FROM `uidbank` WHERE used = '1';";
 //discard all "used" uids from previous hits on the bank 
 $sql .= "UPDATE `uidbank` SET used = '1' WHERE used = '0' LIMIT 1;";
 //setup a new hit
 $dbh->exec($sql);
 //be done with that

 $sql = "SELECT uid FROM `uidbank` WHERE used = '1'";
 $uid = $dbh->query($sql)->fetchColumn();
 //now pickup the uid hit we just setup
 return $uid;
 //return the "safe" uid ready for use
}
这里也没有问题。它在我的单用户测试环境中运行良好。然而,我的SQL技能非常基本,所以我不能100%肯定这一点

这是处理这项工作的正确方法 我的安全UID拾取方法不会返回不安全的值,因为同时另一个用户被分配了相同的UID。
我非常感谢关于如何改进此方案的任何提示。

您不使用序列号作为唯一标识符的原因是什么?这肯定是我的第一个建议,并将否定你的复杂设置的必要性

假设有某种原因,那么我在您当前的makeUID调用中看到的最大缺陷是,您可能会遇到这样的情况,即更新集“used”为1,并且这一行在它能够成功返回列(表示您的第二个select uid FROM uidbank)之前被对makeUID的第二次调用删除WHERE used='1'将不返回任何行


你能解释一下为什么不使用序列号,这样我就可以试着更好地了解发生了什么

如果你觉得需要处理多个表,并且任何表中的任何更改都会影响其他表,那么你应该使用Transaction。你不能使用PHP来强制执行数据完整性,你正在这样做。您正在做的另一件事是创建一个生成唯一标识符的过程。我们已经有了。这是MySQL的自动增量和UUID函数,它们工作正常。您推出自己的解决方案有什么原因吗?它产生的问题比修复的问题多。请阅读我对@Olly W的评论。我正在使用自己的例程生成唯一ID,因为它们用于外部世界,需要具有特定结构。话虽如此,+1表示您不应使用PHP强制执行数据完整性。从integrity POV-unique constraint处理唯一性的角度来看,您不会遇到会进入数据库的冲突。至于问题的第二部分,是的——你确实需要事务处理——存在一个删除和更新,你不希望一个失败,另一个成功,反之亦然。出于性能目的,我建议您在那里设置一个自动增量,否则InnoDB将在内部创建一个,并且它将是一个8字节的int。在速度适中的SSD上,您不应该有任何性能问题。您确实有一个唯一的密钥,但它不是主密钥,也不是整数,这在本例中很重要。您还可以使用InnoDB,InnoDB根据主键创建索引b树。为了避免大量的单词,其他地方的内容比我现在能做的要好得多——这与写性能有关。长话短说,将自动递增作为主键只会对您有利,特别是从性能角度来看。不使用串行作为UID有很好的理由。简单地说,UID不仅在数据库内部使用,而且在由用户存储的对象生成的HTML标记中也使用。那里的UID必须是字母数字字符串,并且必须是全局唯一的,并且具有固定的模式。因此,您最好在php中创建UID,并将其与后端的串行文件结合使用。如果这是不可能的,那么我可以设想的唯一方法是使用事务并锁定表,但这会影响性能。我找不到一种合理的方法在外部世界使用UID格式,在内部使用自动增量。同时,事务和表锁定听起来有些过分,因为UID冲突在当前上下文中是非常罕见的事件。所以我最终通过MemCache创建了一个临时锁。我使用PHP5.5,所以请尝试。最终给出了一个非常安全的解决方案。我刚刚用blitz.io模拟了1000次同时命中,系统的性能几乎没有明显下降。