从MySQL中选择可用的号码

时间:2015-01-26 14:44:21

标签: mysql

我即将设置一个大型服务器,将端口分配给特定对象。每个对象在创建时都被授予一个端口,理论上可以将端口分配多年。如果有人破坏了他们的对象,那么该端口就会被释放并且可以抓取。如果我有一个包含所有对象及其端口的MySQL表,我将如何检索指定范围内的随机空闲端口?

所以: 表格包含idport。查询应选择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。

2 个答案:

答案 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;