简体   繁体   English

我需要在这里交易吗?

[英]Do I need a transaction here?

I have a web application in which users create objects that get stored in a MySQL database. 我有一个Web应用程序,用户可以在其中创建要存储在MySQL数据库中的对象。 Each object has a globally unique identifier that is stored in a table. 每个对象都有一个存储在表中的全局唯一标识符。

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;

When a new object is to be created and stored I generate a new uid and ensure that it does not already exist in the uidlist table. 当要创建和存储新对象时,我将生成一个新的uid,并确保它在uidlist表中尚不存在。 (I should mention that collisions are rare since the potential range of UIDs I have is very large). (我应该指出,由于我拥有的UID的潜在范围非常大,因此冲突很少见)。

No issues here - it works just fine. 这里没有问题-效果很好。 However, with an increasing number of users wanting to simultaneously create + store objects the need to check uidlist is liable to become a bottleneck. 但是,随着越来越多的用户希望同时创建+存储对象,检查uidlist的需求很容易成为瓶颈。

To circumvent the problem here is what I have done: 为了解决这个问题,我要做的是:

I have a secondary table 我有第二张桌子

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;

I pre-populate this table at short intervals via a CRON job - which ensures that it always has 1000 uid values that are tested for uniqueness. 我通过CRON作业以较短的间隔预填充了该表-确保该表始终具有经过测试的唯一性的uid值。

When a live user requires a new UID I do the following: 当实时用户需要新的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
}

No issues here either. 这里也没有问题。 It works perfectly well in my single user test environment. 在我的单用户测试环境中,它工作得很好。 However, my SQL skills are pretty basic so I am not 100% sure that 但是,我的SQL技能很基础,所以我不能100%确定

  • this is the right way to handle the job 这是处理工作的正确方法
  • that my "safe" UID pickup method will not return unsafe values because in the mean time another user has been assigned the same UID. 我的“安全” UID提取方法不会返回不安全值,因为与此同时,另一个用户已被分配了相同的UID。

I'd much appreciate any tips on how this scheme might be improved. 我非常感谢有关如何改进此方案的任何提示。

Any reason you are not using a serial as your unique identifier? 有什么理由不将序列号用作唯一标识符? That would definitely be my first suggestion and would negate the necessity for the complicated setup you have. 那肯定是我的第一个建议,并且会否定您拥有复杂设置的必要性。

Assuming that there is some reason then the biggest flaw I can see in your current makeUID call is that you are likely to get into a situation whereby the update sets 'used' to 1 and this row is deleted by a secondary call to makeUID before it has been able to successfully return the column meaning your second select (SELECT uid FROM uidbank WHERE used = '1') would return no rows 假设有某种原因,那么我在当前的makeUID调用中所能看到的最大缺陷是,您可能会遇到这样的情况,即更新将“已使用”设置为1,并且该行在其之前被辅助调用makeUID删除了能够成功返回该列,这意味着您的第二个选择(SELECT uid FROM uidbank WHERE used ='1')将不返回任何行

Could you explain why you dont use a serial so then I can try and get a better idea as to what is going on 您能解释一下为什么不使用序列号的原因吗,然后我可以尝试对发生的事情有一个更好的了解

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM