可以将Python字典序列化到sqlite3文本字段吗?
有没有什么需要注意的地方?我可以把它存放在文本字段里,还是必须用二进制大对象(blob)?
(我对pickle和sqlite都不是很熟悉,所以我想确认一下我的一些高层设计想法是不是在正确的方向上。)
14 个回答
我写了一篇关于这个想法的博客,不过我用的是json,而不是pickle,因为我想让它能和perl以及其他程序一起使用。
http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/
从架构上看,这是一种快速且简单的方法,可以让任意数据结构实现持久化、事务等功能。我发现这种组合在我需要持久化数据时特别有用,而且在sql层面上不需要做太多操作(或者在sql中处理起来非常复杂,而用生成器处理则简单得多)。
代码本身也很简单:
# register the "loader" to get the data back out.
sqlite3.register_converter("pickle", cPickle.loads)
然后,当你想把它存入数据库时,
p_string = p.dumps( dict(a=1,b=[1,2,3]))
conn.execute('''
create table snapshot(
id INTEGER PRIMARY KEY AUTOINCREMENT,
mydata pickle);
''')
conn.execute('''
insert into snapshot values
(null, ?)''', (p_string,))
''')
我也需要实现同样的功能。
这让我费了不少脑筋,直到我终于搞明白了,多亏了这篇文章,我才知道怎么在二进制格式下让它正常工作。
插入/更新数据:
pdata = cPickle.dumps(data, cPickle.HIGHEST_PROTOCOL)
curr.execute("insert into table (data) values (:data)", sqlite3.Binary(pdata))
你必须给dumps函数传递第二个参数,这样才能强制使用二进制格式进行序列化。
另外,记得使用sqlite3.Binary,这样才能把数据放进BLOB字段里。
获取数据:
curr.execute("select data from table limit 1")
for row in curr:
data = cPickle.loads(str(row['data']))
当你获取BLOB字段的数据时,sqlite3会得到一个'buffer'类型的数据,这个数据需要用str函数转换成字符串,然后才能传给loads方法。
如果你想存储一个被“腌制”的对象(这是一种数据处理方式),你需要用到一个叫做“blob”的东西,因为它是二进制数据。不过,你可以把这个“腌制”的对象进行base64编码,这样就能得到一个可以存储在文本字段里的字符串。
不过,通常来说,这种做法可能不是个好主意,因为你存储的是一种不透明的数据,这样一来,你就无法用SQL(一种数据库查询语言)对这些数据进行有用的操作了。不过,具体情况我也不太清楚,所以没法对这个做法下定论。