python下的mysql模块包装

#!/usr/bin/env python
# -*- coding: utf-8 -*-"""
设计db模块的原因:1. 更简单的操作数据库一次数据访问:   数据库连接 => 游标对象 => 执行SQL => 处理异常 => 清理资源。db模块对这些过程进行封装,使得用户仅需关注SQL执行。2. 数据安全用户请求以多线程处理时,为了避免多线程下的数据共享引起的数据混乱,需要将数据连接以ThreadLocal对象传入。
设计db接口:1.设计原则:根据上层调用者设计简单易用的API接口2. 调用接口1. 初始化数据库连接信息create_engine封装了如下功能:1. 为数据库连接 准备需要的配置信息2. 创建数据库连接(由生成的全局对象engine的 connect方法提供)from transwarp import dbdb.create_engine(user='root',password='password',database='test',host='127.0.0.1',port=3306)2. 执行SQL DMLselect 函数封装了如下功能:1.支持一个数据库连接里执行多个SQL语句2.支持链接的自动获取和释放使用样例:users = db.select('select * from user')# users =># [#     { "id": 1, "name": "Michael"},#     { "id": 2, "name": "Bob"},#     { "id": 3, "name": "Adam"}# ]3. 支持事物transaction 函数封装了如下功能:1. 事务也可以嵌套,内层事务会自动合并到外层事务中,这种事务模型足够满足99%的需求
"""import time
import uuid
import functools
import threading
import logging# global engine object:
engine = Nonedef next_id(t=None):"""生成一个唯一id   由 当前时间 + 随机数(由伪随机数得来)拼接得到"""if t is None:t = time.time()return '%015d%s000' % (int(t * 1000), uuid.uuid4().hex)def _profiling(start, sql=''):"""用于剖析sql的执行时间"""t = time.time() - startif t > 0.1:logging.warning('[PROFILING] [DB] %s: %s' % (t, sql))else:logging.info('[PROFILING] [DB] %s: %s' % (t, sql))def create_engine(user, password, database, host='127.0.0.1', port=3306, **kw):"""db模型的核心函数,用于连接数据库, 生成全局对象engine,engine对象持有数据库连接"""import mysql.connectorglobal engineif engine is not None:raise DBError('Engine is already initialized.')params = dict(user=user, password=password, database=database, host=host, port=port)defaults = dict(use_unicode=True, charset='utf8', collation='utf8_general_ci', autocommit=False)for k, v in defaults.iteritems():params[k] = kw.pop(k, v)params.update(kw)params['buffered'] = Trueengine = _Engine(lambda: mysql.connector.connect(**params))# test connection...logging.info('Init mysql engine <%s> ok.' % hex(id(engine)))def connection():"""db模块核心函数,用于获取一个数据库连接通过_ConnectionCtx对 _db_ctx封装,使得惰性连接可以自动获取和释放,也就是可以使用 with语法来处理数据库连接_ConnectionCtx    实现with语法^|_db_ctx           _DbCtx实例^|_DbCtx            获取和释放惰性连接^|_LasyConnection   实现惰性连接"""return _ConnectionCtx()def with_connection(func):"""设计一个装饰器 替换with语法,让代码更优雅比如:@with_connectiondef foo(*args, **kw):f1()f2()f3()"""@functools.wraps(func)def _wrapper(*args, **kw):with _ConnectionCtx():return func(*args, **kw)return _wrapperdef transaction():"""db模块核心函数 用于实现事物功能支持事物:with db.transaction():db.select('...')db.update('...')db.update('...')支持事物嵌套:with db.transaction():transaction1transaction2..."""return _TransactionCtx()def with_transaction(func):"""设计一个装饰器 替换with语法,让代码更优雅比如:@with_transactiondef do_in_transaction():>>> @with_transaction... def update_profile(id, name, rollback):...     u = dict(id=id, name=name, email='%s@test.org' % name, passwd=name, last_modified=time.time())...     insert('user', **u)...     update('update user set passwd=? where id=?', name.upper(), id)...     if rollback:...         raise StandardError('will cause rollback...')>>> update_profile(8080, 'Julia', False)>>> select_one('select * from user where id=?', 8080).passwdu'JULIA'>>> update_profile(9090, 'Robert', True)Traceback (most recent call last):...StandardError: will cause rollback..."""@functools.wraps(func)def _wrapper(*args, **kw):start = time.time()with _TransactionCtx():func(*args, **kw)_profiling(start)return _wrapper@with_connection
def _select(sql, first, *args):"""执行SQL,返回一个结果 或者多个结果组成的列表"""global _db_ctxcursor = Nonesql = sql.replace('?', '%s')logging.info('SQL: %s, ARGS: %s' % (sql, args))try:cursor = _db_ctx.connection.cursor()cursor.execute(sql, args)if cursor.description:names = [x[0] for x in cursor.description]if first:values = cursor.fetchone()if not values:return Nonereturn Dict(names, values)return [Dict(names, x) for x in cursor.fetchall()]finally:if cursor:cursor.close()def select_one(sql, *args):"""执行SQL 仅返回一个结果如果没有结果 返回None如果有1个结果,返回一个结果如果有多个结果,返回第一个结果>>> u1 = dict(id=100, name='Alice', email='alice@test.org', passwd='ABC-12345', last_modified=time.time())>>> u2 = dict(id=101, name='Sarah', email='sarah@test.org', passwd='ABC-12345', last_modified=time.time())>>> insert('user', **u1)1>>> insert('user', **u2)1>>> u = select_one('select * from user where id=?', 100)>>> u.nameu'Alice'>>> select_one('select * from user where email=?', 'abc@email.com')>>> u2 = select_one('select * from user where passwd=? order by email', 'ABC-12345')>>> u2.nameu'Alice'"""return _select(sql, True, *args)def select_int(sql, *args):"""执行一个sql 返回一个数值,注意仅一个数值,如果返回多个数值将触发异常>>> u1 = dict(id=96900, name='Ada', email='ada@test.org', passwd='A-12345', last_modified=time.time())>>> u2 = dict(id=96901, name='Adam', email='adam@test.org', passwd='A-12345', last_modified=time.time())>>> insert('user', **u1)1>>> insert('user', **u2)1>>> select_int('select count(*) from user')5>>> select_int('select count(*) from user where email=?', 'ada@test.org')1>>> select_int('select count(*) from user where email=?', 'notexist@test.org')0>>> select_int('select id from user where email=?', 'ada@test.org')96900>>> select_int('select id, name from user where email=?', 'ada@test.org')Traceback (most recent call last):...MultiColumnsError: Expect only one column."""d = _select(sql, True, *args)if len(d) != 1:raise MultiColumnsError('Expect only one column.')return d.values()[0]def select(sql, *args):"""执行sql 以列表形式返回结果>>> u1 = dict(id=200, name='Wall.E', email='wall.e@test.org', passwd='back-to-earth', last_modified=time.time())>>> u2 = dict(id=201, name='Eva', email='eva@test.org', passwd='back-to-earth', last_modified=time.time())>>> insert('user', **u1)1>>> insert('user', **u2)1>>> L = select('select * from user where id=?', 900900900)>>> L[]>>> L = select('select * from user where id=?', 200)>>> L[0].emailu'wall.e@test.org'>>> L = select('select * from user where passwd=? order by id desc', 'back-to-earth')>>> L[0].nameu'Eva'>>> L[1].nameu'Wall.E'"""return _select(sql, False, *args)@with_connection
def _update(sql, *args):"""执行update 语句,返回update的行数"""global _db_ctxcursor = Nonesql = sql.replace('?', '%s')logging.info('SQL: %s, ARGS: %s' % (sql, args))try:cursor = _db_ctx.connection.cursor()cursor.execute(sql, args)r = cursor.rowcountif _db_ctx.transactions == 0:# no transaction enviroment:logging.info('auto commit')_db_ctx.connection.commit()return rfinally:if cursor:cursor.close()def update(sql, *args):"""执行update 语句,返回update的行数>>> u1 = dict(id=1000, name='Michael', email='michael@test.org', passwd='123456', last_modified=time.time())>>> insert('user', **u1)1>>> u2 = select_one('select * from user where id=?', 1000)>>> u2.emailu'michael@test.org'>>> u2.passwdu'123456'>>> update('update user set email=?, passwd=? where id=?', 'michael@example.org', '654321', 1000)1>>> u3 = select_one('select * from user where id=?', 1000)>>> u3.emailu'michael@example.org'>>> u3.passwdu'654321'>>> update('update user set passwd=? where id=?', '***', '123')0"""return _update(sql, *args)def insert(table, **kw):"""执行insert语句>>> u1 = dict(id=2000, name='Bob', email='bob@test.org', passwd='bobobob', last_modified=time.time())>>> insert('user', **u1)1>>> u2 = select_one('select * from user where id=?', 2000)>>> u2.nameu'Bob'>>> insert('user', **u2)Traceback (most recent call last):...IntegrityError: 1062 (23000): Duplicate entry '2000' for key 'PRIMARY'"""cols, args = zip(*kw.iteritems())sql = 'insert into `%s` (%s) values (%s)' % (table, ','.join(['`%s`' % col for col in cols]), ','.join(['?' for i in range(len(cols))]))return _update(sql, *args)class Dict(dict):"""字典对象实现一个简单的可以通过属性访问的字典,比如 x.key = value"""def __init__(self, names=(), values=(), **kw):super(Dict, self).__init__(**kw)for k, v in zip(names, values):self[k] = vdef __getattr__(self, key):try:return self[key]except KeyError:raise AttributeError(r"'Dict' object has no attribute '%s'" % key)def __setattr__(self, key, value):self[key] = valueclass DBError(Exception):passclass MultiColumnsError(DBError):passclass _Engine(object):"""数据库引擎对象用于保存 db模块的核心函数:create_engine 创建出来的数据库连接"""def __init__(self, connect):self._connect = connectdef connect(self):return self._connect()class _LasyConnection(object):"""惰性连接对象仅当需要cursor对象时,才连接数据库,获取连接"""def __init__(self):self.connection = Nonedef cursor(self):if self.connection is None:_connection = engine.connect()logging.info('[CONNECTION] [OPEN] connection <%s>...' % hex(id(_connection)))self.connection = _connectionreturn self.connection.cursor()def commit(self):self.connection.commit()def rollback(self):self.connection.rollback()def cleanup(self):if self.connection:_connection = self.connectionself.connection = Nonelogging.info('[CONNECTION] [CLOSE] connection <%s>...' % hex(id(connection)))_connection.close()class _DbCtx(threading.local):"""db模块的核心对象, 数据库连接的上下文对象,负责从数据库获取和释放连接取得的连接是惰性连接对象,因此只有调用cursor对象时,才会真正获取数据库连接该对象是一个 Thread local对象,因此绑定在此对象上的数据 仅对本线程可见"""def __init__(self):self.connection = Noneself.transactions = 0def is_init(self):"""返回一个布尔值,用于判断 此对象的初始化状态"""return self.connection is not Nonedef init(self):"""初始化连接的上下文对象,获得一个惰性连接对象"""logging.info('open lazy connection...')self.connection = _LasyConnection()self.transactions = 0def cleanup(self):"""清理连接对象,关闭连接"""self.connection.cleanup()self.connection = Nonedef cursor(self):"""获取cursor对象, 真正取得数据库连接"""return self.connection.cursor()# thread-local db context:
_db_ctx = _DbCtx()class _ConnectionCtx(object):"""因为_DbCtx实现了连接的 获取和释放,但是并没有实现连接的自动获取和释放,_ConnectCtx在 _DbCtx基础上实现了该功能,因此可以对 _ConnectCtx 使用with 语法,比如:with connection():passwith connection():pass"""def __enter__(self):"""获取一个惰性连接对象"""global _db_ctxself.should_cleanup = Falseif not _db_ctx.is_init():_db_ctx.init()self.should_cleanup = Truereturn selfdef __exit__(self, exctype, excvalue, traceback):"""释放连接"""global _db_ctxif self.should_cleanup:_db_ctx.cleanup()class _TransactionCtx(object):"""事务嵌套比Connection嵌套复杂一点,因为事务嵌套需要计数,每遇到一层嵌套就+1,离开一层嵌套就-1,最后到0时提交事务"""def __enter__(self):global _db_ctxself.should_close_conn = Falseif not _db_ctx.is_init():# needs open a connection first:_db_ctx.init()self.should_close_conn = True_db_ctx.transactions += 1logging.info('begin transaction...' if _db_ctx.transactions == 1 else 'join current transaction...')return selfdef __exit__(self, exctype, excvalue, traceback):global _db_ctx_db_ctx.transactions -= 1try:if _db_ctx.transactions == 0:if exctype is None:self.commit()else:self.rollback()finally:if self.should_close_conn:_db_ctx.cleanup()def commit(self):global _db_ctxlogging.info('commit transaction...')try:_db_ctx.connection.commit()logging.info('commit ok.')except:logging.warning('commit failed. try rollback...')_db_ctx.connection.rollback()logging.warning('rollback ok.')raisedef rollback(self):global _db_ctxlogging.warning('rollback transaction...')_db_ctx.connection.rollback()logging.info('rollback ok.')if __name__ == '__main__':logging.basicConfig(level=logging.DEBUG)create_engine('www-data', 'www-data', 'test', '192.168.10.128')update('drop table if exists user')update('create table user (id int primary key, name text, email text, passwd text, last_modified real)')import doctestdoctest.testmod()


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

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

相关文章

【OpenCV 例程200篇】44. 图像的灰度变换(伽马变换)

『youcans 的 OpenCV 例程200篇 - 总目录』 【OpenCV 例程200篇】44. 图像的灰度变换&#xff08;伽马变换&#xff09; 线性灰度变换将原始图像灰度值的动态范围按线性关系扩展到指定范围或整个动态范围。 幂律变换也称伽马变换&#xff0c;可以提升暗部细节&#xff0c;对发…

乱码的解决

关于JSP中request请求中乱码问题的解决 首先request请求有两种请求方式&#xff0c;一是post方法&#xff0c;二是get方法&#xff0c;方法不同&#xff0c;乱码的解决也稍有不同 关于post方法乱码的解决 获取参数之前&#xff0c;在接受请求的页面中规定字符编码格式 <…

【OpenCV 例程300篇】46. 直方图处理之直方图均衡化(cv2.equalizeHist)

『youcans 的 OpenCV 例程300篇 - 总目录』 【youcans 的 OpenCV 例程300篇】46. 直方图处理之直方图均衡化&#xff08;cv2.equalizeHist&#xff09; 图像直方图是反映图像像素分布的统计表&#xff0c;横坐标代表像素值的取值区间&#xff0c;纵坐标代表每一像素值在图像中的…

lingo的初步使用(集)

lingo里面!开始;结束之间的部分是注释。 !什么是集&#xff0c;为啥要有集&#xff1f; 我认为集的概念和面向对象里面的类比较像。一个集可以有一些成员&#xff0c;类似于面向对象里面的对象&#xff0c;集成员有相应的属性&#xff0c;类似面向对象里面的属性。 Lingo有两种…

【OpenCV 例程300篇】47. 直方图处理之直方图匹配

『youcans 的 OpenCV 例程300篇 - 总目录』 【youcans 的 OpenCV 例程300篇】47. 直方图处理之直方图匹配 图像直方图是反映图像像素分布的统计表。 灰度直方图是图像灰度级的函数&#xff0c;用来描述每个灰度级在图像矩阵中的像素个数。 直方图均衡直接对图像全局进行均衡化…

SQLServer查找已知数相邻前后数

查找与一个已知数相邻的前一个数和后一个数 举例解释&#xff1a;在班级排名表中&#xff0c;已经知道张无忌的排名和分数等相关信息&#xff0c;但是想要知道与之相邻的前一个人是谁或者后一个人是谁 1. 数据库的设计和实现 --创建数据库 CREATE DATABASE school ON PRIMAR…

lingo入门(数据部分)

lingo入门(数据部分) 在数据部分也可以指定一些标量变量&#xff08;scalar variables&#xff09;。当一个标量变量在数据部 分确定时&#xff0c;称之为参数。 data: interest_rate .085; enddata还可以指定几个参数data: interest_rate,inflation_rate .085 .03; enddata如…

我的Go+语言初体验——(1)超详细安装教程

我的Go语言初体验——&#xff08;1&#xff09;超详细安装教程 “我的Go语言初体验” | 征文活动进行中… Go 是什么&#xff1f;为数据而生&#xff0c;实现教学、工程与数据的 “三位一体”。 Go 语言的安装和环境配置有些复杂&#xff0c;官方教程也没有写的很详细。 本文…

JAVA增删查改的实现

java程序对SQLServer数据库的数据进行增删查的操作&#xff0c;结果在控制台输出 步骤详解&#xff1a; 设计并实现数据库在数据库中插入相应的数据链接SQLServer数据库实现对数据库的查增删等功能 数据库内容效果图 下面讲述JAVA代码 目录结构 1 . 数据库链接&#xff…

Mac下配置sublime实现LaTeX

在Mac上通过Sublime、Skim编辑LaTeX Sublime Text是一款非常优秀的编辑器&#xff0c;速度快&#xff0c;界面简洁&#xff0c;插件众多。并且能跨平台使用&#xff0c;在Mac和Windows上都能完美使用。虽然是一款付费软件&#xff0c;但作者很厚道地给了无限期的试用期限。这一…

我的Go+语言初体验——(2)IDE 详细安装教程

我的Go语言初体验——&#xff08;2&#xff09;IDE 详细安装教程 “我的Go语言初体验” | 征文活动进行中… Go 语言的安装和环境配置有些复杂&#xff0c;官方教程也没有写的很详细。 通过控制台编写和运行 Go 程序很不方便。本文从零开始&#xff0c;详细介绍 Go 集成开发环…

GoogleNet网络详解与keras实现

GoogleNet网络详解与keras实现 GoogleNet网络详解与keras实现GoogleNet系列网络的概览Pascal_VOC数据集第一层目录第二层目录第三层目录 InceptionV1模块介绍Inception的架构GoogleNet的图片Keras代码实现为了搭建Inception网络我们使用了以下策略整个代码的流程如下 实验结果实…

我的Go+语言初体验——(3)Go+ 语言数据类型

我的Go语言初体验——&#xff08;3&#xff09;Go 语言数据类型 “我的Go语言初体验” | 征文活动进行中… Go 语言刚刚发布&#xff0c;网络上还很难找到各种的支持文档和编程指南&#xff0c;使初学者很难深入地进行学习。 本文结合官方文档与 Go 语言的技术资料&#xff0…

循环输出

使用foreach循环输出List中的数据 步骤详解&#xff1a; 1.数据库的设计和实现 2. Java代码的书写 3. jsp页面的显示 效果图展示 数据库数据 查询结果的显示 功能分析&#xff1a; 链接数据库查找数据库内容把这些内容放入List数组里面用session传递jsp页面获取session内…

我的Go+语言初体验——(4)零基础学习 Go+ 爬虫

我的Go语言初体验——&#xff08;4&#xff09;零基础学习 Go 爬虫 “我的Go语言初体验” | 征文活动进行中… Go 语言非常适合编写爬虫程序&#xff0c;具有并发机制完善、并发数量大、占用资源少、运行速度快、部署方便的优点。 本文结合官方文档与 Go 语言的资料&#xff…

latex的基本使用

LaTeX使用 LaTeX使用基本使用源文件的基本结构中文处理办法字体字号设置文章基本结构特殊字符处理图片的使用表格的使用Texstduio的导入表格功能会更快浮动体的使用数学公式初步矩阵的使用TexStudio里面的矩阵模板功能参考文献使用BibTex定义自己的命令 基本使用 sublime使用…

【OpenCV 例程300篇】48. 直方图处理之彩色直方图匹配

『youcans 的 OpenCV 例程300篇 - 总目录』 【youcans 的 OpenCV 例程300篇】48. 直方图处理之彩色直方图匹配 图像直方图是反映图像像素分布的统计表。 灰度直方图是图像灰度级的函数&#xff0c;用来描述每个灰度级在图像矩阵中的像素个数。 直方图匹配又称为直方图规定化&a…

Vue的安装和配置

Vue是目前最流行的前端框架之一&#xff0c;给大家讲一下如何安装和配置Vue环境。 网上也有许多关于安装和配置Vue的教程&#xff0c;但是他们的方法太过于麻烦了&#xff0c;而且对于初学者来说对网上的一些安装和配置Vue的方法不理解&#xff0c;看了之后还是没有一点思绪&a…

【OpenCV 例程300篇】49. 直方图处理之局部直方图处理(cv2.createCLAHE)

『youcans 的 OpenCV 例程300篇 - 总目录』 【youcans 的 OpenCV 例程300篇】49. 直方图处理之局部直方图处理&#xff08;cv2.createCLAHE&#xff09; 图像直方图是反映图像像素分布的统计表。 灰度直方图是图像灰度级的函数&#xff0c;用来描述每个灰度级在图像矩阵中的像素…

ResNet网络详解与keras实现

ResNet网络详解与keras实现 ResNet网络详解与keras实现Resnet网络的概览Pascal_VOC数据集第一层目录第二层目录第三层目录 梯度退化Residual LearningIdentity vs Projection ShortcutsBottleneck architectureResnet网络构建表ResNet论文结果为了搭建Resnet网络我们使用了以下…