sqlite3 事务
1. 什么是事务
在数据库管理系统中,事务(Transaction)是指作为一个逻辑单位的一组数据库操作,这些操作要么都执行,要么都不执行。事务可以保证数据库的一致性和完整性。
事务具有以下四个特性(ACID):
- 原子性(Atomicity):一个事务中的所有操作要么全部成功,要么全部失败,不允许部分操作成功。
- 一致性(Consistency):事务的执行保持数据库的一致状态,从一个一致的状态转移到另一个一致的状态。
- 隔离性(Isolation):并发执行的事务之间是相互隔离的,一个事务看不到另一个事务的中间状态。事务之间的执行是串行化的。
- 持久性(Durability):一旦事务提交,其所做的修改就会永久保存到数据库,即使发生系统故障也不会丢失。
2. SQLite3 事务
SQLite3 是一种轻量级的嵌入式关系型数据库,支持事务功能。在 SQLite3 中,事务是通过对 SQL 语句进行操作来实现的。
SQLite3 使用以下语句来控制事务:
- BEGIN:开始一个事务。
- COMMIT:提交一个事务,使得对数据库的修改永久生效。
- ROLLBACK:回滚一个事务,撤销对数据库的修改。
SQLite3 还支持自动提交事务的功能。当没有显式地使用 BEGIN 和 COMMIT 语句时,每个 SQL 语句都会被视为一个事务,并自动提交。
3. SQLite3 事务的用法
3.1 手动控制事务
在 SQLite3 中,可以使用 BEGIN 和 COMMIT 语句手动控制事务的开始和提交。下面是一个示例代码:
import sqlite3
# 连接到 SQLite 数据库
conn = sqlite3.connect('example.db')
c = conn.cursor()
# 创建一个表格
c.execute('''CREATE TABLE IF NOT EXISTS books
(id INT PRIMARY KEY,
title TEXT,
author TEXT)''')
# 开始事务
c.execute("BEGIN")
# 插入数据
c.execute("INSERT INTO books (id, title, author) VALUES (1, 'Book 1', 'Author 1')")
c.execute("INSERT INTO books (id, title, author) VALUES (2, 'Book 2', 'Author 2')")
# 提交事务
c.execute("COMMIT")
# 关闭数据库连接
conn.close()
上述代码中,首先使用 BEGIN
语句开始事务,然后执行插入操作,最后使用 COMMIT
语句提交事务。如果在插入操作之后发生错误,可以使用 ROLLBACK
语句回滚事务,撤销对数据库的修改。
3.2 自动提交事务
SQLite3 默认情况下会自动提交每个 SQL 语句,因此不需要显式地使用 BEGIN
和 COMMIT
语句。下面是一个示例代码:
import sqlite3
# 连接到 SQLite 数据库
conn = sqlite3.connect('example.db')
c = conn.cursor()
# 创建一个表格
c.execute('''CREATE TABLE IF NOT EXISTS books
(id INT PRIMARY KEY,
title TEXT,
author TEXT)''')
# 插入数据,这里不需要使用 BEGIN 和 COMMIT 语句
c.execute("INSERT INTO books (id, title, author) VALUES (1, 'Book 1', 'Author 1')")
c.execute("INSERT INTO books (id, title, author) VALUES (2, 'Book 2', 'Author 2')")
# 关闭数据库连接
conn.close()
上述代码中,不需要显式地使用 BEGIN
和 COMMIT
语句,每个插入语句都会自动成为一个事务,并自动提交。
3.3 回滚事务
在发生错误或其他异常情况时,可以使用 ROLLBACK
语句回滚事务,撤销对数据库的修改。下面是一个示例代码:
import sqlite3
# 连接到 SQLite 数据库
conn = sqlite3.connect('example.db')
c = conn.cursor()
# 创建一个表格
c.execute('''CREATE TABLE IF NOT EXISTS books
(id INT PRIMARY KEY,
title TEXT,
author TEXT)''')
try:
# 开始事务
c.execute("BEGIN")
# 插入数据
c.execute("INSERT INTO books (id, title, author) VALUES (1, 'Book 1', 'Author 1')")
c.execute("INSERT INTO books (id, title, author) VALUES (2, 'Book 2', 'Author 2')")
# 抛出异常
raise Exception("Simulated exception")
# 提交事务
c.execute("COMMIT")
except:
# 回滚事务
c.execute("ROLLBACK")
# 关闭数据库连接
conn.close()
上述代码中,抛出了一个异常,触发了回滚操作。在回滚操作后,数据库中的修改将被撤销。
4. SQLite3 事务的性能优化
在使用 SQLite3 事务时,以下技巧可以帮助提高性能:
4.1 批量操作
将多个操作合并为一个事务,可以减少事务的开销,提高性能。以下是一个示例代码:
import sqlite3
# 连接到 SQLite 数据库
conn = sqlite3.connect('example.db')
c = conn.cursor()
# 创建一个表格
c.execute('''CREATE TABLE IF NOT EXISTS books
(id INT PRIMARY KEY,
title TEXT,
author TEXT)''')
# 开始事务
c.execute("BEGIN")
# 批量插入数据
books = [(3, 'Book 3', 'Author 3'), (4, 'Book 4', 'Author 4')]
c.executemany("INSERT INTO books (id, title, author) VALUES (?, ?, ?)", books)
# 提交事务
c.execute("COMMIT")
# 关闭数据库连接
conn.close()
上述代码中,使用 executemany
方法一次性插入多条数据,减少了事务的开销。
4.2 禁用日志
在 SQLite3 中,默认会将每个事务的操作记录在内存中的日志文件中。禁用日志文件可以进一步提高性能。以下是一个示例代码:
import sqlite3
# 连接到 SQLite 数据库
conn = sqlite3.connect('example.db')
c = conn.cursor()
# 禁用日志
c.execute("PRAGMA journal_mode = OFF")
# 创建一个表格
c.execute('''CREATE TABLE IF NOT EXISTS books
(id INT PRIMARY KEY,
title TEXT,
author TEXT)''')
# 开始事务
c.execute("BEGIN")
# 插入数据
c.execute("INSERT INTO books (id, title, author) VALUES (1, 'Book 1', 'Author 1')")
c.execute("INSERT INTO books (id, title, author) VALUES (2, 'Book 2', 'Author 2')")
# 提交事务
c.execute("COMMIT")
# 关闭数据库连接
conn.close()
上述代码中,通过使用 PRAGMA journal_mode = OFF
语句禁用了日志文件,从而提高了性能。在高负载场景下,禁用日志可以显著减少磁盘操作,加快事务处理速度。
5. 总结
本文详细介绍了 SQLite3 中事务的概念和用法。通过手动控制事务的开始和提交,或者使用自动提交事务的功能,可以确保数据库操作的原子性、一致性、隔离性和持久性。另外,通过批量操作和禁用日志等性能优化技巧,还可以提高事务处理的效率。SQLite3 提供了简单而强大的事务支持,使得在开发数据库应用程序时更加灵活和可靠。