如何在 SQLite 中使用序列?

发布于 2024-10-08 12:47:24 字数 719 浏览 7 评论 0原文

我正在编写一个基于 PHP 的 Web 应用程序,该应用程序应该与多个数据库系统一起使用。最重要的是 MySQL 和 SQLite,但 PostgreSQL 和其他也不错。为此,我尝试尽可能使用可移植的 SQL。如果这是不可能的,我在查询中定义了一些元词,这些元词由我的数据库层处理并转换为特定于平台的 SQL 命令。

我现在正在尝试添加序列支持。每个 DBMS 处理序列的方式都不同,没有通用的方法用 SQL 编写它们。我已经阅读并理解了 PostgreSQL 的做法。我发现了一个有趣的 MySQL 解决方案它使用 MyISAM 表来逃避事务的隔离约束。毕竟,序列不会随着它们所使用的事务而回滚,而这正是我想要的。序列应该是多用户安全的。

现在我还没有找到SQLite的解决方案。它缺乏内置的序列支持。它不提供在正在运行的事务之外存储数据的方法。我当前的实现是将表锁定得足够远以执行 SELECT MAX(...) 并使用该值。但我想完全摆脱它。在 SQLite 中,这种方法需要锁定整个数据库!

有人知道 SQLite 的解决方案吗?

I'm writing a PHP-based web application that should work with multiple database systems. The most important are MySQL and SQLite but PostgreSQL and others would also be nice. For this I try to use as portable SQL as possible. Where this isn't possible, I have defined some meta words in my queries that are handled by my DB layer and converted to platform-specific SQL commands.

I'm now trying to add sequences support. Every DBMS handles sequences differently, there is no common way to write them in SQL. I have read and understood the way PostgreSQL does it. I have found an interesting solution for MySQL that uses MyISAM tables to escape the isolation constraints of a transaction. After all, sequences are not rolled back with the transaction they're used in and that's exactly what I want. Sequences are supposed to be multi-user safe.

Now I haven't found a solution for SQLite. It lacks built-in sequence support. It doesn't provide ways to store data outside a running transaction. My current implementation is to lock the table far enough to do a SELECT MAX(...) and use that value. But I want to get rid of that entirely. In SQLite, this approach requires locking the whole database!

Does anybody know a solution for this with SQLite?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

为你拒绝所有暧昧 2024-10-15 12:47:24

只需创建一个常规计数器表即可。创建序列 foo 时,执行 do

create table foo(value int);
insert into foo(value) values(0);

然后,当请求下一个计数器值时,执行 do

update foo set value=value+1;

虽然事务中止时会回滚,但它是多用户安全的:没有两个用户会提交相同的号码。 sqlite 使用数据库锁实现并发,因此第二个写入器无论如何都会阻塞(不仅仅是因为序列更新,还因为它想要进行的其他更改)。

Just create a regular counter table. On creation of a sequence foo, do

create table foo(value int);
insert into foo(value) values(0);

Then, when asking for the next counter value, do

update foo set value=value+1;

While this gets rolled back when the transaction is aborted, it is multi-user safe: no two users will commit the same number. sqlite implements concurrency with a database lock, so the second writer will block anyway (not just because of the sequence update, but also because of the other changes it wants to make).

泪是无色的血 2024-10-15 12:47:24

我会使用lastInsertRowID。这将返回最后插入数据的 rowid(等于该行的 INTEGER PRIMARY KEY 值)。
那么你就不需要任何序列了。

I would use lastInsertRowID. This returns the rowid of the last inserted data (which equals the INTEGER PRIMARY KEY value of that row).
You won't need any sequence then.

咿呀咿呀哟 2024-10-15 12:47:24

您可以模拟一个序列,首先创建一个具有自动递增主键列的表。

CREATE TABLE G_SEQUENCE(
   id INTEGER AUTO_INCREMENT PRIMARY KEY
);

将所需序列数插入该表 n 次。如果您担心性能,那么您可以一次缓存 100 个序列。

BEGIN TRANSACTION;
insert into G_SEQUENCE default values; 
...
insert into G_SEQUENCE default values; 
COMMIT;

如果您的序列表变得太大(这是一个很好的问题),您可以轻松获取最大 id,并删除小于它的所有内容。

You can emulate a sequence, first create one table with an auto-incremented primary key column.

CREATE TABLE G_SEQUENCE(
   id INTEGER AUTO_INCREMENT PRIMARY KEY
);

Insert into that table n number of times for the number of sequences you want. If you're worried about performance, then you can cache 100 sequences at a time.

BEGIN TRANSACTION;
insert into G_SEQUENCE default values; 
...
insert into G_SEQUENCE default values; 
COMMIT;

If your sequence table becomes too large - which is a nice problem to have - you can easily get the max id, and delete everything less than it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文