在 MySql 中存储 Pickle

Storing a Pickle in MySql

这是困扰我一段时间的问题。我有以下通过序列化一些 Python Dict 对象生成的 pickle 文件(名为 rawFile.raw):

rawFile.raw 的内容(为便于阅读而截断):

(dp0
S'request_body # 1'
p1
S''
p2
sS'port # 1'
p3
I80
sS'query_params # 1'
p4
ccopy_reg
_reconstructor
p5
(cnetlib.odict
ODict
p6
c__builtin__
object
p7
Ntp8
Rp9
(dp10
S'lst'
p11
(lp12
(S'layoutId'
p13
S'-1123196643'
p14
tp15
asbsS'headers # 1'
p16
g5
(cnetlib.odict
ODictCaseless
p17
g7
Ntp18
Rp19
(dp20
g11
(lp21
(lp22
S'sn'
p23
aS'2.VI7D9DF640615B4948854C88C5E769B94C.SIE5FB3A28D0DA4F27A3D2C03B8FAAFFAE.VS144257070601359422212.1442570840'
p24
aa(lp25
S'Browser-Name'
p26
aS'Mobile Safari'
p27
aa(lp28
S'Accept-Encoding'
p29
aS'gzip'
p30
aa(lp31
S'secureToken'
p32
aS'5nANXZrwYBrl9sNykA+qlpLsjHXlnF97tQLHnPgcjwZm9u0t8XAHtO4XTjKODcIb0ee4LlFchmUiptWZEPDUng=='
p33
aa(lp34
S'User-Agent'
p35
aS'Mozilla/5.0 (Linux; U; Android 4.3; en-us; Google Galaxy Nexus - 4.3 - API 18 - 720x1280 Build/JLS36G) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 FKUA/Retail/590206/Android/Mobile (Genymotion/Google Galaxy Nexus - 4.3 - API 18 - 720x1280/fd6babaa1ff9127ed7e9cc7a916639e5)'
p36
aa(lp37
S'Device-Id'
p38
aS'fd6babaa1ff9127ed7e9cc7a916639e5'
p39
aa(lp40
S'Host'
p41
aS'mobileapi.flipkart.net'
p42
aa(lp43
S'Connection'
p44
aS'Keep-Alive'
p45
aasbsS'method # 1'
p46
S'GET'
p47
sS'scheme # 1'
p48
S'http'
p49
sS'path # 1'
p50
(lp51
S'3'
p52
aS'layout'
p53
aS'widget'
p54
aS'productBundle'
p55
as.(dp0
S'request_body # 1'
p1
S''
p2
sS'method # 1'
p3
S'GET'
p4
sS'query_params # 2'
p5
ccopy_reg
_reconstructor
p6
(cnetlib.odict
ODict
p7
c__builtin__
object
p8
Ntp9
Rp10
(dp11
S'lst'
p12
(lp13
sbsS'query_params # 1'
p14

...更多类似内容被截断。

现在我需要将此文件的内容存储在 MySql table 中的一个列中。通过一些谷歌搜索,我了解到这些应该存储在 BLOB 列中。所以我做了。另外,如果您观察,上面的内容也有很多单引号和(可能有)双引号。我正在使用 MySqlDB python 连接器。因此,当我尝试将上述数据插入相应列中时:

INSERT INTO session_logs(request_as_on, session_pickle) VALUES (%s, %s)

然后是

self.cur.execute(insertValueQry,(parser.parse(reqTimeStamp).strftime('%Y-%m-%d %H:%M:%S'), putThisPickleInDb))

我收到以下错误:

mysqldb insertion error while inserting Error 1241: Operand should contain 1 column(s)

因此,为了解决上述问题,我将上面的执行语句替换为:

self.cur.execute(insertValueQry,(parser.parse(reqTimeStamp).strftime('%Y-%m-%d %H:%M:%S'), self.con.escape_string(str(putThisPickleInDb))))

它通过转义 pickle 数据中的所有单引号和双引号解决了这个问题。但它不会以与原始文件中相同的格式将数据存储在 table 中。

显然,现在当我需要从数据库中读回这个 pickle 内容时,

  1. 它仍然被转义 - 所以我执行以下操作来取消转义并获取原始内容:

    aalu = "" <br>
    aalu = aalu + str(userSelectedSessionPickle[0]).decode('string_escape').decode('string_escape')
    

其中 userSelectedSessionPickle 是从数据库返回的元组。

  1. 取消转义后,我尝试用它再次制作泡菜:

    pickle.dump (aalu, currentPickleRawFile)
    

这样我可以稍后加载 pickle 文件并在需要时使用它。但是当对文件 currentPickleRawFile 执行 pickle.load 时,它会抛出以下错误:

ValueError: dictionary update sequence element #0 has length 1; 2 is required

以防万一,如果它有帮助:当我在文本编辑器中打开文件 currentPickleRawFile 时,其中内容的格式与 rawFile.raw 中的内容不同(如上所示的内容)。

我只需要将上面的 pickle 文件存储在数据库中,然后能够将其加载回来。我该如何完成?

如果你想在 sql table 或 sql 数据库中存储 pickled 对象,有一个名为 klepto 的包(我写的)允许你透明地做到这一点。由于您有兴趣将字典作为单个对象存储在 sql table 中,我将在下面执行此操作……但您可以存储任何对象。 klepto 用于将字典条目映射到数据库或 table。

>>> import klepto
>>> # dump to the sql archive
>>> d = klepto.archives.sql_archive('mysql')
>>> a = dict(a=1,b=2,c=3,d=min,e=lambda x:x,f=[1,2,3,4,5])
>>> d['x'] = a
>>> d.dump()
>>> del d, a
>>>
>>> # read from the sql archive
>>> d = klepto.archives.sql_archive('mysql')
>>> d.load()
>>> a = d['x']
>>> a     
{'a': 1, 'c': 3, 'b': 2, 'e': <function <lambda> at 0x103aa9848>, 'd': <built-in function min>, 'f': [1, 2, 3, 4, 5]}
>>> 
>>> # different options for klepto backends
>>> klepto.archives.sql_archive 
<class 'klepto.archives.sql_archive'>
>>> klepto.archives.sqltable_archive
<class 'klepto.archives.sqltable_archive'>
>>> klepto.archives.file_archive
<class 'klepto.archives.file_archive'>
>>> klepto.archives.dir_archive
<class 'klepto.archives.dir_archive'>

认为解决方案是不公正的。我必须,必须 提到这个天使博客,它终于拯救了我,帮助我完成了现在几乎让我发疯的工作。

http://blog.cameronleger.com/2011/05/31/python-example-pickling-things-into-mysql-databases/

看起来他将 pickle 插入数据库的方式就是诀窍。

正如有人在下面的评论中建议的那样,如果博客失效,我们将再次松开问题的解决方案。所以这里是代码片段,复制粘贴 来自博客 post:

import cPickle
import MySQLdb

## Create a semi-complex list to pickle
listToPickle = [(10, 10), (20, 10.0), (1.0, 2.0)]

## Pickle the list into a string
pickledList = cPickle.dumps(listToPickle)

## Connect to the database as localhost, user pickle,
## password cucumber, database lists
connection = MySQLdb.connect('localhost','pickle','cucumber','lists')

## Create a cursor for interacting
cursor = connection.cursor()

## Add the information to the database table pickleTest
cursor.execute("""INSERT INTO pickleTest VALUES (NULL, 'testCard', %s)""", (pickledList, ))

## Select what we just added
cursor.execute("""SELECT features FROM pickleTest WHERE card = 'testCard'""")

## Dump the results to a string
rows = cursor.fetchall()

## Get the results
for each in rows:
    ## The result is also in a tuple
    for pickledStoredList in each:
        ## Unpickle the stored string
        unpickledList = cPickle.loads(pickledStoredList)
        print unpickledList