@Author : Roger TX ([email protected])
@Link : https://github.com/paotong999
一、Python数据库API
Python 需要为操作不同的数据库使用不同的模块,但基本都遵守 Python 制订的 DB API 协议,目前该协议的最新版本是 2.0。
使用 Python DB API 2.0 操作数据库的基本流程如下
- 调用 connect() 方法打开数据库连接,该方法返回数据库连接对象。
- 通过数据库连接对象打开游标。
- 使用游标执行 SQL 语句(包括 DDL、DML、select 查询语句等)。如果执行的是查询语句,则处理查询数据。
- 关闭游标。
- 关闭数据库连接。
使用 Python DB API 2.0 操作数据库的基本流程如图
数据库 API 的核心类
遵守 DB API 2.0 协议的数据库模块通常会提供一个 connect() 函数,该函数用于连接数据库,并返回数据库连接对象。数据库连接对象通常会具有如下方法和属性:
- cursor(factory=Cursor):打开游标。
- commit():提交事务。
- rollback():回滚事务。
- close():关闭数据库连接。
- isolation_level:返回或设置数据库连接中事务的隔离级别。
- in_transaction:判断当前是否处于事务中。
游标对象通常会具有如下方法和属性:
- execute(sql[, parameters]):执行 SQL 语句。parameters 参数用于为 SQL 语句中的参数指定值。
- executemany(sql, seq_of_parameters):重复执行 SQL 语句。可以通过 seq_of_parameters 序列为 SQL 语句中的参数指定值,该序列有多少个元素,SQL 语句被执行多少次。
- fetchone():获取查询结果集的下一行。如果没有下一行,则返回 None。
- fetchmany(size=cursor.arraysize):返回查询结果集的下 N 行组成的列表。如果没有更多的数据行,则返回空列表。
- fetchall():返回查询结果集的全部行组成的列表。
- close():关闭游标。
- rowcount:该只读属性返回受 SQL 语句影响的行数。对于 executemany() 方法,该方法所修改的记录条数也可通过该属性获取。
- lastrowid:该只读属性可获取最后修改行的 rowid。
- arraysize:用于设置或获取 fetchmany() 默认获取的记录条数,该属性默认为 1。有些数据库模块没有该属性。
- description:该只读属性可获取最后一次查询返回的所有列的列名信息。
- connection:该只读属性返回创建游标的数据库连接对象。有些数据库模块没有该属性。
二、Python操作数据库SQLite
SQLite是一种嵌入式数据库,它的数据库就是一个文件。
Python内置了SQLite3,在Python中使用SQLite,不需要安装任何东西,直接使用。
# 导入访问SQLite的模块
import sqlite3
# ①、打开或创建数据库
# 也可以使用特殊名::memory:代表创建内存中的数据库
conn = sqlite3.connect('first.db')
# ②、获取游标
c = conn.cursor()
# ③、执行DDL语句创建数据表
c.execute('''create table user_tb(
_id integer primary key autoincrement,
name text,
pass text,
gender text)''')
# 执行DDL语句创建数据表
c.execute('''create table order_tb(
_id integer primary key autoincrement,
item_name text,
item_price real,
item_number real,
user_id inteter,
foreign key(user_id) references user_tb(_id) )''')
# 执行DML的insert语句插入数据
c.execute('insert into user_tb values(null, ?, ?, ?)',
('孙悟空', '123456', 'male'))
c.execute('insert into order_tb values(null, ?, ?, ?, ?)',
('鼠标', '34.2', '3', 1))
# SQLite 数据库 API 默认是开启了事务,需要提交事务
conn.commit()
# 调用executemany()方法把同一条SQL语句执行多次
c.executemany('insert into user_tb values(null, ?, ?, ?)',
(('sun', '123456', 'male'),
('bai', '123456', 'female'),
('zhu', '123456', 'male'),
('niu', '123456', 'male'),
('tang', '123456', 'male')))
# 通过rowcount获取被修改的记录条数
print('修改的记录条数:', c.rowcount)
conn.commit()
# ④、关闭游标
c.close()
# ⑤、关闭连接
conn.close()
- 操作数据之后需要提交事务,否则对数据库的修改(包括插入数据、修改数据、删除数据)不会生效
- 调用 executemany() 方法执行一条 insert 语句,但调用该方法的第二个参数是一个元组,该元组的每个元素都代表执行该 insert 语句一次,在执行 insert 语句时这些元素负责为该语句中的“?”占位符赋值
- executemany() 也可以重复执行 update 语句或 delete 语句,只要其第二个参数是一个序列,序列的每个元素都可对被执行 SQL 语句的参数赋值即可
import sqlite3
conn = sqlite3.connect('first.db')
c = conn.cursor()
# 调用执行select语句查询数据
c.execute('select * from user_tb where _id > ?', (2,))
print('查询返回的记录数:', c.rowcount)
# 通过游标的description属性获取列信息
for col in (c.description):
print(col[0], end='\t')
print('\n--------------------------------')
while True:
# 获取一行记录,每行数据都是一个元组
row = c.fetchone()
# 如果抓取的row为None,退出循环
if not row :
break
print(row)
c.close()
conn.close()
- 不能使用 executemany() 执行查询语句,executemany() 只支持DML语句
- 对于查询语句,rowcount返回的值为-1
- fetchone() 方法每次获取一条记录,也可以使用 fetchmany(n) 或 fetchall() 方法一次获取多条记录
while True:
rows = c.fetchmany(3)
# 如果抓取的rows为None,退出循环
if not rows :
break
# 再次使用循环遍历获取的列表
for r in rows:
print(r)
三、Python操作数据库MySQL
安装MySQL驱动
由于MySQL服务器以独立的进程运行,并通过网络对外服务,所以需要支持Python的MySQL驱动来连接MySQL服务器。
MySQL官方提供了mysql-connector-python驱动,但是安装的时候需要给pip命令加上参数--allow-external:
$ pip install mysql-connector-python --allow-external mysql-connector-python
如果上面的命令安装失败,可以试试另一个驱动:
$ pip install mysql-connector
我们演示如何连接到MySQL服务器的test数据库:
# 导入访问MySQL的模块
import mysql.connector
# ①、连接数据库
conn = conn = mysql.connector.connect(user='root', password='123456',
host='localhost', port='3306',
database='python', use_unicode=True)
# ②、获取游标
c = conn.cursor()
# ③、执行DDL语句创建数据表
c.execute('''create table user_tb(
user_id int primary key auto_increment,
name varchar(255),
pass varchar(255),
gender varchar(255))''')
# 执行DDL语句创建数据表
c.execute('''create table order_tb(
order_id integer primary key auto_increment,
item_name varchar(255),
item_price double,
item_number double,
user_id int,
foreign key(user_id) references user_tb(user_id) )''')
# 执行DML的insert语句插入数据
c.execute('insert into user_tb values(null, %s, %s, %s)'%
('孙悟空', '123456', 'male'))
c.execute('insert into order_tb values(null, %s, %s, %s, %s)'%
('鼠标', '34.2', '3', 1))
# 调用executemany()方法把同一条SQL语句执行多次
c.executemany('insert into user_tb values(null, %s, %s, %s)'%
(('sun', '123456', 'male'),
('bai', '123456', 'female'),
('zhu', '123456', 'male'),
('niu', '123456', 'male'),
('tang', '123456', 'male')))
# 关闭事务支持conn.autocommit = True
conn.commit()
# ④、关闭游标
c.close()
# ⑤、关闭连接
conn.close()
- 与连接 SQLite 相比,最大的区别在于第 5 行代码,程序要连接 localhost 主机上 3306 端口服务的 python 数据库。
- 与连接 SQLite 相比,MySQL 语句中的占位符:%s
- MySQL 数据库模块的连接对象有一个 autoconunit 属性,如果将该属性设为 True,则意味着关闭该连接的事务支持,程序每次执行 DML 语句之后都会自动提交,这样程序就无须调用连接对象的 commit() 方法来提交事务了
MySQL callproc方法:调用数据库存储过程
MySQL 数据库模块为游标对象提供了一个非标准的 callproc(self, procname, args=())
方法,该方法用于调用数据库存储过程。
callproc 方法的 procname 参数代表存储过程的名字,而 args 参数则用于为存储过程传入参数。
存储过程
delimiter //
create procedure add pro(a int, b int, out sum int)
begin
set sum = a + b;
end;
//
MySQL 数据库模块来调用存储过程
# 导入访问MySQL的模块
import mysql.connector
# ①、连接数据库
conn = conn = mysql.connector.connect(user='root', password='32147',
host='localhost', port='3306',
database='python', use_unicode=True)
# ②、获取游标
c = conn.cursor()
# ③、调用callproc()方法执行存储过程
# 虽然add_pro存储过程需要3个参数,但最后一个参数是传出参数,
# 因此程序不会用它的值
result_args = c.callproc('add_pro', (5, 6, 0))
# 返回的result_args既包含了传入参数的值,也包含了传出参数的值
print(result_args)
# 如果只想访问传出参数的值,可直接访问result_args的第3个元素,如下代码
print(result_args[2])
# ④、关闭游标
c.close()
# ⑤、关闭连接
conn.close()
运行上面的程序,可以看到如下输出结果:
(5, 6, 11)
11
四、ORM框架SQLAlchemy
首先通过pip安装SQLAlchemy:
pip install sqlalchemy
第一步,导入SQLAlchemy,并初始化DBSession:
# 导入:
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))
# 一对多:
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'))
# 初始化数据库连接:
engine = create_engine('mysql+mysqlconnector://root:password@localhost:3306/test')
# 创建DBSession类型:
DBSession = sessionmaker(bind=engine)
create_engine()用来初始化数据库连接:
'数据库类型+数据库驱动名称://用户名:口令@机器地址:端口号/数据库名'
第二步,向数据库表中添加一行记录:
# 创建session对象:
session = DBSession()
# 创建新User对象:
new_user = User(id='5', name='Bob')
# 添加到session:
session.add(new_user)
# 提交即保存到数据库:
session.commit()
# 关闭session:
session.close()
第三步,从数据库表中查询数据:
# 创建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()