sqlite是一个非常好用的轻量级数据库,并且python自带操作sqlite的函数库,开箱即用,对新手特别友好。

1. 傻瓜式调用

Python官方API 中,sqlite3.Cursor对象有 lastrowid 属性,使用 cursor.lastrowid 即可得到新插入的数据记录的ID值。

lastrowid

This read-only attribute provides the row id of the last inserted row. It is only updated after successful INSERT or REPLACE statements using the execute() method. For other statements, after executemany() or executescript() , or if the insertion failed, the value of lastrowid is left unchanged. The initial value of lastrowid is None .

Inserts into WITHOUT ROWID tables are not recorded.

Changed in version 3.6: Added support for the REPLACE statement.

lastrowid

该属性只读,提供最后插入的行记录的 row id 。它只有在使用 execute() 方法成功 insert 和 replace 时才会被更新。

使用 executemany() 和 executescript() 方法时 或者插入操作失败时, lastrowid 的值不会变化。

lastrowid 初始值是 None。

在没有 ROWID 的数据库表执行插入,lastrowid不会记录值。

版本3.6变化:增加对 replace 语句的支持。

代码如下:

# Python3
# -*- coding: utf-8 -*-
import sqlite3
con = sqlite3.connect(":memory:")	# 表示在内存中创建的数据库文件,运行完数据即丢失
cur = con.cursor()
# id 自增
cur.execute("create table t_haha(id INTEGER PRIMARY KEY AUTOINCREMENT,name text, age INTEGER)")
# 第1条数据
data = ("Tom",18)
cur.execute("insert into t_haha(name,age) values (?,?)", data)
theid = cur.lastrowid

2. 深入研究

仔细看说明,可以发现官方手册中说的是 返回新插入记录的 row id ,而不是我们自定义的主键id。

而这个 row id是何方神圣呢?

2.1 row id是什么

默认情况下,所有的SQLite表每一行都有一个特殊的列,通常被称为 rowid ,它是每个 表内代表每个行的唯一标识。

如果某个建表语句 create table后附带了 without rowid ,则该表的 rowid 特殊列就会被删除,这个新建的表就是个 WITHOUT ROWID table。

[译自 官方此文 ]

也就是说一般的SQLite的每个表都带有 rowid 列。

2.2 rowid table

注意:下文中的 rowid rowid table 都是专有名词,具有特定的含义,指代特定的一类东西。

我们看看 SQLite 官方网站对 rowid table 的介绍,节选翻译自官方网站的 此文

rowid table定义:

  • 不是 virtual table(和视图有点像的东西)
  • 不是 WITHOUT ROWID table

大部分的典型的SQLite数据库表都是 rowid table。

Rowid table 一般有以下特征:它们都有唯一的(unique), 非空的(not-NULL), 带有符号的 64位整型(signed 64-bit integer) rowid ,用来在 B-tree存储引擎中作为key索引数据。

变形(Quirks)

  • rowid table 的 PRIMARY KEY 通常并不是用来在B-Tree中索引数据那种意义上的主键。(博主注:说人话,就是说 在SQLite内部B-Tree中,并不是用 PRIMARY KEY 来索引该数据记录的)。这条规则的例外就是, 当 rowid table 声明了一个 INTEGER PRIMARY KEY。在这种情况下,这个 INTEGER PRIMARY KEY 就变成了 rowid 的别称
  • rowid table 真正的主键(primary key)是 rowid。(主键(primary key)的值通常用来在内部B-Tree存储中查找指定行的key)。
  • rowid table 的 rowid 可以使用 "rowid"或"oid"或“_rowid_”中的任一个名称作为列名来访问、读写。有一种例外,如果某个表在创建时占用了那些特殊的列名,那么这些特殊的列名就代表声明时的含义,而不是指代 rowid 了。
  • 通过 rowid 获取数据库记录是经过高度优化,速度很快。
  • rowid 没有被  INTEGER PRIMARY KEY 代替,那么它不是持久的,可能会被更改。特别是 VACUUM命令会改变那些没有声明 INTEGER PRIMARY KEY 的表的rowid。所以, 应用软件不建议直接访问 rowid,而是应该用一个 INTEGER PRIMARY KEY 列来代替rowid

总结一下,就是说:

1. 创建表时,主键要创建为 INTEGER PRIMARY KEY,其实我觉得最好再加上自增 AUTOINCREMENT ,这样最简单最完美。

2. 带有 INTEGER PRIMARY KEY 列的SQLite 数据库表,其 rowid 就是 该INTEGER PRIMARY KEY 列。所以,前面 使用 cur.lastrowid 得到就是我们的ID值了。

3. 创建表SQL语句应该这样:

create table t_haha(id INTEGER PRIMARY KEY AUTOINCREMENT,name text, age INTEGER)

这样这个表 t_haha 的id 列就代表原始的 rowid了。

注意:INTEGER PRIMARY KEY  不要写成了 int primary key。大小写无所谓,但是 integer 不要写成了 int,因为 int 不是 sqlite 的基本数据类型。

3. 代码

# Python3
# -*- coding: utf-8 -*-
import sqlite3
con = sqlite3.connect(":memory:")	# 表示在内存中创建的数据库文件,运行完数据即丢失
cur = con.cursor()
# id 自增
cur.execute("create table t_haha(id INTEGER PRIMARY KEY AUTOINCREMENT,name text, age INTEGER)")
# 第1条数据
data = ("Tom",18)
cur.execute("insert into t_haha(name,age) values (?,?)", data)
# 第2条数据
data = ("Jerry",22)
cur.execute("insert into t_haha(name,age) values (?,?)", data)
# 第3条数据
data = ("Lily",25)
cur.execute("insert into t_haha(name,age) values (?,?)", data)
# 打印全部数据
cur.execute("select * from t_haha")
print(cur.fetchall())
print("===insert 3 data, and last row id is", cur.lastrowid)
# 删除第1条 
cur.execute("delete from t_haha where id = 1")
# 打印全部数据
cur.execute("select * from t_haha")
print(cur.fetchall())
print("===delete the first row")
# 再插入1条数据,此时id自动递增,插入后id应该为4
data = ("Peter",100)
cur.execute("insert into t_haha(name,age) values (?,?)", data)
# 验证下 lastrowid 是否严格和自增的id一致
cur.execute("select * from t_haha")
print(cur.fetchall())
print("===last row id:",cur.lastrowid)
con.close()
con.close()

程序输出如下:

表明 cur.lastrowid 值其实就是我们的 id 列值。

当我在开发一个项目时,发现当 数据库 中存入了较多的信息时,我们要读每条数据然后处理删除时,我会用select 语句来逐一读取,但这样有个弊端就是我需要自己来维护这个 id 值,这样就是得代码变得更加复杂,可重入性大大降低。但是 sqlite 3还是给我们提供了很多便利,我们可以通过只读取第一条数据方法来让 数据库 自己来维护这个 id 值,这样就是得了我们的代码精简了很多,而且代码的可重入性也有了比较乐观的改善。 话不多说上函数: #include "init_db.h" #include "log.h" #inclu
使用INSERT OR REPLACE命令即可满足需求 语句规范INSERT OR REPLACE INTO table-name (column-name,...) VALUES (column-value,...) 二、具体操作 1、创建UNIQUE约束 UNIQUE约束: 唯一约束,防止在一个特定的列存在两个 记录 具有相同的值 UNIQUE和 PRIMARY KEY约束有什
本文实例讲述了 Python sqlite 3事务处理方法。分享给大家供大家参考,具体如下: sqlite 3事务总结: 在connect()中不传入 isolation_level 事务处理: 使用connection.commit() #!/usr/bin/env python # -*- coding:utf-8 -*- ''' sqlite 3事务总结: 在connect()中不传入 isolation_level 事务处理: 使用connection.commit() 智能commit状态: 生成方式: 在connect()中不传入 isolation_level,
Python 中对 sqlite 3 数据库 进行操作时,经常需要用到字段名,然而对于 sqlite 使用select语句并不能象MySql等 数据库 一样返回带字段名的字典数据集。特别是对于一个不熟悉的 sqlite 数据库 ,写代码时如果需要借助工具查看,那其实是有点对不起 python 的。 下面两段代码就可以轻易获得一个 sqlite 数据库 中所有数据表名和字段名的列表: # python 获取 sqlite 3 数据库 mydb.db中的表名和表字段名 import sqlite 3 conn= sqlite 3.connect('mydb.db') cu=conn.cursor() # 获取 表名,保存在tab_name列表 String sql = "select last_insert_ row id () from " + TABLE_NAME ; Cursor cursor = db.rawQuery(sql, null); int a = -1; if(cursor.moveToFirst()){ a = cursor.getInt(0); return a;
SQLite 是一个C语言库,它实现了一个 小型, 快速, 自包含, 高可靠性, 功能齐全的 SQL 数据库 引擎。 SQLite 是世界上使用最多的 数据库 引擎。它内置于所有移动电话和大多数计算机中,并且捆绑在人们每天使用的无数其他应用程序中。下面是介绍如何使用INSERT OR REPLACE命令。 具体业务中,遇到需要批量 插入 和修改 数据库 的情况。 当前数据不存在,进行数据 插入 操作 当前数据存在,进行数据更 操作 以上的业务情况,可以使用 SQlite 的 INSERT OR REPLACE命令进.
在使用 Python sqlite 3 模块执行多线程 插入 数据时,需要注意以下几点: 1. 每个线程需要创建独立的 数据库 连接对象,避免多个线程共用同一个连接对象导致数据混乱或者死锁等问题。 2. 在 插入 数据时,需要使用 sqlite 3 的锁机制,以确保多个线程不会同时 插入 数据导致数据冲突。 下面是一个简单的示例代码,演示如何在多线程环境下 插入 数据到 sqlite 3 数据库 中: ``` python import sqlite 3 import threading # 定义 插入 数据的函数 def insert_data(thread_ id ): conn = sqlite 3.connect('test.db') cursor = conn.cursor() cursor.execute("INSERT INTO test_table(name, age) VALUES (?, ?)", ('test', thread_ id )) conn.commit() conn.close() # 创建多个线程 插入 数据 threads = [] for i in range(10): t = threading.Thread(target=insert_data, args=(i,)) threads.append(t) # 启动所有线程 for t in threads: t.start() # 等待所有线程结束 for t in threads: t.join() 在上面的代码中,我们创建了 10 个线程,每个线程都会 插入 一条数据到 test_table 表中。注意,在 插入 数据时,我们使用了 sqlite 3 的连接对象和游标对象,以及 commit() 方法来确保数据 插入 成功。同时,我们还使用了线程锁来避免多个线程同时 插入 数据导致数据冲突。