我即将设置一个大型服务器,将端口分配给特定对象。每个对象在创建时都被授予一个端口,理论上可以将端口分配多年。如果有人破坏了他们的对象,那么该端口就会被释放并且可以抓取。如果我有一个包含所有对象及其端口的MySQL表,我将如何检索指定范围内的随机空闲端口?
所以:
表格包含id
和port
。查询应选择number
其中between <min> and <max> and not in table
。在MySQL中这样的事情是可能的,还是我必须让另一个表跳进来?
我目前有以下两个表:
CREATE TABLE `scjs_relays` (
`id` INT(100) UNSIGNED NOT NULL AUTO_INCREMENT,
`displayname` VARCHAR(50) NOT NULL COMMENT 'Name the relay shows up with at the overview',
`origin` VARCHAR(15) NOT NULL COMMENT 'IP the packets originate from',
`auth` BIT(1) NOT NULL DEFAULT b'',
`authurl` VARCHAR(255) NULL DEFAULT '0' COMMENT 'URL to retrieve auth token from',
`authtimeout` INT(10) UNSIGNED NULL DEFAULT '0' COMMENT 'Time before person has to be reauthed',
`steamid` BIT(1) NOT NULL DEFAULT b'',
`teamchat` BIT(1) NOT NULL DEFAULT b'',
`timestamp` BIT(1) NOT NULL DEFAULT b'',
`disconnect` BIT(1) NOT NULL DEFAULT b'',
`playerip` BIT(1) NOT NULL DEFAULT b'',
`node` INT(10) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
COMMENT='Chat relays'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
CREATE TABLE `scjs_ports` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`port` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`node` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`relayid` INT(100) UNSIGNED NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COMMENT='Ports per server'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
但是,如果我尝试添加外键,我会收到错误。 id
表中的scjs_users
是AUTO_INCREMENT,因为这将是一个增量ID,每个服务器都有自己的ID,永远不会被重用。我目前拥有的外键如下:
ALTER TABLE `scjs_ports`
ADD CONSTRAINT `FK_relayid` FOREIGN KEY (`relayid`) REFERENCES `scjs_relays` (`id`) ON UPDATE CASCADE ON DELETE SET NULL;
这应该可行吗?如果我更新scjs_relay中的行,id
将永远不会更改,只会更改其他列,因此CASCADE
是正确的选项吗?如果一行被删除,它的端口显然是免费的,所以应该设置为NULL。
答案 0 :(得分:1)
对于您的应用程序,您可能需要一个包含所有可用端口的表,以及对具有该端口的对象的引用(如果当前没有对象分配给端口,则为null)
所以这可能是这样的:
id - autoincrement primary key
port - port number, has unique index
object_id - foreign key reference to object that has port, NULL-able, unique index if needed for reverse object to port lookups
您需要考虑允许一致的读取,因此当您要搜索开放行并为其分配对象时,您需要在事务中执行此操作并在首次选择时使用锁定,因此没有其他连接可以在尝试更新时触摸该行。
该序列可能如下所示:
START TRANSACTION;
SELECT @update_id:=id
FROM table
WHERE object_id IS NULL
ORDER BY port ASC
/*
Note you could order by RAND here if you truly want random
but query would not be optimized
*/
LIMIT 1
FOR UPDATE;
UPDATE table SET object_id = ?
WHERE id = @update_id;
COMMIT;
此处?
是您要分配给端口的对象的对象引用。正如您所看到的,这可能很适合作为存储过程,您可以将对象id作为参数传递。
答案 1 :(得分:0)
我通过一个包含所有可用端口的表来实现这一点。
然后在发布新端口时,我会通过LEFT JOIN将此表检查到发布的ports表,如下所示:
表table1.port = table2.port上的table1 LEFT JOIN table2中的SELECT table1.port WHERE table2为null 限制1;