使用SQLAlchemy创建后自动递增非唯一ID

Ale*_*sen 3 mysql sqlalchemy flask-sqlalchemy

我的主要目标是使实施修订历史记录和日记更加容易。

我发现自己想知道是否有可能使用Flask-SQLAlchemy(或直接使用SQL)为mysql获取一个自动递增的非唯一整数。 我发现了这个堆栈溢出帖子,该帖子与我想做什么很接近,但问题集中在主键上。例如,如果我的表有这些列,

revision_id = db.Column(db.Integer, nullable=False)
post_id = db.Column(db.Integer, nullable=False)

__table_args__ = (
    PrimaryKeyConstraint('post_id', 'revision_id'),
)
Run Code Online (Sandbox Code Playgroud)

是否可以创建一个修订版本ID为1且post_id为max(post_id)+ 1的新帖子,而不会出现两个用户尝试同时创建一个帖子并创建相同的post_id的问题?

该系统的优势在于,它使发布历史记录(和差异记录)非常简单。每当有人想要修改帖子时,我都将使用与原始帖子相同的post_id并增加version_id(现在我将其键入,但存在相同的问题)。

更新:

西尔万·勒鲁(Sylvain Leroux)使我走上了正确的道路,以解决我的问题。我需要将两个表都设置为sqlalchemy中的主键。如果sqlalchemy中有一个以上的主键,则不会假定它们是唯一的。这是我目前的定义,

revision_id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=False, default=1)
post_id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=True)
__table_args__ = (
    PrimaryKeyConstraint('post_id', 'revision_id'),
)
Run Code Online (Sandbox Code Playgroud)

哪个产生这个SQL

CREATE TABLE `post` (
    revision_id INTEGER NOT NULL, 
    post_id INTEGER NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (post_id, revision_id), 
)
Run Code Online (Sandbox Code Playgroud)

这让我可以插入有无post_id的内容。

所有人都归功于Sylvain Leroux,因为我只是将他的答案翻译成了SQLAlchemy。

Syl*_*oux 5

引用经典的MySQL错误消息:

只能有一个自动列,并且必须将其定义为键:

auto_increment 列必须是主键(或键)(在MySQL中也称为索引,可以是或可以是唯一的)。


至于:

SELECT MAX(id) FROM tbl INTO @new_id;
INSERT INTO tbl (id, ...) VALUES (@new_id, ....);
Run Code Online (Sandbox Code Playgroud)

您清楚地了解到,如果两个并发请求执行相同的操作,您将最终获得两个完全不相关且具有相同ID的新行。您可能不想使用表锁来避免这种陷阱。

就我自己而言,我会说“不要那样做”。也许这会让一些事情变得更加容易在你的应用程序,但我敢打赌,会做出的其他事情更复杂或太多不太可靠。


但是...如果真正的问题是保持“ post id”不变,请记住auto_increment可能是密钥的一部分http://sqlfiddle.com/#!2/9b4b45/1):

create table tbl(id int auto_increment not null, 
                 rev int not null default 1,
                 content TEXT,
                 primary key(id,rev));

-- insert 3 new contents with "auto id" and default revision 1
insert into tbl (content) values ("alpha"), ("bta"), ("gamma");
Run Code Online (Sandbox Code Playgroud)

假设项目id2,rev1中存在错误。您可以插入一个新修订:

insert into tbl (id, rev, content) values (2,2,"beta");
Run Code Online (Sandbox Code Playgroud)

如果要查看项目id2的各种版本,请执行以下操作:

select * from tbl where id=2 order by rev;
Run Code Online (Sandbox Code Playgroud)

您将必须找到如何使用SQLAlchemy(:D)进行此操作,但是使用MySQL绝对可以做到这一点。