Python DB-API 规范及 MySQL Connector/Python 实现

简介: Python DB-API 规范及 MySQL Connector/Python 实现

一、持久化存储与PEP 249

持久化存储有3中基础的存储机制:文件、数据库(关系型和非关系型)以及一些混合类型。文件存储不适合大型项目,需要使用数据库存储,MySQL是目前持久化存储中最流行的解决方案。

Python访问关系型数据库有两种方式,一种是通过数据库接口既Python DB-API,另一种方式是通过ORM来访问;DB-API是一套访问数据库的标准或者规范,它可以为不同的数据库适配器和底层数据库系统提供一致性访问,类似Java中的JDBC。DB-API 已移动至 PEP 249 中(PEP 248 中的老版 DB-API 1.0 标准已经废弃)。可以参考官网 PEP 249 – Python Database API Specification v2.0

基于PEP 249 DB-API规范的 MySQL 访问实现,类似Spring Data JPA 以及 Hibernate

  • MySQL Connector/Python
  • PyMySQL
  • MySQL for Python
  • mysqlclient

更多实现可以参考官网

二、Python DB-API

全局属性

DB-API规范要求必须提供以下全局属性:

属性 描述
apilevel 适配器兼容的DB-API版本,默认为1.0
threadsafety 线程安全级别,整数值类型
paramstyle SQL语句参数风格
connect() Connect()函数

线程安全级别属性是一个整数类型,有以下几个选择:

  • 0:不支持线程安全,线程间不能共享模块
  • 1:最小化的线程安全支持,线程间可以共享模块,但是不能共享连接
  • 2:适度的线程安全支持,线程间可以共享模块和连接,但是不能共享游标
  • 3:完整的线程安全支持,线程间可以共享模块、连接和游标

connect() 函数 与 Connection 对象

connect()函数可以返回一个Connection对象既一个数据库连接,该函数可以使用办函多个参数的字符串传递数据库连接信息,也可以安装位置传递每个参数,或者通过关键字方式传参

  • user:用户名
  • password:密码
  • host:主机名
  • database:数据库名
  • dsn:数据源名

具体使用的参数还需要根据适配器的不同而是用不同的参数,如ODBC或者JDBC的API需要用大DSN,而MySQL Connector就不需要使用DSN.

Connection对象是一个具体的数据库连接,可以用于创建游标,使用游标执行SQL语句,Connection对象不包含任何属性,但是包含了以下这些方法:

  • close():关闭数据库连接,关闭之后连接将无法使用
  • commit():提交当前事务
  • rollback():取消当前事务
  • cursor():创建并返回一个游标对象
  • errorhandler():给定连接的游标的处理程序

Cursor

当建立好连接之后就可以和数据库进行通信了,游标可以让用户提交数据库命令,并获取的执行结果,DB-API规范中定义了游标的功能,基于DB-API规范实现的适配器都是实现游标的功能 ,以此来保证访问不同数据库时的一致性。

游标可以执行查询或者其他命令,可以通过execute和executemany执行一条或者多条命令,并支持从结果集中取出一行或者多行结果。

Cursor对象的属性和方法如下:

对象属性或者方法 描述
arraysize 使用fetchmany()或获取多行结果时,指定获取的行数,默认为1
connection 创建游标使用的连接
description 返回游标的活动状态
lastrowid 上次修改行的id
rowcount 执行SQL影响的行数
rownumber 当前结果集中游标的索引
messages 游标执行后从数据库中获得的消息列表
callproc() 调用存储过程
close() 关闭游标
execute() 执行一条数据库命名
executemany 执行多条命令,类似execute()和map()的组合
fetchone() 获取一行数据
fetchmany() 获取多行数据,可以指定行数
fetchall() 获取全部数据
__iter__() 为游标创建迭代器
next() 游标迭代器查询下一行数据
nextset() 移动到下一个结果集合
fetchmany() 获取多行数据,可以指定行数
setinputsize() 设置允许的最大输入大小,可选
setoutputsize() 设置列获取的最大缓冲区的大小

三、MySQL Connector/Python

安装MySQL Connector

MySQL Connector是MySQL官方提供的适配器,基于PEP249规范。

  • mplements the Python DB API 2.0 (PEP 249).
  • Pure Python implementation of the MySQL protocol.
  • Actively developed and maintained by Oracle.
  • Includes Django database backend.

MySQL Connector可以通过pip进行安装。

python3 -m pip install mysql-connector -i https://pypi.tuna.tsinghua.edu.cn/simple
复制代码

也可以通过MySQL 官方网站下载安装包进行安装

创建连接

创建MySQL连接有两种方式,第一种是直接传入数据连接信息来创建连接。

import mysql.connector
conn = mysql.connector.connect(
    host='localhost', port=3306, user='root',
    password='123456', database='test'
)
# 打印连接
print(conn)
# 关闭连接
conn.close()
复制代码

4fa7a3b612124c4e963b9c66ecdc4f6d_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

连接无异常。

第二种方式是传入一个配置,配置中包含了数据库连接信息。

import mysql.connector
import mysql.connector.connection
mysql_connect_config = {
    'host': 'rm-uf67r962043910k193o.mysql.rds.aliyuncs.com',
    'port': 3306,
    'user': 'root',
    'password': 'Abc*123456',
    'database': 'test'
}
conn = mysql.connector.connect(
    **mysql_connect_config
)
print(conn)
# 关闭连接
conn.close()
复制代码

53fe85ca00b2479da6b7de03373d5abd_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

通过游标来执行SQL语句,在上述脚本尾部中增加代码

# 使用游标执行SQL
cursor = conn.cursor()
sql = "SELECT * FROM porsche"
cursor.execute(sql)
print(cursor)
print(type(cursor))
print(isinstance(cursor, list))
for i in cursor:
    print(i)
    print(type(i))
    print(i[0], i[1], i[2])
# 关闭连接
conn.close()
复制代码

05d877af8fcd43a5a521dcf1a402d50b_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

游标中存储了一行行数据,这些数据以元组类型存储,通过索引可以获取指定列的元素

executemany()

当需要执行批量操作时,for循环执行SQL和executemany函数可以到达相同的效果,以实现实现批量插入功能为例。

import mysql.connector
mysql_connect_config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': 'Abc*123456',
    'database': 'test'
}
conn = mysql.connector.connect(
    **mysql_connect_config
)
try:
    # 开启事务
    conn.start_transaction()
    # 使用游标执行SQL
    cursor = conn.cursor()
    sql = 'INSERT INTO porsche (por_name, por_price, por_stock) VALUES (%s, %s, %s)'
    data = [['Taycan 2020', 1200000.00, 100], ['Taycan 2021', 1200000.00, 100], ['Taycan 2022', 1200000.00, 100]]
    cursor.executemany(sql, data)
    conn.commit()
except Exception as e:
    if 'conn' in dir():
        conn.rollback()
    print(e)
复制代码

ada75199b09b40d4b15edab94aa0cd9b_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

SQL执行无异常,并且成功插入到数据库中。

b21594740cbf46c98d6c650ca7f05efe_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

SQL 注入

import mysql.connector
mysql_connect_config = {
    'host': 'rm-uf67r962043910k193o.mysql.rds.aliyuncs.com',
    'port': 3306,
    'user': 'root',
    'password': 'Abc*123456',
    'database': 'test'
}
conn = mysql.connector.connect(
    **mysql_connect_config
)
# 根据条件查询
id = '1 OR 1=1'
sql = 'SELECT * FROM porsche WHERE por_id=' + id
# 获取游标
cursor = conn.cursor()
cursor.execute(sql)
print(type(cursor))
for i in cursor:
    print(i)
# 关闭连接
conn.close()
复制代码

41c02131dd8c400a8b5b4283fc68b10b_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

正常通过WHERE por_id=?条件应该只能查出一个数据,但是通过拼接加入OR True可以使where条件失效,进而查询到所有的数据,因此使用拼接的方式传递参数非常容易出现SQL注入漏洞。

预编译SQL

预编译SQL就是数据库提前把SQL语句编译成二级制,这样反复执行同一条SQL语句的效率就会提升。

预编译过程中,关键字会被解析,向编译后的SQL语句传入参数,都会被当做字符串串处理,数据库不会解析其中注入的SQL语句。

注意预编译传参方式,虽然预编译使用%s进行占位,但是传参的时候一定更不要通过%(参数1,参数2)方式传参,要区分预编译占位符和Python格式化操作符。

# 根据条件查询
id = '2 OR 1=1'
# sql = 'SELECT * FROM porsche WHERE por_id=' + id
sql = 'SELECT * FROM porsche WHERE por_id=%s'
# 获取游标
cursor = conn.cursor()
cursor.execute(sql, (id,))
# cursor.execute(sql)
# print(type(cursor))
for i in cursor:
    print(i)
# 关闭连接
conn.close()
复制代码

cb89c21b9c3d44c2bf5c523e4e030289_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

只查出一条符合WHERE条件的数据,避免了SQL注入。

MySQL Connector 异常处理

import mysql.connector
try:
    # 数据库连接
    conn = mysql.connector.connect(
        host='localhost', port=3306, user='root',
        password='Abc123456', database='test'
    )
    conn.start_transaction()
    # 数据库操作
    insert_sql = 'INSERT INTO porsche(por_id, por_name, por_price, por_stock) ' \
                 'VALUES (%s, %s, %s, %s)'
    cursor = conn.cursor()
    cursor.execute(insert_sql, (18, 'Taycan 2024', 880000.00, 100))
    conn.commit()
except Exception as e:
    # 出现异常回滚
    conn.rollback()
    print(e)
finally:
    # 关闭连接
    if 'conn' in dir():
        conn.close
复制代码

d0163cb533c9449bae70533eeb8132c9_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

查看数据库,数据成功插入

432e237d559e4da4b54be5db5f0ce186_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

模拟一个异常情况,将数据库连接密码改成错误的密码,是否能捕获异常。

32f1d4b32b2c4664b86d58d1161684a4_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

在except代码中增加判断,执行回滚。

except Exception as e:
    if 'conn' in dir():
        conn.rollback()
    print(e)
复制代码

数据库连接池

数据库连接是一种关键的、有限的、昂贵的资源,在高并发执行时表现得尤为突出,建立以及释放连接还需要经过三次握手、四次挥手而且还需要校验数据库连接信息,这会导致一定的资源开销,而数据库连接池会预先创建出一些数据库连接,缓存起来,避免程序反复创建和关闭连接。

f592d09b70d24d32886baafcb3b95c1c_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

数据库连接池通过mysql.connector.pooling包下的MySQLConnectionPool函数创建,需要传入数据库连接信息以及要创建连接的个数。

import mysql.connector.pooling
mysql_connect_config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': 'Abc*123456',
    'database': 'test'
}
try:
    pool = mysql.connector.pooling.MySQLConnectionPool(**mysql_connect_config, pool_size=10)
    # print(pool)
    # 获取数据库连接
    conn = pool.get_connection()
    # 开启事务
    conn.start_transaction()
    # 使用游标执行SQL
    cursor = conn.cursor()
    sql = 'UPDATE porsche SET por_stock=100 WHERE por_id=%s'
    # 只传递一个参数的情况,传递的参数的集合必须是元组类型
    cursor.execute(sql,(3,))
    conn.commit()
except Exception as e:
    if 'conn' in dir():
        conn.rollback()
    print(e)
复制代码

MySQL Connector 删除数据的两种方式

MySQL Connector可以通过执行delete语句来执行删除操作,delete语句依赖事务,删除之后要进行commit()。

import mysql.connector.pooling
mysql_connect_config = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '123456',
    'database': 'test'
}
try:
    pool = mysql.connector.pooling.MySQLConnectionPool(**mysql_connect_config, pool_size=10)
    conn = pool.get_connection()
    # 开启事务
    conn.start_transaction()
    # 游标
    cursor = conn.cursor()
    # delete 删除语句
    delete_sql = 'DELETE FROM porsche WHERE por_name=%s AND por_price=%s'
    por_name = 'Cayman'
    por_price = 720000
    # 执行sql
    cursor.execute(delete_sql, (por_name, por_price))
    conn.commit()
except Exception as e:
    # 回滚
    if 'conn' in dir():
        conn.rollback
    print(e)
复制代码

04c98b0120af44978ea6c750b5e46f58_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

SQL 执行无异常。

第二种删除方式是TRUNCATE删除, 不依赖事务。

truncate_sql = 'TRUNCATE TABLE porsche'
# 执行sql
# cursor.execute(delete_sql, (por_name, por_price))
cursor.execute(delete_sql)
复制代码

执行TRUNCATE SQL 删除。cursor的execute函数只能执行一条SQL语句。


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
9月前
|
JSON 算法 API
Python采集淘宝商品评论API接口及JSON数据返回全程指南
Python采集淘宝商品评论API接口及JSON数据返回全程指南
|
9月前
|
JSON API 数据安全/隐私保护
Python采集淘宝拍立淘按图搜索API接口及JSON数据返回全流程指南
通过以上流程,可实现淘宝拍立淘按图搜索的完整调用链路,并获取结构化的JSON商品数据,支撑电商比价、智能推荐等业务场景。
|
9月前
|
Cloud Native 算法 API
Python API接口实战指南:从入门到精通
🌟蒋星熠Jaxonic,技术宇宙的星际旅人。深耕API开发,以Python为舟,探索RESTful、GraphQL等接口奥秘。擅长requests、aiohttp实战,专注性能优化与架构设计,用代码连接万物,谱写极客诗篇。
1863 1
Python API接口实战指南:从入门到精通
|
10月前
|
JSON API 数据安全/隐私保护
Python采集淘宝评论API接口及JSON数据返回全流程指南
Python采集淘宝评论API接口及JSON数据返回全流程指南
|
10月前
|
缓存 监控 供应链
唯品会自定义 API 自定义操作深度分析及 Python 实现
唯品会开放平台提供丰富API,支持商品查询、订单管理、促销活动等电商全流程操作。基于OAuth 2.0认证机制,具备安全稳定的特点。通过组合调用基础接口,可实现数据聚合、流程自动化、监控预警及跨平台集成,广泛应用于供应链管理、数据分析和智能采购等领域。结合Python实现方案,可高效完成商品搜索、订单分析、库存监控等功能,提升电商运营效率。
|
10月前
|
缓存 监控 供应链
京东自定义 API 操作深度分析及 Python 实现
京东开放平台提供丰富API接口,支持商品、订单、库存等电商全链路场景。通过自定义API组合调用,可实现店铺管理、数据分析、竞品监控等功能,提升运营效率。本文详解其架构、Python实现与应用策略。
JSON 监控 API
382 0
|
11月前
|
JSON 供应链 API
京东工业商品详情API数据python解析
京东工业商品详情API专为工业品采购设计,提供商品参数、资质认证、供应链等专业数据,适用于企业采购与供应链管理。支持多SKU查询,采用HTTPS协议与JSON格式,保障数据安全与高效调用。附Python调用示例,便于快速集成。
|
11月前
|
JSON 供应链 API
深度分析京东工业API接口,用Python脚本实现
京东工业是京东旗下工业供应链服务平台,提供商品查询、库存管理、订单处理等API接口,支持企业高效对接工业采购系统。本文解析其API架构、认证机制及Python调用示例,助力企业集成工业供应链能力。
|
11月前
|
缓存 API 网络架构
淘宝item_search_similar - 搜索相似的商品API接口,用python返回数据
淘宝联盟开放平台中,可通过“物料优选接口”(taobao.tbk.dg.optimus.material)实现“搜索相似商品”功能。该接口支持根据商品 ID 获取相似推荐商品,并返回商品信息、价格、优惠等数据,适用于商品推荐、比价等场景。本文提供基于 Python 的实现示例,包含接口调用、数据解析及结果展示。使用时需配置淘宝联盟的 appkey、appsecret 和 adzone_id,并注意接口调用频率限制和使用规范。

推荐镜像

更多