数据存储:从pickle到sqlite 《Head First Python》第九章

本文介绍了一个简单的案例,展示了如何从使用pickle和文本文件存储数据转为使用sqlite数据库进行统一存储,解决了数据不一致的问题,并提供了具体的实现步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 pickle存储+文本存储——容易出现数据不一致

当有数据需要更新时,前面章节所采取的“pickle+文本”的存储模式会存在问题,如下图所示:
20170130-1.JPG
如果更新pickle,下一次put_to_store()函数运行时,罪行的更新会丢失,因为put_to_store()会由文本文件中的数据重新创建pickle。
如果更新文本文件,则直到put_to_store()再次运行时,pickle才会得到更新,造成用户调用不一致的情况。中不一致成为竞态条件。要尽量避免这种情况发生,就需要采取更好的存储机制。

如果能把数据只存储在一个地方,并能支持相应的需求,那该多好!

这就是——数据库。

我们有许多选择:
20170130-2.JPG
这些都很好,但是对于我们的应用 优点大材小用。

Python自带的sqlite

2 用sqlite存储所有的数据

2.1 python与sqlite

python预装了sqlite,这是一个相当完备、无需配置的基于SQL的数据管理系统。
要使用sqlite只需导入sqlite库,并使用python标准化数据库API来编程,不需要数据库设置,没有配置,也没有后续维护。

2.2 python的数据库接口(API)

python数据库API提供了一种标准机制,可以针对各种各样的数据库管理系统编程,其中包括sqlite,不论后台数据库是什么,代码遵循的过程基本一致:
20170130-3.JPG
下面图是python与sqlite交互的代码示例:
20170130-4.JPG

2.3 pickle存储模式

数据在pickle中存储的方法如下图所示,每个选手的数据是一个AthleteList对象实例与字典中的选手名相关联,整个字典存放在pickle中。
20170130-5.JPG
每个AthleteList有以下属性:
20170130-6.JPG
从这种设计模式可以清楚的看出哪个名字、出生日期于那个选手相对,如何在sqlite数据库中建立起这种关系呢?

2.4 sqlite存储模式

创建数据库coachdata.sqlite,它包含两个表:athletes和timing_data。

2.5 创建sqlite数据库

创建的方法是用python API编写相关的代码,将程序命名为createDBtables.py其代码如下:

import sqlite3
connection = sqlite3.connect('coachdata.sqlite')
cursor = connection.cursor()
cursor.executescript("""
       CREATE TABLE athletes(
                  id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,
                  name TEXT NOT NULL,
                  dob DATE NOT NULL);
                  """)
cursor.executescript("""
       CREATE TABLE timing_data(
                  athlete_id INTEGER NOT NULL,
                  value TEXT NOT NULL,
                  FOREIGN KEY (athlete_id) REFERENCES athletes)
                  """)
connection.commit()
connection.close()

其中,创建表athletes的第一行代码,按照《Head First Python》上的:

id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL会出错,而写成:

id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE才可以。

2.6 从pickle向sqlite导入数据

创建好数据库和表,需要将数据从现在的模型(pickle+文本)传输到数据库模型中。可以编写代码来完成这个工作,先给出initDBathletes.py的完整代码:

import sqlite3

connection = sqlite3.connect('coachdata.sqlite')
cursor = connection.cursor()

import glob
import athletemodel

data_files = glob.glob("../data/*.txt")
athletes = athletemodel.put_to_store(data_files)

for each_ath in athletes:
    name = athletes[each_ath].name
    dob  = athletes[each_ath].dob
    cursor.execute("INSERT INTO athletes (name,dob) VALUES (?,?)",(name,dob))
    connection.commit()
    cursor.execute("SELECT id from athletes WHERE name=? AND dob=?",(name,dob))
    the_current_id=cursor.fetchone()[0]
    for each_time in athletes[each_ath].clean_data:
        cursor.execute("INSERT INTO timing_data (athlete_id,value) VALUES (?,?)",
                                (the_current_id,each_time)) 
    connection.commit()
connection.close()

第1步:将运动员的文本数据转换为AthleteList实例:

data_files = glob.glob("../data/*.txt")
athletes = athletemodel.put_to_store(data_files)

第2步:逐一将每个运动员的数据加入到表中:
(1)首先是加入运动员的姓名和出生日期

    name = athletes[each_ath].name
    dob  = athletes[each_ath].dob
    cursor.execute("INSERT INTO athletes (name,dob) VALUES (?,?)",(name,dob))
    connection.commit()

(2)查询刚才加入的运动员的id,将运动员的id和运动员的成绩逐一增加到成绩表timing_data中。

 cursor.execute("SELECT id from athletes WHERE name=? AND dob=?",(name,dob))
    the_current_id=cursor.fetchone()[0]
    for each_time in athletes[each_ath].clean_data:
        cursor.execute("INSERT INTO timing_data (athlete_id,value) VALUES (?,?)",
                                (the_current_id,each_time)) 
    connection.commit()

2.7 sqlite数据查看——SQLite Manager

安装工具软件SQLite Manager便可方便查看sqlite数据库的数据。
20170130-7.JPG
20170130-8.JPG

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值