在使用sqlite3写一个建议订单系统的时候,没设置主键,默认将第一个条属性设置成了主键,而这条属性并不具有唯一性,导致经常出现插入失败的问题。
在这个背景下,我考虑设置一个数据库里的自增主键,之后这部分就可以自动生成了。
但是在我使用的ORM_LITE中没有提供这样的属性,那么是不是这个属性不推荐使用呢?
找到了下面这篇文章SQLite AUTOINCREMENT : Why You Should Avoid Using It
下文是这篇的翻译。
SQLite ROWID表简介
无论何时,创建表时不指定WITHOUT ROWID
选项,都会得到一个名为rowid的隐式自动增量列。
rowid列存储64位有符号整型,用于唯一标识表中的行。
我们来看下面的例子。
首先,创建一个包含两列first_name, last_name
的新表people
:
1 | CREATE TABLE people ( |
其次,用以下INSERT
语句插入people
一行: 1
2
3INSERT INTO people (first_name, last_name)
VALUES
('John', 'Doe');
第三,用以下SELECT
语句从people
中查询数据 1
2
3
4
5
6SELECT
rowid,
first_name,
last_name
FROM
people;
所以,SQLite会自动创建一个名为rowid的隐式列,并 在您插入新行时自动分配一个整数值。
可以通过rowid
的两个别名_rowid_
和oid
来使用它
如果创建具有INTEGER PRIMARY KEY
列的表,则该列指向rowid
列。
以下语句删除people
表并重新创建它,不过这一次,我们添加另一列带有INTEGER PRIMARY KEY
属性的名为person_id
的列。
1 | DROP TABLE people; |
现在person_id
列实际上就是rowid
列。
那么,Sqlite如何分配一个整型值给rowid列呢?
如果插入一个新行时,你没有指定一个rowid值或者使用NULL
值, Sqlite会分配一个比表中最大的rowid大1的整型。 当还没有插入任何行时, rowid是1。
首先,插入带有最大值的一行插入people
表。
1 | INSERT INTO people ( |
第二,插入不指定person_id
的另一行
1
2
3
4
5
6
7
8
9 INSERT INTO people (
first_name,
last_name
)
VALUES
(
'William',
'Gate'
);
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 | DROP TABLE people; |
其次,将具有最大行id值的行添加到people表中。
1 | INSERT INTO people ( |
第三,在people表中插入另一行
1 | INSERT INTO people ( |
这次,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