SQLite是一款嵌入式关系型数据库,整个数据库就是一个单独的文件,不需要像MySQL那样单独安装和启动服务。Python的标准库中内置了sqlite3模块,因此只要装好了Python,就可以直接操作SQLite数据库。这篇文章将从创建数据库文件开始,一步步演示建表、插入数据、查询数据以及连接管理的常见做法。

一、创建数据库并建立连接
操作SQLite的第一步是建立连接。sqlite3.connect()接收一个文件路径作为参数,如果该文件不存在,SQLite会自动创建一个新的数据库文件。如果传入的是:memory:,则会在内存中创建一个临时数据库,程序结束后数据消失,适合做测试或临时缓存。
import sqlite3
# 连接数据库,如果文件不存在则自动创建
conn = sqlite3.connect('test.db')
# 创建游标对象,用于执行SQL语句
cursor = conn.cursor()
# 关闭连接释放资源
cursor.close()
conn.close()执行上面的代码后,当前目录下会生成一个test.db文件,这就是一个完整的SQLite数据库。值得注意的是,即使不执行任何SQL语句,连接对象创建后文件也会生成,但只有调用了commit()或关闭连接后,数据才会真正写入磁盘。
建议使用with语句管理连接,这样无论是否发生异常,连接都会被正确关闭,代码也更加简洁:
import sqlite3
with sqlite3.connect('test.db') as conn:
cursor = conn.cursor()
# 在with块中的操作会自动提交事务
cursor.execute('SELECT SQLITE_VERSION()')
print(cursor.fetchone())需要注意一点,with语句只负责提交事务和关闭连接,并不会自动关闭游标。游标对象在连接关闭后会被垃圾回收机制回收,但显式关闭仍是更好的习惯。
二、创建数据表并插入数据
有了连接之后,就可以通过游标执行SQL语句来创建表。下面的例子创建一个用户表,包含自增主键、用户名和邮箱三个字段,并插入几条测试数据:
import sqlite3
with sqlite3.connect('test.db') as conn:
cursor = conn.cursor()
# 创建用户表
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
email TEXT UNIQUE
)
''')
# 插入单条数据
cursor.execute(
'INSERT INTO users (username, email) VALUES (?, ?)',
('张三', 'zhangsan@ipipp.com')
)
# 插入多条数据
users = [
('李四', 'lisi@ipipp.com'),
('王五', 'wangwu@ipipp.com'),
]
cursor.executemany(
'INSERT INTO users (username, email) VALUES (?, ?)',
users
)
# 查询确认
for row in cursor.execute('SELECT * FROM users'):
print(row)这里有几个关键点值得展开说明。第一,SQL语句中使用?作为占位符,通过元组传入参数,这种参数化查询方式能有效防止SQL注入攻击,绝对不要用字符串拼接的方式构造SQL。第二,CREATE TABLE IF NOT EXISTS可以避免重复建表时报错。第三,executemany()适合批量插入,比循环调用execute()效率更高。
如果插入时违反了约束条件,例如向email这个UNIQUE字段插入重复值,会抛出sqlite3.IntegrityError异常,可以用try语句捕获处理:
import sqlite3
try:
with sqlite3.connect('test.db') as conn:
cursor = conn.cursor()
cursor.execute(
'INSERT INTO users (username, email) VALUES (?, ?)',
('赵六', 'zhangsan@ipipp.com') # 邮箱重复
)
except sqlite3.IntegrityError as e:
print('插入失败:', e)三、查询数据与结果处理
查询操作同样通过游标完成。常用的获取结果方法有三个:fetchone()返回下一条记录,fetchall()返回所有剩余记录,fetchmany(n)返回n条记录。如果直接遍历游标对象,也可以逐条取出结果。
import sqlite3
with sqlite3.connect('test.db') as conn:
conn.row_factory = sqlite3.Row # 让查询结果支持按列名访问
cursor = conn.cursor()
cursor.execute('SELECT id, username, email FROM users WHERE id > ?', (1,))
row = cursor.fetchone()
print(row['username'], row['email'])
for r in cursor.fetchall():
print(dict(r)) # 可以直接转成字典默认情况下,查询结果是以元组形式返回的,只能通过下标访问。将row_factory设置为sqlite3.Row后,就可以用列名访问字段,代码可读性大大提升,这在表字段较多时尤为实用。此外还可以用cursor.description获取列名信息,方便动态生成表头。
更新和删除操作与插入类似,同样是执行SQL语句后提交事务。例如更新用户邮箱、删除指定记录:
with sqlite3.connect('test.db') as conn:
cursor = conn.cursor()
cursor.execute('UPDATE users SET email = ? WHERE username = ?', ('new@ipipp.com', '张三'))
print('更新了', cursor.rowcount, '条记录')
cursor.execute('DELETE FROM users WHERE username = ?', ('王五',))
print('删除了', cursor.rowcount, '条记录')rowcount属性返回受影响的行数,可以用来判断操作是否真正生效,这在调试数据操作逻辑时非常有用。
四、实用技巧与常见问题
再补充几个实际开发中经常用到的技巧。首先是备份问题,由于SQLite数据库就是单个文件,直接复制.db文件即可完成冷备份,也可以用conn.backup()方法在程序运行中安全备份。其次是性能问题,大量写入时建议把多次操作放在同一个事务中批量提交,能显著减少磁盘IO次数。
常见报错方面:sqlite3.OperationalError: no such table通常表示表还没创建或者连接到了错误的数据库文件;database is locked多发生在多个连接同时写入时,SQLite默认不支持高并发写入,可以通过设置超时时间sqlite3.connect('test.db', timeout=10)缓解,或者在写入频繁的场景考虑换用MySQL、PostgreSQL这类独立数据库服务。
最后提醒一下,如果使用的是较老的Python版本,连接后可能遇到中文乱码问题,确认数据库文件编码即可;而Python 3的sqlite3模块默认以UTF-8处理文本,一般无需额外配置。掌握以上内容后,你就可以在Python中自如地创建和管理SQLite数据库了,无论是写个小爬虫存数据,还是做桌面软件的本地存储,都完全够用。