【问题标题】:how to use Blob datatype in Postgres如何在 Postgres 中使用 Blob 数据类型
【发布时间】:2020-11-03 22:34:03
【问题描述】:

我在我的 rails 应用程序中使用 Postgresql 数据库。 为了在数据库中存储大文件或数据,我在 MySql 中使用了 blob 数据类型。

对于 Postgres,我必须使用哪种数据类型而不是 MySql 中的 blob?

【问题讨论】:

标签: database postgresql


【解决方案1】:

使用bytea(如果您使用absolutely have to),则使用Large Objects

【讨论】:

  • 你为什么说“如果你绝对必须”?您认为使用大对象的主要缺点是什么?
  • @avernet - 是的,他们更难合作并且拥有some security issues
  • @dave no, bytea is binary data - 它的大小肯定不会翻倍 - 'hex' 格式用于输入和输出,而不是用于存储。当然,您的客户如何选择显示该二进制数据是另一回事...
  • bytea 在获取行时加载。所以要注意记忆。 Blob 数据在实际需要数据时通过 STDOUT 加载。
  • 我确实发现 bytea 在客户端需要额外的 RAM 才能进行转换,但是 @daveatflow 你对存储的看法是错误的。与所有 PostgreSQL 类型一样,它作为文本字符串暴露给 SQL 接口,但就像时间戳或几何图形或 inet 地址一样,文本表示不是内部二进制表示。 Pg 文档中充满了如何编写二进制时间的示例,可以清楚地说明这一点。
【解决方案2】:

我认为这是 PostgreSQL wiki 本身最全面的答案:https://wiki.postgresql.org/wiki/BinaryFilesInDB

阅读标题为“将文件存储在数据库中的最佳方式是什么?”的部分

【讨论】:

    【解决方案3】:

    将文件存储在数据库中会导致数据库变大。对于开发、测试、备份等,您可能不喜欢这样。

    相反,您将使用 FileStream (SQL-Server) 或 BFILE (Oracle)。

    Postgres 中没有 BFILE/FileStream 的默认实现,但您可以添加它: https://github.com/darold/external_file

    更多信息(法语)可以在这里获得:
    http://blog.dalibo.com/2015/01/26/Extension_BFILE_pour_PostgreSQL.html


    回答尖锐的问题:
    除了bytea,对于非常大的文件,你可以使用LOBS

    // http://stackoverflow.com/questions/14509747/inserting-large-object-into-postgresql-returns-53200-out-of-memory-error
    // https://github.com/npgsql/Npgsql/wiki/User-Manual
    public int InsertLargeObject()
    {
        int noid;
        byte[] BinaryData = new byte[123];
    
        // Npgsql.NpgsqlCommand cmd ;
        // long lng = cmd.LastInsertedOID;
    
        using (Npgsql.NpgsqlConnection connection = new Npgsql.NpgsqlConnection(GetConnectionString()))
        {
            using (Npgsql.NpgsqlTransaction transaction = connection.BeginTransaction())
            {
                try
                {
                    NpgsqlTypes.LargeObjectManager manager = new NpgsqlTypes.LargeObjectManager(connection);
                    noid = manager.Create(NpgsqlTypes.LargeObjectManager.READWRITE);
                    NpgsqlTypes.LargeObject lo = manager.Open(noid, NpgsqlTypes.LargeObjectManager.READWRITE);
    
                    // lo.Write(BinaryData);
                    int i = 0;
                    do
                    {
                        int length = 1000;
                        if (i + length > BinaryData.Length)
                            length = BinaryData.Length - i;
    
                        byte[] chunk = new byte[length];
                        System.Array.Copy(BinaryData, i, chunk, 0, length);
                        lo.Write(chunk, 0, length);
                        i += length;
                    } while (i < BinaryData.Length);
    
                    lo.Close();
                    transaction.Commit();
                } // End Try
                catch
                {
                    transaction.Rollback();
                    throw;
                } // End Catch
    
                return noid;
            } // End Using transaction 
    
        } // End using connection
    
    } // End Function InsertLargeObject 
    
    
    
    public System.Drawing.Image GetLargeDrawing(int idOfOID)
    {
        System.Drawing.Image img;
    
        using (Npgsql.NpgsqlConnection connection = new Npgsql.NpgsqlConnection(GetConnectionString()))
        {
            lock (connection)
            {
                if (connection.State != System.Data.ConnectionState.Open)
                    connection.Open();
    
                using (Npgsql.NpgsqlTransaction trans = connection.BeginTransaction())
                {
                    NpgsqlTypes.LargeObjectManager lbm = new NpgsqlTypes.LargeObjectManager(connection);
                    NpgsqlTypes.LargeObject lo = lbm.Open(takeOID(idOfOID), NpgsqlTypes.LargeObjectManager.READWRITE); //take picture oid from metod takeOID
                    byte[] buffer = new byte[32768];
    
                    using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                    {
                        int read;
                        while ((read = lo.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            ms.Write(buffer, 0, read);
                        } // Whend
    
                        img = System.Drawing.Image.FromStream(ms);
                    } // End Using ms
    
                    lo.Close();
                    trans.Commit();
    
                    if (connection.State != System.Data.ConnectionState.Closed)
                        connection.Close();
                } // End Using trans
    
            } // End lock connection
    
        } // End Using connection
    
        return img;
    } // End Function GetLargeDrawing
    
    
    
    public void DeleteLargeObject(int noid)
    {
        using (Npgsql.NpgsqlConnection connection = new Npgsql.NpgsqlConnection(GetConnectionString()))
        {
            if (connection.State != System.Data.ConnectionState.Open)
                connection.Open();
    
            using (Npgsql.NpgsqlTransaction trans = connection.BeginTransaction())
            {
                NpgsqlTypes.LargeObjectManager lbm = new NpgsqlTypes.LargeObjectManager(connection);
                lbm.Delete(noid);
    
                trans.Commit();
    
                if (connection.State != System.Data.ConnectionState.Closed)
                    connection.Close();
            } // End Using trans 
    
        } // End Using connection
    
    } // End Sub DeleteLargeObject 
    

    【讨论】:

    • 但这不是问题的答案(它是相关的,但不是答案)。
    • @Bruno Ranschaert:是的 - 修复了这个问题。但大多数赞成票的答案也没有。但是实际的问题不是“如何使用 blob/bytea/lobs”,而是“如何在数据库中存储大文件或数据”(如问题中所述) - 答案是:大文件不属于数据库- 我的意思既不是 bytea 也不是 blob。我的回答回答了如何(正确地)做到这一点。不需要 Blob。
    猜你喜欢
    • 1970-01-01
    • 2017-02-11
    • 2022-01-26
    • 2020-06-29
    • 2020-11-29
    • 1970-01-01
    • 2014-10-01
    • 2023-03-04
    • 2020-10-16
    相关资源
    最近更新 更多