如何在使用Python在SQLite中插入行后检索插入的id?

Jan*_*ane 156 python sqlite

如何在使用Python在SQLite中插入行后检索插入的id?我有这样的表:

id INT AUTOINCREMENT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(50)
Run Code Online (Sandbox Code Playgroud)

我插入一个新行,例如数据username="test"password="test".如何以事务安全的方式检索生成的id?这适用于网站解决方案,其中两个人可能同时插入数据.我知道我可以得到最后一行,但我不认为这是交易安全的.有人可以给我一些建议吗?

unu*_*tbu 232

您可以使用cursor.lastrowid(请参阅"可选的DB API扩展"):

connection=sqlite3.connect(':memory:')
cursor=connection.cursor()
cursor.execute('''CREATE TABLE foo (id integer primary key autoincrement ,
                                    username varchar(50),
                                    password varchar(50))''')
cursor.execute('INSERT INTO foo (username,password) VALUES (?,?)',
               ('test','test'))
print(cursor.lastrowid)
# 1
Run Code Online (Sandbox Code Playgroud)

如果两个人同时插入,只要他们使用不同的cursors,cursor.lastrowid将返回插入id的最后一行cursor:

cursor.execute('INSERT INTO foo (username,password) VALUES (?,?)',
               ('blah','blah'))

cursor2=connection.cursor()
cursor2.execute('INSERT INTO foo (username,password) VALUES (?,?)',
               ('blah','blah'))

print(cursor2.lastrowid)        
# 3
print(cursor.lastrowid)
# 2

cursor.execute('INSERT INTO foo (id,username,password) VALUES (?,?,?)',
               (100,'blah','blah'))
print(cursor.lastrowid)
# 100
Run Code Online (Sandbox Code Playgroud)

请注意,当您一次插入多行时lastrowid返回:Noneexecutemany

cursor.executemany('INSERT INTO foo (username,password) VALUES (?,?)',
               (('baz','bar'),('bing','bop')))
print(cursor.lastrowid)
# None
Run Code Online (Sandbox Code Playgroud)

  • 还有[`last_insert_rowid()`SQL函数](http://www.sqlite.org/lang_corefunc.html#last_insert_rowid),允许您在*next*insert语句中插入最后一行id作为外键,完全在SQL中. (38认同)
  • +1用于解释它将返回该单个游标实例的最新id. (13认同)
  • 看来Python的sqlite3 lastrowid在https://github.com/ghaering/pysqlite/blob/e728ffbcaeb7bfae1d6b7165369bd0ae16cabf95/src/cursor.c下使用`last_insert_rowid`(这不保证线程安全,但似乎是FWIW的唯一选择).另请参见http://stackoverflow.com/q/2127138/32453 (3认同)
  • @MartijnPieters你可以发布这个作为答案,即使问题已经很久了.它仍然可以帮助用户阅读此页面. (2认同)
  • 顺便说一句,这适用于`INSERT`,但不适用于`UPDATE`。但是当更新一行时,你可能已经有了相应的行 id(我花了一段时间才弄清楚这一点......)。 (2认同)

Ste*_*ker 15

@Martijn Pieters在评论中的所有功劳:

您可以使用该功能last_insert_rowid()

last_insert_rowid()函数ROWID从调用该函数的数据库连接返回最后一行插入的 。的last_insert_rowid()SQL函数是围绕一个包装sqlite3_last_insert_rowid()C / C ++接口功能。

更新:您可以RETURNINGSQLite 3.35 中使用:

create table users (
  id integer primary key,
  first_name text,
  last_name text
);

insert into users (first_name, last_name)
values ('Jane', 'Doe')
returning id;
Run Code Online (Sandbox Code Playgroud)

  • “LAST_INSERT_ROWID()”函数特定于 SQLite。`cursor.lastrowid` 属性是 Python DB-API 规范的一部分,因此它应该更可移植。 (6认同)
  • 根据您的程序,如果多个线程可能并行写入数据库,您还应该小心竞争条件。在这种情况下,您不能假设 last_insert_rowid 是您刚刚插入的行。值得庆幸的是,现在可以使用 RETURNING 来解决这个问题,尽管它还不是在所有地方都可用。 (5认同)
  • 如果在您写入和调用last_insert_rowid 之间有东西写入数据库,则这是可能的。 (2认同)