Python 访问数据库

要操作关系数据库,首先需要连接到数据库,一个数据库连接称为Connection

连接到数据库后,需要打开游标,称之为Cursor,通过Cursor执行 SQL 语句,然后,获得执行结果。

Python 定义了一套操作数据库的 API 接口,任何数据库要连接到 Python,只需要提供符合 Python 标准的数据库驱动即可。

一、常用数据库

SQLite

SQLite 是一种嵌入式数据库,它的数据库就是一个文件。由于 SQLite 本身是C写的,而且体积很小,所以,经常被集成到各种应用程序中,甚至在 iOS 和 Android 的 App 中都可以集成。Python 就内置了 SQLite3。

导入数据库模块

1
import sqlite3

打开数据库

在 python 中,使用 sqlite3 创建数据库的连接,当我们指定的数据库文件不存在的时候连接对象会自动创建数据库文件;如果数据库文件已经存在,则连接对象不会再创建数据库文件,而是直接打开该数据库文件。

连接对象可以是硬盘上面的数据库文件,也可以是建立在内存(memory)中的,在内存中的数据库执行完任何操作后,都不需要提交事务的(commit)

connect方法返回con对象,即是数据库链接对象,它提供了以下方法:

方法描述
.cursor()创建一个游标对象
.commit()处理事务提交
.rollback()处理事务回滚
.close()关闭一个数据库连接

在硬盘上建立数据库

  • 数据库的名称不区分大小写,且以第一次建立时的名字为准。
  • 不加全路径时,数据库文件会自动建立在工程项目文件夹下。
1
con=sqlite3.connect("D:\Test.db")

在内存上建立数据库

1
con = sqlite3.connect("memory")

创建游标

1
cur = con.cursor()

游标对象有以下方法支持数据库操作:

方法描述
.execute()用来执行sql语句
.executemany()用来执行多条sql语句
.close()用来关闭游标
.fetchone()用来从结果中取一条记录,并将游标指向下一条记录
.fetchmany()用来从结果中取多条记录。
.fetchall()用来从结果中取出所以记录。
.scroll()用于游标滚动。

注意:使用游标的方法返回的数据类型是列表。

执行SQL语句

事务提交或回滚

1
2
3
4
5
6
7
8
9
10
# 提交
con.commit()

# 回滚
con.rollback()

# 关闭游标
cur.close()
# 关闭数据库连接
con.close()

注意:一定要先关闭游标,再关闭数据库连接,否则会报错!

MySQL

SQLite 的特点是轻量级、可嵌入,但不能承受高并发访问,适合桌面和移动应用。而MySQL 是为服务器端设计的数据库,能承受高并发访问,同时占用的内存也远远大于 SQLite。

安装驱动

由于 MySQL 服务器以独立的进程运行,并通过网络对外服务,所以,需要支持 Python 的 MySQL 驱动来连接到 MySQL 服务器。

MySQL 官方提供了 mysql-connector-python 驱动,但是安装的时候需要给 pip 命令加上参数--allow-external

1
2
3
pip install mysql-connector-python --allow-external mysql-connector-python
# 如果上面的命令安装失败,可以试试另一个驱动:
pip install mysql-connector

快速入门

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
# 导入MySQL驱动:
>>> import mysql.connector

# 注意把password设为你的root口令:
>>> conn = mysql.connector.connect(user='root', password='password', database='test')
>>> cursor = conn.cursor()

# 创建user表:
>>> cursor.execute('create table user (id varchar(20) primary key, name varchar(20))')

# 插入一行记录,注意MySQL的占位符是%s:
>>> cursor.execute('insert into user (id, name) values (%s, %s)', ['1', 'Michael'])
>>> cursor.rowcount
1

# 提交事务:
>>> conn.commit()
>>> cursor.close()

# 运行查询:
>>> cursor = conn.cursor()
>>> cursor.execute('select * from user where id = %s', ('1',))
>>> values = cursor.fetchall()
>>> values
[('1', 'Michael')]

# 关闭Cursor和Connection:
>>> cursor.close()
True
>>> conn.close()

二、使用 ORM 框架

SQLAlchemy

背景

数据库表是一个二维表,包含多行多列。把一个表的内容用 Python 的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是 tuple,表示一行记录,比如,包含idnameuse 表:

1
2
3
4
5
[
('1', 'Michael'),
('2', 'Bob'),
('3', 'Adam')
]

Python 的 DB-API 返回的数据结构就是像上面这样表示的。

但是用tuple表示一行很难看出表的结构。如果把一个tupleclass 实例来表示,就可以更容易地看出表的结构来:

1
2
3
4
5
6
7
8
9
10
class User(object):
def __init__(self, id, name):
self.id = id
self.name = name

[
User('1', 'Michael'),
User('2', 'Bob'),
User('3', 'Adam')
]

这就是传说中的 ORM 技术:Object-Relational Mapping,把关系数据库的表结构映射到对象上

但是由谁来做这个转换呢?

所以 ORM 框架应运而生。在 Python 中,最有名的 ORM 框架是 SQLAlchemy。我们来看看 SQLAlchemy 的用法。

安装

1
pip install sqlalchemy

快速入门

SQLAlchemy 的初始化和对象定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 导入:
from sqlalchemy import Column, String, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# 创建对象的基类:
Base = declarative_base()

# 定义User对象:
class User(Base):
# 表的名字:
__tablename__ = 'user'

# 表的结构:
id = Column(String(20), primary_key=True)
name = Column(String(20))

# 初始化数据库连接:
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)

以上代码完成 SQLAlchemy 的初始化和具体每个表的class定义。

create_engine()用来初始化数据库连接。SQLAlchemy用一个字符串表示连接信息:

‘数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名’

如果有多个表,就继续定义其他 class,例如 School:

1
2
3
4
class School(Base):
__tablename__ = 'school'
id = ...
name = ...

添加记录

由于有了 ORM,我们向数据库表中添加一行记录,可以视为添加一个User对象:

1
2
3
4
5
6
7
8
9
10
# 创建session对象:
session = DBSession()
# 创建新User对象:
new_user = User(id='5', name='Bob')
# 添加到session:
session.add(new_user)
# 提交即保存到数据库:
session.commit()
# 关闭session:
session.close()

可见,关键是获取session,然后把对象添加到session,最后提交并关闭。

DBSession 对象可视为当前数据库连接。

查询数据

有了ORM,查询出来的可以不再是tuple,而是User对象。SQLAlchemy 提供的查询接口如下:

1
2
3
4
5
6
7
8
9
# 创建Session:
session = DBSession()
# 创建Query查询,filter是where条件,最后调用one()返回唯一行,如果调用all()则返回所有行:
user = session.query(User).filter(User.id=='5').one()
# 打印类型和对象的name属性:
print('type:', type(user))
print('name:', user.name)
# 关闭Session:
session.close()

运行结果:

1
2
type: <class '__main__.User'>
name: Bob

一对多关联

由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应地,ORM 框架也可以提供两个对象之间的一对多、多对多等功能。

例如,如果一个User拥有多个Book,就可以定义一对多关系如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User(Base):
__tablename__ = 'user'

id = Column(String(20), primary_key=True)
name = Column(String(20))
# 一对多:
books = relationship('Book')

class Book(Base):
__tablename__ = 'book'

id = Column(String(20), primary_key=True)
name = Column(String(20))
# “多”的一方的book表是通过外键关联到user表的:
user_id = Column(String(20), ForeignKey('user.id'))

当我们查询一个User对象时,该对象的books属性将返回一个包含若干个Book对象的list

其他

executemany()

executemany()方法中,参数列表需要是一个可迭代对象,并且每个元素都需要是一个序列(例如列表、元组等)。这是为了支持批量执行多次操作。

为了满足executemany()方法的要求,需要将每个参数以元组形式传递,即使是只有一个值的情况也不例外。这样可以确保参数列表与 SQL 语句中占位符的数量和顺序相匹配,从而正确地执行批量操作。


Python 访问数据库
https://blog-21n.pages.dev/2023/10/17/Python访问数据库/
作者
Neo
发布于
2023年10月17日
许可协议