python Day 2 - 编写数据库模块
在一个Web App中,所有数据,包括用户信息、发布的日志、评论等,都存储在数据库中。在awesome-python-app中,我们选择MySQL作为数据库。
Web App里面有很多地方都要访问数据库。访问数据库需要创建数据库连接、游标对象,然后执行SQL语句,最后处理异常,清理资源。这些访问数据库的代码如果分散到各个函数中,势必无法维护,也不利于代码复用。
此外,在一个Web App中,有多个用户会同时访问,系统以多进程或多线程模式来处理每个用户的请求。假设以多线程为例,每个线程在访问数据库时,都必须创建仅属于自身的连接,对别的线程不可见,否则,就会造成数据库操作混乱。
所以,我们还要创建一个简单可靠的数据库访问模型,在一个线程中,能既安全又简单地操作数据库。
为什么不选择SQLAlchemy?SQLAlchemy太庞大,过度地面向对象设计导致API太复杂。
所以我们决定自己设计一个封装基本的SELECT、INSERT、UPDATE和DELETE操作的db模块:transwarp.db。
设计db接口
设计底层模块的原则是,根据上层调用者设计简单易用的API接口,然后,实现模块内部代码。
假设transwarp.db模块已经编写完毕,我们希望以这样的方式来调用它:
首先,初始化数据库连接信息,通过create_engine()函数:
from transwarp import db
db.create_engine(user='root', password='password', database='test', host='127.0.0.1', port=3306)
然后,就可以直接操作SQL了。
如果需要做一个查询,可以直接调用select()方法,返回的是list,每一个元素是用dict表示的对应的行:
users = db.select('select * from user')
# users =>
# [
# { "id": 1, "name": "Michael"},
# { "id": 2, "name": "Bob"},
# { "id": 3, "name": "Adam"}
# ]
如果要执行INSERT、UPDATE或DELETE操作,执行update()方法,返回受影响的行数:
n = db.update('insert into user(id, name) values(?, ?)', 4, 'Jack')
update()函数签名为:
update(sql, *args)
统一用?作为占位符,并传入可变参数来绑定,从根本上避免SQL注入攻击。
每个select()或update()调用,都隐含地自动打开并关闭了数据库连接,这样,上层调用者就完全不必关心数据库底层连接。
但是,如果要在一个数据库连接里执行多个SQL语句怎么办?我们用一个with语句实现:
with db.connection():
db.select('...')
db.update('...')
db.update('...')
如果要在一个数据库事务中执行多个SQL语句怎么办?我们还是用一个with语句实现:
with db.transaction():
db.select('...')
db.update('...')
db.update('...')
实现db模块
由于模块是全局对象,模块变量是全局唯一变量,所以,有两个重要的模块变量:
# db.py # 数据库引擎对象:
class _Engine(object):
def __init__(self, connect):
self._connect = connect
def connect(self):
return self._connect() engine = None # 持有数据库连接的上下文对象:
class _DbCtx(threading.local):
def __init__(self):
self.connection = None
self.transactions = 0 def is_init(self):
return not self.connection is None def init(self):
self.connection = _LasyConnection()
self.transactions = 0 def cleanup(self):
self.connection.cleanup()
self.connection = None def cursor(self):
return self.connection.cursor() _db_ctx = _DbCtx()
由于_db_ctx是threadlocal对象,所以,它持有的数据库连接对于每个线程看到的都是不一样的。任何一个线程都无法访问到其他线程持有的数据库连接。
有了这两个全局变量,我们继续实现数据库连接的上下文,目的是自动获取和释放连接:
class _ConnectionCtx(object):
def __enter__(self):
global _db_ctx
self.should_cleanup = False
if not _db_ctx.is_init():
_db_ctx.init()
self.should_cleanup = True
return self def __exit__(self, exctype, excvalue, traceback):
global _db_ctx
if self.should_cleanup:
_db_ctx.cleanup() def connection():
return _ConnectionCtx()
python Day 2 - 编写数据库模块的更多相关文章
- python import自己编写的模块:import json和simplejson
python import的模块都是库里面的,而自己的模块也可以添加 比如python的json处理,库里没有json文件,import json不行. 网上大部分人告诉你处理json用 dumps和 ...
- Python全栈 MongoDB 数据库(聚合、二进制、GridFS、pymongo模块)
断网了2天 今天补上 聚合操作: 对文档的信息进行整理统计的操作 返回:统计后的文档集合 db.collection.aggregate() 功能:聚合函数,完成聚合操作 参数:聚合条件,配 ...
- Python安装MySQL数据库模块
背景 折腾: [记录]使用Python操作MySQL数据库 的过程中,需要去安装MySQLdb. 下载MySQLdb 去官网: http://pypi.python.org/pypi/MySQL-py ...
- python学习笔记之常用模块(第五天)
参考老师的博客: 金角:http://www.cnblogs.com/alex3714/articles/5161349.html 银角:http://www.cnblogs.com/wupeiqi/ ...
- 用Perl编写Apache模块续二 - SVN动态鉴权实现SVNAuth 禅道版
代码地址:https://code.csdn.net/x3dcn/svnauth 以禅道项目管理系统的数据库结构为标准,实现了可用的svn authz验证功能. 以用户名.密码.项目的acl开发程度o ...
- Python之进程 2 - multiprocessing模块
我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起来的python程序也是一个进程,那么我们也可以在程序中再创建进程.多个进程可以实现并发效果,也就是说, ...
- {Python之线程} 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Threading模块 九 锁 十 信号量 十一 事件Event 十二 条件Condition(了解) 十三 定时器
Python之线程 线程 本节目录 一 背景知识 二 线程与进程的关系 三 线程的特点 四 线程的实际应用场景 五 内存中的线程 六 用户级线程和内核级线程(了解) 七 python与线程 八 Thr ...
- Python操作三大主流数据库☝☝☝
Python操作三大主流数据库☝☝☝ Python 标准数据库接口为 Python DB-API,Python DB-API为开发人员提供了数据库应用编程接口. Python 数据库接口支持非常多的数 ...
- Python操作三大主流数据库✍✍✍
Python操作三大主流数据库 Python 标准数据库接口为 Python DB-API,Python DB-API为开发人员提供了数据库应用编程接口. Python 数据库接口支持非常多的数据库, ...
随机推荐
- localStorage、sessionStorage详解,以及storage事件使用
有关localStorage和sessionStorage的特性. localStorage本身带有方法有 添加键值对:localStorage.setItem(key,value),如果key存在时 ...
- 如何解决PHP中文乱码问题
如何解决PHP中文乱码问题 一.解决HTML中中文乱码问题方法 1.在head标签里面加入UTF8编码(国际化编码):UTF-8是没有国家的编码,也就是独立于任何一种语言,任何语言都可以使用的. ...
- 有反斜杠时候,CakePHP往pgsql插入数据异常
原始数据:INSERT INTO “public”.”tables” (“table”, “columns”) VALUES (‘table1\’, ‘{“col1″:false,”col2″:tru ...
- javaScript & jquery完美判断图片是否加载完毕
好久没写东西了,正好最近因为工作需要,写了一个瀑布流异步加载的程序. 今天就不谈瀑布流,来谈一下关于load的问题. ----------------------------------------- ...
- php图片上传代码
使用copy函数 if (!empty($_FILES)) { //图片 if(isset($_FILES['image'])) { $img_data = $_FILES['image']['tmp ...
- Linux使用问答
1.ubuntu 查看安装的软件包? 在终端输入 sudo dpkg -l http://vardesa.blog.hexun.com/58593247_d.html 其他:http://qiuye. ...
- WordPress标题函数wp_title()详解
在wp_title()中通常是在页面头部的title元素中.当wp_title()在主页主循环(loop)外时,可以用在模板的任何地方. 用法: <?php wp_title( $sep, $e ...
- 如何通过SNMP的OID识别不同厂商的设备
众所周知,SNMP作为通用的网络协议常用于系统监控之中,那么如何借助SNMP来识别不同厂商的设备呢? 事实上,在SNMP的OID树状图中专门有一个节点用于识别各不同的厂商,这个节点是: iso(1) ...
- hdu 4762 && 2013 ACM/ICPC 长春网络赛解题报告
这次的答案是猜出来的,如果做得话应该是应该是一个几何概型的数学题: 答案就是:n/(m^(n-1)); 具体的证明过程: 1.首先枚举这M个点中的的两个端点,概率是:n*(n-1); 2.假设这个蛋糕 ...
- SEO 网站URL优化
很多人都知道URL对SEO的重要之处,但是很多站点却忽略了站点的路径优化.今天本人在这里写几点关于优化路径小篇! 本人结论出关于站点URL在优化中其实也是占为一个相当重要的一个优化!优化站点的URL本 ...