0%

写一个资源共享服务 03.python里的sqlite3

写一个资源共享服务 3.python里的sqlite3

上次我们大概讲述的关系型数据库的理论部分, 这次我们实际编码实现真正能用的数据存取模块。

我们说标准python模块提供了sqlite3数据库的支持, 无需额外安装任何模块直接import导入即可使用。

此外我们的数据库操作和文件操作大体相似, 创建文件, 打开文件; 读写文件和关闭文件, 同样的套路创建数据库; 连接数据库; 增删改查数据库最后关闭数据库。

但是数据库操作接口和文件操作接口相比显得更加复杂, 设计文件操作无非就是open; read; write和close, 而数据库的基本操作包括如下这几种:

  • connect 连接到数据库

  • execute 执行sql语句

  • commit 提交生效, 见下文详细解释

  • close 关闭或者断开数据库

    那么我们为什么要使用更加复杂的sql数据库, 而不用相对简单的文件?

    虽然读写文件貌似比sql语句简单, 但是如果把数据存取到文件, 那么需要大量的数据解析工作, 而这一切我们需要自己实现。

    如果直接用sql数据库的话可以省去大量的工作量, 用上最优秀的数据存取方案。

    当然存取少量的数据我们也可以使用xml; json这样的方案。

    接下来我们开始设计保存资源的数据表,

定义数据表

我们前面讲过insert; delete; update和select是数据库增删改查四大语句, 此外我们还需要其他一些语句, 可以称之为sql定义语句, 比如创建数据表; 修改数据表和删除数据表。

你对数据库做增删改查之前需要定义数据表的格式, 后续你也许修改数据表的格式或者删除某个数据表, 但是个人觉得修改数据表不是什么明智之举, 更好的做法是定义新的数据表然后把原来的数据从旧数据表里迁移到新创建的数据表, 原来的数据表直接弃用。

这里简单解释一下所谓的修改数据表格式, 本来你的论坛用户数据表有昵称; 密码和邮箱地址, 但是你接到了主管部门的通知, “要求用户发布内容必须实名认证”, 那如此你的用户数据表需要增加两个新字段, 真实姓名和手机号码,

这个时候你最好的做法不是在原来的数据表上折腾, 而是直接创建新的数据表, 当然很多具体问题还是具体看。

在sqlite3里创建一个数据表的语句是:

CREATE TABLE 数据表名称 (字段1 类型 约束, ............ );

学过编程的人字段名称和类型好理解, 所谓的约束就是, 这个字段有什么具体要求, 比如常用的:

  • NOT NULL 表示不接受空值

  • DEFAULT 100 如果没有提供值, 默认就是100这个值

  • PRIMARY KEY 表示这是主键, 所谓的主键唯一标记一条记录, 每个人的身份证号都不相同, 而其他字段可以是相同的, 所以说身份证号就是我们每个人的主键

  • AUTOINCREMENT 表示这个字段自动增长, 比如论坛按照注册先后自动分配用户ID

    一个典型的数据表定义如下所示, 这也是我们资源数据表的定义:

CREATE TABLE RES_HUB_TAB (ID INTEGER PRIMARY KEY AUTOINCREMENT,
DESCRIPTION TEXT NOT NULL,
BINARY_CONTENT BLOB,
TEXT_CONTENT TEXT,
DATETIME INTEGER NOT NULL,
INVALID INT DEFAULT 1);

通常情况下我们数据表名称用_TAB或者_TABLE做后缀。

我们的资源有个自动分配的ID, 类型是integer, 而且这是主键。

还有两个字段标记为不能为空, description类型是text描述当前资源; 第二个是datetime类型是integer, 表示资源的时间戳, 这两个字段不接受空值。

儿TEXT_CONTENT和BINARY_CONTENT保存资源本身的主要内容, TEXT_CONTENT保存字符串, BINARY_CONTENT保存二进制数据, 两者没有额外的约束, 可以接受空值。

最后就是invalid标记资源是否有效, 默认值1, 表明资源是有效的, 如果删除资源的话需要把INVALID设为0,

那么什么时候真正删除资源呢? 当数据库的大小达到某个阈值的时候, 比如10G, 或者删除的时候设置时间戳, 某个资源逻辑删除过去某个时间段后删除。

上面的话比较拗口, 比如用户删除某个资源, 这个时候invalid为0; 同时datetime设为当前时间, 而后过去一段时间比如超过三个月就彻底从数据库里删除该资源,

这样我们就实现了回收站的功能, 哪天用户后悔了想要恢复已删除的资源, 那么我们只要把invalid设为1; 重新设置一下资源的时间戳就ok了。

自动清理功能可以用过期时间; 也可以用数据库最大容量, 或者两者兼而有之, 全拼自由发挥!

这样算是把我们的资源数据表定义好了, 需要说明的是sqlite的数据类型系统非常丰富灵活; 大家对数据表的理解也有很大差距, 我这里提供的只是一种参考而已, 如果大家能想到更加合理的方案, 那么也完全可以自行采用。

这里唯一需要解释的是为什么搞出text_content和binary_content两个字段, 难道统一用binary_content来保存不行么?

答案是为了后续做全文搜索功能, 在字符串里可以做搜索, 如果这是一张图片或者一段音频呢? 所以只能分成二进制数据和字符串数据, 然后把字符串类型的资源和其他资源分别存储。

python里的sqlite3

python的sqlite3提供了一些比较好用的接口, 而其他第三方数据库也提供了类似的接口, 所以学会sqlite3模块后可以无障碍上手其他RDMS提供的python模块, 比如pymysql; pysqlserver等等。

如下是几个重要的函数:

  • 函数: connect 连接到一个数据库,

  • 方法: Connection.execute 执行一个sql语句

  • 方法: Cursor.fetchall 返回全部查询结果

  • 方法: Cursor.fetchone 返回下一条查询结果

  • 属性: Connection.total_changes 返回本次连接更改的总行数

  • 方法: Connection.commit 提交事务

  • 方法: Connection.close 关闭数据库连接

    此外Connection.get_cursor提供了获取游标的方法, 而游标Cursor对象除了能获取sql查询结果之外也能执行execute方法。

    实际上Connection.execute方法是Cursor.execute方法的快捷方式, 不过我们直接用Connection对象的方法就可以了。

    还有execute有好几个变体, 具体可以参考文档……

总结

本篇也一直在给后续的实际开发做铺垫, 但是事情还没结束, 下次我们讲一讲如何提高开发效率……

未完待续……