python 访问数据库 笔记
1 使用dbm持久字典
存储名称、值对,保存在磁盘上,键和值都必须是字符串类型
不同dbm模块创建的文件是不兼容的。如果使用某个dbm模块创建一个dbm持久字典,那么必须使用相同的模块来读取数据。
dbm 选择最好的dbm模块,dbm模块替自己做出选择,在创建一个新的持久字典时,dbm模块将选择系统上已有的最好的实现方式。
dbm.dumb使用dbm库的一个简单但可移植的实现
dbm.gnu使用GNU dbm库
所有dbm模块都支持使用open函数创建一个新的dbm对象。打开后便可以在字典中存储数据、读取数据、关闭dbm对象 以及相关联的数据文件、移除项和检查字典中是否存在某个键等。
c 打开数据文件以便对其进行读写,必要时创建该文件;
N打开文件以便对其进行读写,但总是创建一个新的空文件。如果该文件已经存在,则将被覆盖,已有的内容将会丢失
W打开文件以便对其进行读写,但是如果该文件不存在,那么不会创建它。
import dbm
db=dbm.open('websites','c')
#add an item.
db['www.python.org']='python home page'
print(db['www.python.org'])
#close and save to disk.
db.close()
dbm模块可能创建多个文件,通常一个文件用于数据,一个文件用于键的索引
通常底层的dbm库将为数据附加一个后缀 如:.dat
dbm模块的open方法返回一个新的dbm对象,之一便可以使用此对象存储和检索数据。
键和值都必须是字符串,如果希望保存一个对象,可以使用pickle模块对它进行串行化
close方法关闭文件,并将数据保存到磁盘中。
可以将open函数返回的对象视作一个字典对象。value=db['key']
可以使用del删除字典中值:del db['key']
keys 方法返回包含所有键的一个列表 for key in db.keys():
如果在文件中包含大量的键,那么keys方法的执行可以会占用很长时间。另外对于较大的文件 ,此方法可能需要大量的内存来存储列表
import dbm
#open existing file
db=dbm.open('websites','w')
#add another item
db['www.wrox.com']='wrox home page'
#verify the previous item remains.
if db['www.python.org']!=None:
print('found www.python.org')
else:
print('error:mission item')
# iterate over the keys .may be slow.
#may use a lot of memory
for key in db.keys():
print("key=",key,"value=",db[key])
del db['www.wrox.com']
print("after deleting www.wrox.com,we have:")
for key in db.keys():
print('key=%s value=%s'%(key,db[key]))
#close and save to disk.
db.close() # 关闭字典,保存所有修改到硬盘上。
当数据需求可以通过存储一些键、值对来满足时,dbm模块十分有用。数据需求简单、存储少量的数据时使用
一些dbm库对可以用于值的空间总数进行了限制,有时达到最大值即1024字节
如果需要支持事务、复杂的数据结构或多个连接数据的表,使用关系数据库
2 使用关系数据库
使用python DB AP访问数据库时,必须首先创建一些Sql语句。
Sqlite数据库随python一起安装、简单、轻便、实用。
import os
import sqlite3
conn=sqlite3.connect('sample_database') #每个数据库模块都有一个连接函数,返回一个connection对象
cursor=conn.cursor() #游标,是一种python 对象,用于使用数据库
#create tables
#cursor.execute("""drop table if exists user""") #这里删除的判断与下面创建重复 execute 执行sql语句
#cursor.execute("""drop table if exists employee""")
#cursor.execute("""drop table if exists department""")
#cursor.execute("""drop index if exists userid""")
#cursor.execute("""drop index if exists emplid""")
#cursor.execute("""drop index if exists deptid""")
#cursor.execute("""drop index if exists deptfk""")
#cursor.execute("""drop index if exists mgr""")
#cursor.execute("""drop index if exists emplid""")
#cursor.execute("""drop index if exists deptmgr""")
cursor.execute("""
create table if not exists employee (empid integer,
firstname varchar,
lastname varchar,
dept integer,
manager integer,
phone varchar)""")
cursor.execute("""
create table if not exists department( departmentid integer,
name varchar,
manager integer)""")
cursor.execute("""
create table if not exists user(userid intege,
username varchar,
employeeid integer)""")
#create indices.
cursor.execute("""create index if not exists userid on user(userid)""")
cursor.execute("""create index if not exists emplid on employee(empid)""")
cursor.execute("""create index if not exists deptid on department(departmentid)""")
cursor.execute("""create index if not exists deptfk on employee(dept)""")
cursor.execute("""create index if not exists mgr on employee(manager)""")
cursor.execute("""create index if not exists emplid on user(employeeid)""")
cursor.execute("""create index if not exists deptmgr on department(manager)""")
conn.commit() # 提交事务以将所有的修改保存到数据库中
cursor.close() # 当脚本完成时,关闭游标和连接以释放资源
conn.close()
Sqlite具有自身的API
在 https://wiki.python.org/moin/DatabaseInterfaces
下载对应的数据库模块,并安装
python3 -m pip install mysql-connector
insertdata.py
import os
import sqlite3
conn=sqlite3.connect('sample_database')
cursor=conn.cursor()
#create employees
cursor.execute("""
insert into employee(empid,firstname,lastname,manager,dept,phone)
values(1,'Eric','Foster-Johnson',1,1,'555-5555')""")
cursor.execute("""
insert into employee(empid,firstname,lastname,manager,dept,phone)
values(2,'Peter','Tosh',2,3,'555-5554')""")
cursor.execute("""
insert into employee(empid,firstname,lastname,manager,dept,phone)
values(3,'Bunny','Wailer',2,2,'555-5553')""")
#create departments.
cursor.execute("""
insert into department(departmentid,name,manager)
values(1,'development',1)""")
cursor.execute("""
insert into department(departmentid,name,manager)
values(2,'qa',2)""")
cursor.execute("""
insert into department(departmentid,name,manager)
values(3,'operations',2)""")
#create users.
cursor.execute("""
insert into user(userid,username,employeeid)
values(1,'ericfj',1)""")
cursor.execute("""
insert into user(userid,username,employeeid)
values(2,'ericfj',2)""")
cursor.execute("""
insert into user(userid,username,employeeid)
values(3,'ericfj',3)""")
conn.commit()
cursor.close()
conn.close()
simplequery.py
import os
import sqlite3
conn=sqlite3.connect('sample_database')
cursor=conn.cursor()
cursor.execute("""
select e.firstname,e.lastname,d.name
from employee e inner join department d on e.dept=d.departmentid
order by e.lastname desc """)
for row in cursor.fetchall(): #数据存储到cursor对象中,可以使用fetchall方法提取这些数据,也可以用fetchone方法一次获取一行
print(row)# 这些数据显示python的元组
cursor.close()
conn.close()
import os
import sqlite3
conn=sqlite3.connect('sample_database')
cursor=conn.cursor()
username1="bunny"
query="""
select u.username,e.firstname,e.lastname,m.firstname,m.lastname,d.name
from user u,employee e,employee m,department d
where u.employeeid=e.empid
and e.manager=m.empid
and e.dept=d.departmentid
and u.username=?
"""
cursor.execute(query,(username1,))
#cursor.execute(query)
for row in cursor.fetchall():
(username,firstname,lastname,mgr_firstname,mgr_lastname,dept)=row
#print(row)
name=firstname+" "+lastname
manager=mgr_firstname+" "+mgr_lastname
print("%s:%s,managed by %s in %s"%(username,name,manager,dept))
#cursor.execute("update user set username=? where userid=?",("peter",2))
#cursor.execute("update user set username=? where userid=?",("bunny",3))
#conn.commit()
#cursor.execute("select * from user")
#for r in cursor.fetchall():
# print(r)
cursor.close()
conn.close()
sqlite3.connect(database)如果指定的数据库不存在,则创建一个数据库,可以指定带路径的文件名,在其他地方创建数据库
cursor.execute(sql[,optional parameters])sqlite3模块支持两种类型的占位符:问号和命名占位符
cursor.execute("insert into people values(?,?)",(who,age)) 元组参数列表
cursor.executescript(sql_script) 收到脚本会执行多个sql语句,用分号分隔
connection.total_changes()返回数据库连接打开以来被修改、插入或删除的数据库总行数
connection.commit() 提交当前的事务
connection.rollback()回滚更改
connection.close()关闭数据库连接
cursor.fetchone()返回一行结果,当没有数据时返回 None
cursor.fetchmany([size=cursor.arraysize]) 返回结果集中的下一行组,由size参数指定的一个列表
cursor.fetchall()获取所有行,返回一个列表 ,没有可用的行时,返回一个空的列表
可以利用cursor对象的definition属性查看返回数据的信息。
3 使用mysql connector
>>> mydb=mysql.connector.connect(host='localhost',user='root' ,passwd='123')
>>> mycursor=mydb.cursor()
>>> mycursor.execute("show databases")
>>> for x in mycursor:
print(x)
('information_schema',)
('mysql',)
('performance_schema',)
('sakila',)
('sys',)
('testmysql',)
('testwin',)
('world',)
>>>
import mysql.connector
mydb=mysql.connector.connect(host='localhost',user='root',passwd='123',database='testwin')
mycursor=mydb.cursor()
mycursor.execute("show tables")
for r in mycursor:
print(r)
mydb.commit()
mycursor.close()
mydb.close()
sql = "INSERT INTO sites (name, url) VALUES (%s, %s)" val = ("RUNOOB", "https://www.runoob.com")
mycursor.execute(sql, val)
sql = "INSERT INTO sites (name, url) VALUES (%s, %s)" val = [ ('Google', 'https://www.google.com'), ('Github', 'https://www.github.com'), ('Taobao', 'https://www.taobao.com'), ('stackoverflow', 'https://www.stackoverflow.com/') ] mycursor.executemany(sql, val)
print(mycursor.rowcount, "记录插入成功。")
sql = "SELECT * FROM sites WHERE name = %s" na = ("RUNOOB", ) mycursor.execute(sql, na) myresult = mycursor.fetchall()
sql = "UPDATE sites SET name = %s WHERE name = %s" val = ("Zhihu", "ZH") mycursor.execute(sql, val)
4 处理错误
Warning 用于非致命的问题。必须定义为StandardError的子类
Error 所有错误的基类。必须定义为StandardError的子类
InterfaceError用于数据库模块中的错误,而不是数据库本身的错误。必须定义为Error的子类
DatabaseError用于数据库中的错误。必须定义为Error的子类
DataError DatabaseError的子类,指数据中的错误
OperationalError DatabaseError的子类,指那些类似于丢失数据库连接 错误。这些错误一般在python脚本设计者的控制之外
IntegrityError DatabaseError的子类,用于可能破坏关系完整性的情况,例如唯一性约束或外键约束。
InternalError DatabaseError的子类,指数据库模块内部的错误,例如游标未被激活
ProgrammingError DatabaseError的子类,指那些类似于错误的表名称等由程序员造成的问题
NotSupportedError DatabaseError的子类,指试图调用不支持的功能
5 检查模块的功能和元数据
DB API 定义了几个需要在模块级别定义的全局变量。可以使用这些全局变量确定关于数据库模块的信息以及它所支持的一些特征。
Apilevel 对于DB API2.0 应该保存 2.0
Paramstyle 定义了在Sql语句中,如何显示动态数据的占位符
qmark 使用问号
numeric 使用一种位置数字的方式 ”:1“、” :2“
named 使用冒号和每个参数的名称 如:name
format 使用ANSI C Sprintf格式代码 如:对于字符串使用%s ,对于整数使用%d
pyformat 使用python 的扩展格式代码 如:%(name)s
import importlib
def get_paramstyle(conn):
name=conn.__class__.__module__.split('.')[0]
mod=importlib.import_module(name)
return mod.paramstyle
import sqlite3
conn=sqlite3.connect('sample_database')
styletest=get_paramstyle(conn)
print (styletest)
小结:
数据库为数据的存储提供了一种方便的手段。可以使用一些附加的模块编写能够访问所有主流数据库的python脚本。
dbm模块 持久化一个字典。
connection 对象封装了到数据库的一个连接。使用数据库模块的connect函数以得到一个新的连接。传递给connect函数的各个参数可能会因各个模块的不同而不同。
游标提供了用于与数据库进行交互的主要对象。使用connection对象以获得一个游标。游标可以执行一些sql语句
可以将动态数据作为一个包含若干值的元组传递给游标的 execute方法
在执行了一个查询操作之后,cursor对象对数据进行保存。使用fetchone 或fetchall方法都可以提取数据
在对数据库进行修改之后,调用connection对象的commit方法以提交事务并保存更改。使用rollback方法可以撤消更改。
当操作完成后,调用每个游标的close方法,当不需要连接时,调用connection对象的close方法
DBAPI定义了一个异常集合。python脚本应该对这些异常进行检查,以处理可能出现的各种问题
疑问:sqlite3物理地址,在哪里可以看到?怎么样查看数据库、表 结构?