Python数据库编程之关系数据库API规范

news2024/11/25 16:21:53

Python关系数据库API规范

对于关系数据库的访问,Python社区已经制定出一个标准,称为Python Database API Specification。Mysql,Oracal等特定数据库模块遵从这一规范,而且可以添加更多特性。

高级数据库API定义了一组用于连接数据库服务器、执行SQL查询并获得结果的函数和对象。其中有两个主要对象:

  • 用于管理数据库连接的Connection对象
  • 用于执行查询的Cursor对象

一、连接(Connection)

为了连接到数据库,每个数据库模块都提供了一个模块级函数connect(parameters)。其中实际使用的参数因为数据库不同而可能不同,但是通常都包含数据源名称、用户名、密码、主机名称和数据库名称等信息。通常情况下,这些信息分别通过关键字参数dsn/user/password/host/database提供。所以可以这样调用:

connect(dsn="hostname:DBNAME", user="xxx", password="xxx")

如果成功,返回Connection对象。Connection对象的实例c有如下方法:

  • c.close()
    关闭与服务器的连接

  • c.commit()
    将所有未完成的事务提交到数据库。如果数据库支持事务处理,那么要使任何变更生效都必须调用这一方法。如果底层数据库不支持事务处理,这一方法没有任何作用。

  • c.rollback()
    将数据库回滚到未完成事务的开始状态。有时,这一方法可用于不支持事务处理的数据库,以撤销对数据库作出的更改。例如,如果在更新数据库的过程中代码发生异常,可以使用这个方法来在异常出现之前撤销对数据库做出的更改。

  • c.cursor()
    创建一个使用连接的新的Cursor对象。cursor是一个对象,你可以使用它执行SQL查询并获得结果。

二、游标(Cursor)

为了在数据库上执行操作,首先必须创建一个连接c,然后调用c.cursor()方法创建Cursor对象。Cursor的实例cur有一些用于执行查询的标准方法和属性。

  • cur.callproc(procname [, parameters])
    调用一个名为procname的存储过程,parameters是一个序列的值,用作该存储过程的参数。函数的结果也是一个序列,项数与parameters相同。它本来是parameters的副本,函数执行后,每一个输出参数的值都被修改值所替换。如果该过程还生成一组输出,可以使用fetch*()方法来读取。

  • cur.close()
    关闭游标,防止再对其进行操作。

  • cur.execute(query, [, parameters])
    在数据库上执行查询或query命令。query是一个包含命令(通常是SQL语句)的字符串,parameters是一个序列或映射,用于为查询字符串中的变量赋值。

  • cur.executemany(query, [, parameters])
    重复执行查询或命令。query是一个查询字符串,parameters是一个参数序列。这一序列的每一项都是一个序列或映射对象,他们可以使用上面提到的execute()方法得到。

  • cur.fetchone()
    返回有execute()或executemany()生成的下一行结果集。这一结果通常是列表或元组,包含结果中的不同列的值。如果没有更多的行,返回None。如果没有未处理完的结果或者如果以前执行的操作没有生成结果集,就会提示异常。

  • cur.fetchmany([size])
    返回结果行的序列(例如,元组列表)。size是要返回的行数。如果省略,cur.arraysize的值就会作为默认值使用。实际返回的行数可能比请求的少,如果没有更多的行,就会返回空的序列。

  • cur.fetchall()
    返回全部剩余结果行的序列。(例如,元组列表)

  • cur.nextset()
    放弃当前结果集中的所有剩余行,跳至下一个结果集(如果有的话)。如果没有更多的结果集,返回None,否则返回True,接着通过fetch*()操作从新的集合中返回数据。

  • cur.setinputsize(sizes)
    给游标一个提示,说明要在接下来的execute*()方法中传递的参数。sizes是一个剪短描述类型对象的序列或者是代表每一参数预期最高字符串长度的整数序列。在内部,这用于预定义内存缓冲区,来创建发送至数据库的查询和命令。使用这个方法能够加速接下来的execute*()操作。

  • cur.setoutputsize(size [, column])
    为特定的列设定缓冲区容量。column是结果行的整数索引,而size是字节的数目。这种方法通常用于在调用execute*()之前,在一个大型的数据库列(如字符串、BLOB和LONG)上设定上限。如果column省略,则为结果中的所有列设定的上限。

游标有一系列属性,用来描述当前的结果集,并提供关于游标本身的信息。

  • cur.arraysize
    为fetchmany()操作提供默认的一个整数值。该值因数据库模块的不同而有所不同,可将其初始值设置为在本模块中“最佳”的值。

  • cur.description
    提供当前结果集中的每一列的信息的一个元组序列。每一个元组都包括(name, type_code, display_size, internal_size, precision, scale, null_ok)。通常需要定义第一个字段并使之与列名称相对应。type_code可以用于涉及类型对象的比较。其他字段如果不适用该列,可以设置为None。

  • cur.rowcount
    表示由一种execute*()方法生成的最后结果中的行数。如果设置为-1,意味着既没有结果集,行数也不能确定。

虽然没有在规范中要求,但大多数数据库模块中的Cursor对象也执行迭代协议。在这种情况下,像for row in cur:这样的语句将迭代由最后一次execute*()方法生成的结果集的行。

下面是一个简单的例子,演示了如何通过sqlite3数据库模块使用这些操作,sqlite3数据库模块是一个内置库。

import sqlite3

connection = sqlite3.connect("dbfile")
cur = connection.cursor()

# 简单的查询示例
cur.execute('select name, age, sex from students where age < 20')

# 循环查询结果
while True:
    row = cur.fetchone()
    if not row:
        break
    # 处理每行的结果
    name, age, sex = row
    print(f'name:{name}, age:{age}, sex:{sex}')
    
# 一种替代方法,使用迭代
cur.execute('select name, age, sex from students where age > 20')
for name, age, sex in cur:
    # 处理每行的结果
    print(f'name:{name}, age:{age}, sex:{sex}')

三、生成查询

使用数据库API的关键是生成SQL查询字符串,以便将其传递到execute*()方法中。问题是,你需要根据用户提供的参数填充查询字符串的各个部分。例如:

my_name = 'hubing'
my_account = 123456

cur.execute(f"select shares from bank where name = {my_name} and account = {my_account}")

虽然这能够工作,但也绝不能这样使用python字符串操作手动生成查询。如果这样做,代码将可能受到SQL注入的攻击。它是一个漏洞,攻击者可以利用它在数据库服务器上随意执行语句。例如,在以前的代码中,有些人可能为my_name应用了类似于“EVEL LAUGH; drop table bank; --"的值,而这可能得到出乎意料的结果。

所有的数据库模块在值替换上都有各自的机制。例如,下面这段代码,与生成整个查询不同,你可能会这样做:

my_name = 'hubing'
my_account = 123456
cur.execute("select shares from bank where name = ? and account = ?", (my_name, my_account))

这里,占位符 ? 后来被元组 (my_name, my_account) 中的值替换。

然而,在整个数据库模块实现中没有关于占位符的标准规则。但是,每一个模块都定义了一个变量paramstyle, 它描述了将在查询中使用的值替换格式。这一变量可能的值如下:

20221130001542

四、类型对象

当使用数据库时,内置类型(例如整数和字符串)通常以相应类型映射到数据库中。然而,对于日期、二进制数据和其他特殊类型,数据管理变得棘手。为了辅助这一映射,数据库模块实现了一组构造函数,用于创建各种类型的对象。

  • Date(year, month, day)
    创建表示日期的对象。

  • Time(hour, minute, second)
    创建表示时间的对象

  • Timestamp(year, month, day, hour, minute, second)
    创建表示时间戳的对象

  • DateFromTicks(ticks)
    根据系统时间创建日期对象。ticks是秒数,就是函数time.time()返回的一样

  • TimeFromTicks(ticks)
    根据系统时间创建时间对象。

  • TimestampFromTicks(ticks)
    根据系统时间创建时间戳对象。

  • Binary(s)
    根据字节字符串s创建二进制对象。

除了上述构造函数外,可以定义如下类型的对象。这些代码的目的是对type_code的cur.description字段执行类型检查。该字段描述了当前结果集的内容。

20221130002146

五、处理错误

数据库模块定义了一个高级异常Error,作为所有其他错误的基类。下列的异常是更加具体的数据库错误。

20221130002302

模块也可以定义一个Warning异常,由数据库模块使用,就更新过程中出现的数据截断等事件发出警告。

六、多线程

如果将数据库访问与多线程混合,底层的数据库模块可能是线程安全的,也可能不安全。下列变量已在每一个模块中定义,以提供更多的信息。

  • threadsafety

这是一个说明模块线程安全性的整数。其可能的值是:

  • 0, 没有线程安全。线程不能共享模块的任何部分
  • 1, 该模块是线程安全的。但是连接是不能共享的
  • 2, 模块和连接都是线程安全的,但是游标是不能共享的
  • 3, 模块、连接和游标都是线程安全的

七、将结果映射到字典中

关于数据库结果的共同问题是:要将元组或列表映射到命名字段字典中。例如,如果查询的结果集包含大量的列,使用描述性字段名称来利用数据就更加容易,而不用通过硬编码元组中特定字段的数字索引来实现。

有许多方式实现这一点,但是处理结果数据最好的方式是使用生成器函数,例如:

def generate_dicts(cur):
    import itertools
    fieldnames = [ d[0].lower() for d in cur.description ]
    while True:
        rows = cur.fetchmany()
        if not rows:
            return
        for row in rows:
            yield dict(itertools.izip(fieldnames, row))

# 使用样例
cur.execute("select name, shares, price from testtable")
for r in generate_dicts(cur):
    print(r['name'])
    print(r['shares'])
    print(r['price'])

注意, 列的名称在不同的数据库中并不完全一致,特别是否区分大小写之类的事情。所以,在使用这一方法来编码时必须小心,因为这以为着与多个不同的数据库模块一起使用。

小手一抖,点个赞再走哦

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

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

相关文章

三十六、Java 泛型

Java 泛型 Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制&#xff0c;该机制允许程序员在编译时检测到非法的类型。 泛型的本质是参数化类型&#xff0c;也就是说所操作的数据类型被指定为一个参数。 假定我们有这…

火山引擎 DataLeap 的 Data Catalog 系统公有云实践

Data Catalog 通过汇总技术和业务元数据&#xff0c;解决大数据生产者组织梳理数据、数据消费者找数和理解数的业务场景。本篇内容源自于火山引擎大数据研发治理套件 DataLeap 中的 Data Catalog 功能模块的实践&#xff0c;主要介绍 Data Catalog 在公有云部署和发布中遇到挑战…

5. LSTM的C++实现

[C 基于Eigen库实现CRN前向推理] 第三部分&#xff1a;TransposedConv2d实现 &#xff08;含dilation&#xff09; 前言&#xff1a;(Eigen库使用记录)第一部分&#xff1a;WavFile.class (实现读取wav/pcm,实现STFT)第二部分&#xff1a;Conv2d实现第三部分&#xff1a;Tran…

你知道不同U盘在ARM+Linux下的读写速率吗?

优秀的产品离不开完善的测试&#xff0c;即使一个简单的USB接口也要确保稳定性及兼容性。不同的U盘在ARMLinux板卡下的兼容性、速率怎么样呢&#xff1f;本文将为大家提供测试参考数据及详细测试步骤&#xff01; 1. 测试准备 主控选用最近发布的64位Cortex-A55核心板&#xff…

设计模式-day01

1&#xff0c;设计模式概述 1.1 软件设计模式的产生背景 "设计模式"最初并不是出现在软件设计中&#xff0c;而是被用于建筑领域的设计中。 1977年美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任克里斯托夫亚历山大&#xff08;Christopher Alexand…

深入理解SR-IOV和IO虚拟化

一、背景 SR-IOV&#xff08;Single Root I/O Virtualization&#xff09;是由PCI-SIG组织定义的PCIe规范的扩展规范《Single Root I/O Virtualization and Sharing Specification》&#xff0c;目的是通过提供一种标准规范&#xff0c;为VM&#xff08;虚拟机&#xff09;提供…

springboot+vue职称评审管理系统

开发语言&#xff1a;Java 框架&#xff1a;Springbootssm(SpringSpringMVCMyBatis) JDK版本&#xff1a;JDK1.8 前端框架&#xff1a;vue.js 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/idea都支持 Mave…

前端页面的性能测试

介绍 随着 Web 应用的空前发展&#xff0c;前端业务逐渐复杂&#xff0c;为了处理这些复杂业务&#xff0c;前后端分离&#xff0c;出现了专门应对这种分离架构的应用开发框架&#xff0c;比如 Angular&#xff0c;React&#xff0c;Vue 等&#xff0c;从而也导致 Web 应用的复…

高效率开发Web安全扫描器之路(一)

一、背景 经常看到一些SRC和CNVD上厉害的大佬提交了很多的漏洞&#xff0c;一直好奇它们怎么能挖到这么多漏洞&#xff0c;开始还以为它们不上班除了睡觉就挖漏洞&#xff0c;后来有机会认识了一些大佬&#xff0c;发现它们大部分漏洞其实是通过工具挖掘的&#xff0c;比如说下…

linux服务器监控性能测试

一、服务器实时内存监控 1、top&#xff1a;能够实时监控系统的运行状态&#xff0c;并且可以按照cpu以及内存等进行排序。 输入&#xff1a;top -help就可以出现下面的例子&#xff1a; 命令例子&#xff1a;top -hv | -bcHiOSs -d secs -n max -u|U user -p pid(s) -o fiel…

计算机网络——分层结构,协议接口,服务

分层结构 主机进行资源共享时需满足以下条件&#xff1a; &#xff08;1&#xff09;发起通信的计算机要将数据通路进行激活 &#xff08;2&#xff09;告诉网络如何识别主机 &#xff08;3&#xff09;发起通信的主机要查明目的主机是否开机等 &#xff08;4&#xff09;发起…

Java 中你绝对没用过的一个关键字?

这节课给大家介绍一个 Java 中的一个关键字 Record&#xff0c;那 Record 关键字跟不可变类有什么关系呢&#xff1f;看完今天的文章你就知道了。友情提示 Record 关键字在 Java14 过后才支持的&#xff0c;所以是不是被我说中了&#xff0c;还在使用 Java 8 的你一定没用过&am…

vpp hqos分析

vpp支持两套qos实现&#xff0c;一套是基于policer实现的qos&#xff0c;另外一套是基于dpdk的qos套件实现的hqos。 &#xff08;免费订阅,永久学习&#xff09;学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂 更多DPDK相关学习资料有…

DPU网络开发SDK——DPDK(一)

随着软件定义网络SDN的不断发展&#xff0c;网络数据转发面的需求越来越多样化&#xff0c;这体现在更快的数据包处理速率&#xff0c;更高的网络吞吐带宽&#xff0c;更灵活的自定义网络协议。传统的硬件设备无法满足网络协议的自定义&#xff0c;而基于Linux内核网络协议栈的…

故障电弧探测器的必要性及组网方案 安科瑞 时丽花

摘要】&#xff1a;电气设备是建筑中不可缺少的一部分&#xff0c;具有较为重要的作用和意义&#xff0c;在应用过程中不仅能够提升建筑本身实用性能&#xff0c;而且可为消费者提供更加优良的生活环境。但设备一旦在运行过程中出现故障&#xff0c;不仅会影响居民正常生活&…

艾美捷细胞失巢凋亡检测试剂盒测定原理化验方案

对细胞外基质&#xff08;ECM&#xff09;的粘附对于许多粘附细胞的生存和繁殖至关重要细胞。细胞与ECM的粘附丧失或不当粘附导致的细胞凋亡定义为“anoikis”。Anoikis&#xff0c;来自希腊语无家可归的意思&#xff0c;与生理学有关组织更新和细胞稳态的过程。 癌症发展和生长…

做测试8年,33岁前只想追求大厂高薪,今年只求稳定收入

疫情3年&#xff0c;每一个行业的危机&#xff0c;每一个企业的倒下&#xff0c;背后都是无数人的降薪、降职和失业。这也暴露了人生的残酷真相&#xff1a;人活一辈子&#xff0c;总有“丰年”和“荒年” 优秀的测试既过得了丰年&#xff0c;也受得住荒年 一个测试宝妈&…

冒烟测试的7个好处,你是否经常用到它?

以下为作者观点&#xff1a; 冒烟测试(smoke testing)是在开发的早期阶段评估基本的软件组件&#xff0c;以检查它们是否 “着火”&#xff08;有问题&#xff09;&#xff0c;本文旨在介绍冒烟测试及其在程序开发过程中的作用。 什么是冒烟测试&#xff1f; 冒烟测试是在开…

Linux文件权限

Linux文件权限 文件权限介绍 Linux文件权限有三种&#xff1a; 权限对应字符可读(read)r可写(write)w可执行(execute)x 文件权限身份也有三种&#xff1a; 权限身份对应字符文件所有者(user)u文件所有者所在组(group)g其他(other)&#xff0c;即除了文件所有者和其所在组的…

简明误差卡尔曼滤波器(ESKF)及其推导过程

文章目录1. 简明ESKF简介ESKF基本过程及优点ESKF参数含义连续时间上的 ESKF状态方程误差状态方程推导误差状态的旋转项误差状态的速度项完整误差变量的运动学方程离散时间上的ESKF运动学方程ESKF的运动过程ESKF的更新过程ESKF的误差状态后续处理小结1. 简明ESKF 简介 本文主要…