python数据库教程_在Python中编写数据库模块的教程

在一个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()函数:

1

2

from transwarpimport db

db.create_engine(user='root', password='password', database='test', host='127.0.0.1', port=3306)

然后,就可以直接操作SQL了。

如果需要做一个查询,可以直接调用select()方法,返回的是list,每一个元素是用dict表示的对应的行:

1

2

3

4

5

6

7

users= db.select('select * from user')

# users =>

# [

# { "id": 1, "name": "Michael"},

# { "id": 2, "name": "Bob"},

# { "id": 3, "name": "Adam"}

# ]

如果要执行INSERT、UPDATE或DELETE操作,执行update()方法,返回受影响的行数:

1

n= db.update('insert into user(id, name) values(?, ?)',4,'Jack')

update()函数签名为:

1

update(sql,*args)

统一用?作为占位符,并传入可变参数来绑定,从根本上避免SQL注入攻击。

每个select()或update()调用,都隐含地自动打开并关闭了数据库连接,这样,上层调用者就完全不必关心数据库底层连接。

但是,如果要在一个数据库连接里执行多个SQL语句怎么办?我们用一个with语句实现:

1

2

3

4

with db.connection():

db.select('...')

db.update('...')

db.update('...')

如果要在一个数据库事务中执行多个SQL语句怎么办?我们还是用一个with语句实现:

1

2

3

4

with db.transaction():

db.select('...')

db.update('...')

db.update('...')

实现db模块

由于模块是全局对象,模块变量是全局唯一变量,所以,有两个重要的模块变量:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

# 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.connectionis 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对象,所以,它持有的数据库连接对于每个线程看到的都是不一样的。任何一个线程都无法访问到其他线程持有的数据库连接。

有了这两个全局变量,我们继续实现数据库连接的上下文,目的是自动获取和释放连接:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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()

定义了__enter__()和__exit__()的对象可以用于with语句,确保任何情况下__exit__()方法可以被调用。

把_ConnectionCtx的作用域作用到一个函数调用上,可以这么写:

1

2

with connection():

do_some_db_operation()

但是更简单的写法是写个@decorator:

1

2

3

@with_connection

def do_some_db_operation():

pass

这样,我们实现select()、update()方法就更简单了:

1

2

3

4

5

6

7

@with_connection

def select(sql,*args):

pass

@with_connection

def update(sql,*args):

pass

注意到Connection对象是存储在_DbCtx这个threadlocal对象里的,因此,嵌套使用with connection()也没有问题。_DbCtx永远检测当前是否已存在Connection,如果存在,直接使用,如果不存在,则打开一个新的Connection。

对于transaction也是类似的,with transaction()定义了一个数据库事务:

1

2

3

4

with db.transaction():

db.select('...')

db.update('...')

db.update('...')

函数作用域的事务也有一个简化的@decorator:

1

2

3

@with_transaction

def do_in_transaction():

pass

事务也可以嵌套,内层事务会自动合并到外层事务中,这种事务模型足够满足99%的需求。

事务嵌套比Connection嵌套复杂一点,因为事务嵌套需要计数,每遇到一层嵌套就+1,离开一层嵌套就-1,最后到0时提交事务:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

class _TransactionCtx(object):

def __enter__(self):

global _db_ctx

self.should_close_conn= False

if not _db_ctx.is_init():

_db_ctx.init()

self.should_close_conn= True

_db_ctx.transactions= _db_ctx.transactions+ 1

return self

def __exit__(self, exctype, excvalue, traceback):

global _db_ctx

_db_ctx.transactions= _db_ctx.transactions- 1

try:

if _db_ctx.transactions==0:

if exctypeis None:

self.commit()

else:

self.rollback()

finally:

if self.should_close_conn:

_db_ctx.cleanup()

def commit(self):

global _db_ctx

try:

_db_ctx.connection.commit()

except:

_db_ctx.connection.rollback()

raise

def rollback(self):

global _db_ctx

_db_ctx.connection.rollback()

最后,把select()和update()方法实现了,db模块就完成了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

找不到r低版本_R的多进程使用与改进

R的多进程使用与改进在R中需要使用多进程时,常见方案是使用foreach和doParallel的组合。foreachforeach包中最重要的是foreach函数,该函数创建一个foreach对象,随后串行或并行的执行表达式。library(foreach)?foreachout:foreach( ..., .c…

药品研发 计算机系统验证,基于验证的药品研发项目申报系统的设计

摘要:目前国家大力推进信息化与工业化深度融合,提倡"互联网"的概念,信息化已经是现今的一个热名词.计算机系统在各行各业中扮演越来越重要的角色,计算机信息化已经不仅用于信息的管理,更融入了我们日常生活的每一个角落,比如购物,支付等.对于处于制造行业…

html让图片移动到一定位置_百度移动搜索优化指南2.0

百度移动搜索优化指南 2.0前期准备工作【域名】与 PC 网站一样,域名是用户对一个网站的第一印象。一个好的移动域名,不仅容易记忆、易于输入,还能方便用户向其他人推荐。域名应尽量简短易懂,越短的域名记忆成本越低,越…

ddr5内存上市时间_DDR5内存即将开始量产!DDR4内存史低价重现

本月中旬,JEDEC协会正式公布了DDR5标准,起步4800Mbps,未来可以达到6400Mbps,是DDR4内存的两倍多,最高有望达到DDR5-8400的水平。01、DDR5内存要来了DDR5标准公布之后,全球三大DRAM工厂——三星、SK海力士及…

电大法学本科计算机考试题,2016年电大-电大法学本科计算机网考答案.doc

2016年电大-电大法学本科计算机网考答案"更改默认主页"是在Internet Explorer浏览器的选项卡中进行设置,这个选项卡是____。D、常规"美国信息交换标准代码"的缩写是______。 B、ASCII1994年4月20日我国被国际上正式承认为接入Internet的国家,所…

32位mysql安装包_关于Mysql的安装

在安装之前,为保证能够安装成功,请您尝试以下操作:1、卸载原有mysql;2、搜索C:盘中是否有残余的mysql文件,主要是log文件,全部删除;3、为保证能够正常连接服务器,尽量关闭电脑防火墙&#xff1b…

hive sqoop 分区导入_利用oozie,执行sqoop action将DB2中的数据导入到hive分区表中

测试:利用oozie,执行sqoop action将DB2中的数据导入到hive分区表中。需要注意的地方:1,要添加hive.metastore.uris这个参数。否则无法将数据加载到hive表中。并且,如果一个xml文本中有多个这种操作的话,每个…

山东初二计算机会考,2017山东莱芜初二会考科目时间安排:6月14日

考试科目初中学业考试科目、分值和考试时长分别为:语文、数学、英语三科满分均为120分,考试时长均为120分钟,均按原始得分计入总分;思想品德、化学、历史、地理、生物满分均为100分,考试时长均为90分钟,均按考试分数50…

安装 ubuntu18_Ubuntu18.04安装docker及nvidia docker

Ubuntu18.04安装docker及nvidia docker 2之前的时候记得安装完docker之后还需要安装单独的nvidia docker 2,现在的话只需要安装nvidia container toolkit即可1、docker安装官网上又详细的介绍Install Docker Engine on Ubuntu​docs.docker.com或者sudo apt-get upd…

google账号解除游戏绑定_成长守护平台解除实名认证 公众号解绑操作流程

微信成长守护平台是一款培养孩子健康游戏习惯的游戏管控工具,那么微信成长守护平台怎么解除王者荣耀防沉迷呢?接下来小编就给大家带来了解除实名认证方法介绍,一起来看看吧!先简单了解一下游戏成长守护平台,它的运作方…

微软云服务器怎么注销,Microsoft 账户删除及注销

您好,了解到您要取消与当前Microsoft账户的连接。设置-账户-你的账户中,看下有没有断开连接的选项。现在是在第一次开机后的配置界面直接输入了这个邮箱账户吗?如果是这样的话,最好使用重置功能,选择不保留个人文件进行…

如何把python文件发给别人没_python怎么将py文件弄成exe

pandas 生成一列是另一列的累加结果,怎么做与怪物战斗的人,应当小心自己不要成为怪物。当你远远凝视深渊时,深渊也在凝视你。 pandas绘图不显示python用pandas库的绘图语句绘图,如何看到图? left pd.DataFrame({可以显…

混凝土地坪机器人_地面整平机器人:精准又高效,轻松摆“平”混凝土

随着国内经济不断发展,工业厂房、大型广场、体育场、停车场等大面积场地的建设需求越来越多。这类场地大多使用混凝土现场浇筑地基,然后再覆盖地砖或地坪漆,因此对基础层的平整度提出了很高的要求。传统的混凝土地坪施工方法是人工找平&#…

大学计算机成绩统计表怎么做,wps怎么制作成绩表 wps设计成绩统计表的步骤方法...

当我们使用wps统计数据时,如果我们需要制作一个统计成绩的表格,可是怎么制作成绩表吗?其实方法非常的简单,下面教程之家网为大家分享wps设计成绩统计表的步骤方法,不会制作的朋友可以参考下面的步骤方法自己制作即可。wps怎么制作…

chackbox的值 php获取_最详细最全的PHP面试题(附答案)

这篇文章介绍的内容是关于最全最详细的PHP面试题(带有答案),有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下相关推荐:程序猿的生活:面试12家公司,收获9个offer,2020年PHP 面试问题…

python适合安装什么开发环境_python开发环境安装

1、首先安装python-3.4.2.msi,此为python主程序,双击安装,根据自身的情况做选择,也可以使用默认设置,一路next也没什么问题。 2、设置环境变量>编辑Path,在最后加上你的python安装路径。我的安装路径是&…

服务器iis的作用,IIS是什么 IIS服务组件有什么作用

在网上或者一些技术社区我们经常会遇到一些讨论IIS问题文章。那么究竟IIS是什么?有什么用呢?不少电脑爱好者对IIS都充满兴趣,以下脚本之家小编为大家简单介绍下。IIS是什么?IIS是Internet Information Services英文全称的缩写,是…

服务器ssr进程启动怎么运行,要SSR? NUXT项目从初始化到部署服务器流程全记录

首先,简单介绍一下, nuxt.js 是什么Nuxt.js 是一个 Vue.js的SSR通用框架,最常用的就是用来作SSR(服务器端渲染)。首先说下 SSR,最近很热的词,意为 Server Side Rendering(服务端渲染),目的是为了解决单页面应用的 SEO 优化 的问题…

4修改初始值_Java基础语法 --4(连载)

第一部分 : IDEA开发工具参见 :IEDA的安装请参考文件夹PPT中的 04_IDEA.ppt1.数组1.1 数组介绍​ 数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致。 1.2 数组的定义格式1.2.1 第一种格式​ 数据类型[] 数组名​ 示例:int[] ar…

python字典常用方法_Python 字典的常见操作

字典 字典的增删改查 字典的创建方式: #创建字典类型 info {name:李白,age:25,sex:男} msg{user01:Longzeluola,user02:xiaozemaliya,user03:cangjingkong} 字典存储数据的时候,采取的是key:value的形式,是一组无序的存储。在需要的时候通过k…