当我尝试用pymysql插入大blob时断管

时间:2012-11-14 09:58:00

标签: python mysql pymysql

我有一个基于烧瓶的网络应用程序,允许用户上传文件。文件存储在mysql数据库中。

这样可以正常工作,直到文件大于16Mb,插入失败并显示以下内容:

File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1518, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1506, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1504, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1264, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1262, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1248, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/<redacted>/access_control.py", line 15, in decorated_function
    return f(*args, **kwargs)
  File "/<redacted>/views/files.py", line 48, in upload
    VALUES (%s, %s, %s, %s, %s)""", file_details)
  File "/<redacted>/database.py", line 66, in query
    cursor.execute(sql, values)
  File "/usr/local/lib/python2.7/dist-packages/pymysql/cursors.py", line 262, in execute
    result = super(DictCursor, self).execute(query, args)
  File "/usr/local/lib/python2.7/dist-packages/pymysql/cursors.py", line 117, in execute
    self.errorhandler(self, exc, value)
  File "/usr/local/lib/python2.7/dist-packages/pymysql/connections.py", line 187, in defaulterrorhandler
    raise Error(errorclass, errorvalue)
Error: (<class 'socket.error'>, error(32, 'Broken pipe'))

当文件大小似乎与mySQL设置max_allowed_packet匹配时,我很兴奋,因此我在my.cnf中更改了它并重新启动但它没有帮助。 (show variables like 'max_allowed_packet'显示新值150M)

该文件肯定会上传到服务器,我将一些代码放入我的insert方法,在运行查询之前将文件写入磁盘并且文件正常。

blob插入的字段是longblob,负责插入的代码是:

@mod.route('/file/upload', methods=['POST'])
@login_required
def upload():
    filename = request.files['file'].filename
    mime_type = request.files['file'].mimetype
    #filesize = request.files['file'].content_length
    file = request.files['file'].stream.read()

    if mime_type[:5] == 'image':
        file = resize_image_to_width(file, 1024)

    filesize = len(file)
    if filesize == 0:
        return ""

    if not request.form['file_id']:
        file_details = (filename, file, mime_type, filesize, session['user']['user_id'])
        file_id = database.query("""INSERT INTO files (filename, file, mime_type, filesize, owner)
                                      VALUES (%s, %s, %s, %s, %s)""", file_details)
    else:
        file_details = (filename, file, mime_type, filesize, request.form['file_id'])

        file_id = database.query("""UPDATE files 
                                    SET 
                                        filename=%s, 
                                        file=%s, 
                                        mime_type=%s, 
                                        filesize=%s 
                                    WHERE file_id=%s""", file_details)
    return "upload complete"

我现在有点不知所措,我确实在一周前找到了一些东西,建议将文件插入各个部分,但我现在找不到它(我被我分心了)实际的工作!)我不知道如何将其插入块中。

我真的很感激这方面的帮助!

2 个答案:

答案 0 :(得分:0)

首先,您希望将文件分块为可插入的安全大小的块,在您的情况下,您可以将其设置为10MB。您可以使用该答案中的chunks function来执行此操作。然后插入第一块数据并执行一系列更新,将其他块连接到该blob上。要做到这一点,请查看append/concatenate BLOB data to a BLOB column using update?上的问题。

答案 1 :(得分:0)

这是另一种方法。使用LOAD_FILE函数将文件加载到blob列中。

UPDATE t SET blob_col=LOAD_FILE('/tmp/image.png') WHERE id=1;

这不应该面对您的16MB限制。如果您遇到任何二进制编码问题,可以使用十六进制格式的python保存图像,然后使用UNHEX将其安全地解码回原始二进制格式。

UPDATE t SET blob_col=UNHEX(LOAD_FILE('/tmp/image.png.hex')) WHERE id=1;

如果您的网络服务器位于同一台服务器上,这两个选项都需要您将文件保存在MySQL服务器文件系统上,否则您可能必须使用类似scp或ftp之类的东西将文件传输到MySQL服务器SQL语句。

相关问题