在使用sqlite3写一个建议订单系统的时候,没设置主键,默认将第一个条属性设置成了主键,而这条属性并不具有唯一性,导致经常出现插入失败的问题。

在这个背景下,我考虑设置一个数据库里的自增主键,之后这部分就可以自动生成了。

但是在我使用的ORM_LITE中没有提供这样的属性,那么是不是这个属性不推荐使用呢?

找到了下面这篇文章SQLite AUTOINCREMENT : Why You Should Avoid Using It

下文是这篇的翻译。

SQLite ROWID表简介

无论何时,创建表时不指定WITHOUT ROWID选项,都会得到一个名为rowid的隐式自动增量列。

rowid列存储64位有符号整型,用于唯一标识表中的行。

我们来看下面的例子。

首先,创建一个包含两列first_name, last_name的新表people:

1
2
3
4
CREATE TABLE people (
first_name text NOT NULL,
last_name text NOT NULL
);

Try it

其次,用以下INSERT语句插入people一行:

1
2
3
INSERT INTO people (first_name, last_name)
VALUES
('John', 'Doe');
Try it

第三,用以下SELECT语句从people中查询数据

1
2
3
4
5
6
SELECT
rowid,
first_name,
last_name
FROM
people;
Try it

所以,SQLite会自动创建一个名为rowid的隐式列,并 在您插入新行时自动分配一个整数值。

可以通过rowid的两个别名_rowid_oid来使用它

如果创建具有INTEGER PRIMARY KEY列的表,则该列指向rowid列。

以下语句删除people表并重新创建它,不过这一次,我们添加另一列带有INTEGER PRIMARY KEY属性的名为person_id的列。

1
2
3
4
5
6
7
DROP TABLE people;

CREATE TABLE people (
person_id INTEGER PRIMARY KEY,
first_name text NOT NULL,
last_name text NOT NULL
);

Try it

现在person_id列实际上就是rowid列。

那么,Sqlite如何分配一个整型值给rowid列呢?

如果插入一个新行时,你没有指定一个rowid值或者使用NULL值, Sqlite会分配一个比表中最大的rowid大1的整型。 当还没有插入任何行时, rowid是1。

首先,插入带有最大值的一行插入people表。

1
2
3
4
5
6
7
8
9
10
11
INSERT INTO people (
person_id,
first_name,
last_name
)
VALUES
(
9223372036854775807,
'Johnathan',
'Smith'
);

Try it

第二,插入不指定person_id的另一行

1
2
3
4
5
6
7
8
9
 INSERT INTO people (
first_name,
last_name
)
VALUES
(
'William',
'Gate'
);

Try it

SQLite AUTOINCREMENT 属性

SQLite 推荐你不应该使用AUTOCREMENT属性,因为:

The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.

AUTOINCREMENT关键字会产生额外的CPU,内存,磁盘空间和磁盘I/O开销,如果不是严格需求,应该避免使用。通常不是必须的。

此外,SQLite为AUTOCREMENT列分配值的方式与rowid列的使用方式略有不同。

请参阅以下示例。

首先,再次删除并重新创建人员表。这次,我们使用AUTOINCREMENT属性。

1
2
3
4
5
6
7
DROP TABLE people;

CREATE TABLE people (
person_id INTEGER PRIMARY KEY AUTOINCREMENT,
first_name text NOT NULL,
last_name text NOT NULL
);

Try it

其次,将具有最大行id值的行添加到people表中。

1
2
3
4
5
6
7
8
9
10
11
INSERT INTO people (
person_id,
first_name,
last_name
)
VALUES
(
9223372036854775807,
'Johnathan',
'Smith'
);

Try it

第三,在people表中插入另一行

1
2
3
4
5
6
7
8
9
INSERT INTO people (
first_name,
last_name
)
VALUES
(
'John',
'Smith'
);

Try it

这次,SQLite发出了一条错误消息:

1
[Err] 13 - database or disk is full

因为它不会重新使用未被使用数字。

AUTOCREMENT这个属性的主要目的是防止SQLite复用还未使用的值或者使用先前删除的行

如果还没有任何像这样的需求,那么你就不应该在主键中使用SQLite AUTOINCREMENT属性。

在这篇教程中,你已经学习到AUTOINCREMENT属性如何运作的,以及它如何影响SQLite分配值给主键的方式。

# Reference 1. SQLite AUTOINCREMENT : Why You Should Avoid Using It