python使用上下文管理器实现sqlite3事务机制
如题,本文记录如何使用python上下文管理器的方式管理sqlite3的句柄创建和释放以及事务机制。
1、python上下文管理(with)
python上下文管理(context),解决的是这样一类问题,在进入逻辑之前需要进行一些准备工作,在退出逻辑之前需要进行一些善后工作,上下文管理可以使得这种场景变得清晰和可控。
with语句是python上下文管理的基本用法,例如读写文件
with open('filea', r) as f:
f.readlines()
file使用的就是上下文管理机制,这样对于打开文件句柄和释放文件句柄无须我们额外的投入精力。
2、sqlite3
sqlite3是一个嵌入式的文件数据库,无须开启额外的进程和端口,就可以通过文件读取的方式实现数据库的操作。优点是轻量级并且支持事务和触发器等高级特性。
sqlite3在python句柄创建和管理上跟mysql表现的很相似。
3、代码
我们先贴上本文简述的这段代码,然后后面我们在做详细解释。
# -*- coding:utf-8 -*-
import sqlite3
import traceback
class SqliteDB(object):
def __init__(self, database='sqlitedb', isolation_level='', ignore_exc=False):
self.database = database
self.isolation_level = isolation_level
self.ignore_exc = ignore_exc
self.connection = None
self.cursor = None
def __enter__(self):
try:
self.connection = sqlite3.connect(database=self.database, isolation_level=self.isolation_level)
self.cursor = self.connection.cursor()
return self.cursor
except Exception, ex:
traceback.print_exc()
raise ex
def __exit__(self, exc_type, exc_val, exc_tb):
try:
if not exc_type is None:
self.connection.rollback()
return self.ignore_exc
else:
self.connection.commit()
except Exception, ex:
traceback.print_exc()
raise ex
finally:
self.cursor.close()
self.connection.close()
我们给出一个使用的case
if __name__ == '__main__':
# 建表
with SqliteDB('test') as db:
db.execute('create table if not exists user (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(100), age INTEGER)')
# 创建一条记录, 如果抛出异常, 可以测试事务回滚
with SqliteDB('test') as db:
db.execute('insert into user (name, age) values (?, ?)', ('Tom', 10))
#raise Exception()
# 查询记录
with SqliteDB('test') as db:
query_set = db.execute('select * from user where name=? limit ?', ('Tom', 100,)).fetchall()
print len(query_set)
for item in query_set:
print item
# 删除记录
with SqliteDB('test') as db:
query_set = db.execute('delete from user where name=?', ('Tom',))
可以看到通过with语句打开了数据库的句柄,执行数据库操作后,我们并没有管理句柄的释放和事务回滚。
代码的输出是:
1
(6, u'Tom', 10)
当打开raise Exception()的注释,表示在插入的过程中遇到了异常。这时候所有connection中未被提交的数据将被回滚。
那么,这些如何做到的呢?
上下文管理是通过类SqliteDB中的__enter__和__exit__两个魔法函数实现的。
1、enter函数,用来实现处理进入with_body之前的准备工作,这里是创建connect和cursor,enter方法返回了cursor。
enter函数如果有返回值,那么可以赋值给as后面的变量,如果没有返回,可以简单的去掉as子句即可。我们给出一个没有as子句的例子
lock = threading.Lock()
with lock:
pass
如果enter函数抛出异常,那么在执行with语句的时候会抛出这个异常,并且中断程序。
2、逻辑上,enter函数之后,便开始执行with_body内的代码,with_body里的代码包含sql语句和一些业务逻辑,这里说明一下,只要是抛出异常就会触发事务的回滚机制,而不会区分到底是sql语句执行异常还是业务逻辑出现的异常。
3、exit函数,在with_body执行成功或者抛出异常后会执行exit函数。
exit函数传入三个变量,分别是exc_type异常类型,exc_val异常值,exc_tb错误堆栈信息。如果程序正常,那么三个值都是None,相反如果不是None,那么可以就此判断with_body产生了异常。
这里,我们判断了exc_type是否为None,来区分是否抛出了异常,如果抛出了异常我们使用connection.rollback进行了事务的回滚,否则我们使用connection.commit进行事务提交。
要注意的是,在出现异常的时候,返回了一个ignore_exc,这个返回如果是True,表示忽略这个异常,这个异常将不会向上级调用抛出,如果返回的是None或者False,异常将会向上抛出。实际中我们还是希望异常能够跑出来,方便处理,所以这里我们默认为False。
注意:
isolation_level这个字段是隔离级别,这里我们不做深入的说明。需要知道的是这个字段
1)传入空字符串‘’,表示手动提交commit,这时需要程序中显示的执行connection.commit进行事务提交,sql中的dml语句才会生效。
2)传入None,表示开启自动提交,这时候自动提交commit,无需在程序中connection.commit进行事务提交。
- 初探Anaconda——最省心的Python版本和第三方库管理
- Linux环境下JDK/Eclipse一键安装脚本
- (31) 剖析Arrays / 计算机程序的思维逻辑
- 应用自然语言处理(NLP)解码电影
- 不引入新的数组,实现数组元素交换位置函数
- (30) 剖析StringBuilder / 计算机程序的思维逻辑
- Java初始化顺序
- ConcurrentHashMap使用示例
- (40) 剖析HashMap / 计算机程序的思维逻辑
- nginx配置https(亲测可用)
- linux中无 conio.h的解决办法
- 运用适配器模式应对项目中的变化
- 开车啦!小爬虫抓取今日头条街拍美女图
- C语言中随机数相关问题
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法