4

我想将上传的图像保存bytea在我的 PostgreSQL 数据库的列中。我正在寻找有关如何将 Rails 中的图像保存到bytea列中的建议,最好带有示例。

我使用带有“pg”驱动程序的 Rails 3.1 连接到 PostgreSQL。

4

1 回答 1

9

将图像本身存储在数据库中通常不是一个好主意

请参阅有关将图像存储在 BLOB 中还是仅 URL 中更好的讨论?和文件 - 是否在数据库中?. 请注意,这些问题及其答案与 PostgreSQL 无关。

这有一些 PostgreSQL 特定的皱纹。PostgreSQL 没有任何增量转储工具*,因此如果您使用pg_dump备份,则必须为每个备份转储所有图像数据。存储空间和传输时间可能是一个问题,特别是因为您应该保留数周的备份,而不仅仅是一个最近的备份。

如果图像很大或很多,您可能需要考虑将图像存储在文件系统中,除非您强烈需要对它们进行事务性、符合 ACID 的访问。将文件名存储在数据库中,或者只是根据有用的密钥建立文件命名约定。这样,您可以轻松地对映像目录进行增量备份,将其单独管理到适当的数据库中。

如果您将图像存储在 FS 中,您将无法轻松†</sup> 通过 PostgreSQL 数据库连接访问它们。OTOH,您可以直接从文件系统通过 HTTP 直接为它们提供服务,这比您必须首先从数据库查询它们时所希望的要高效得多。特别是,如果您的图像在 FS 上,但不能来自数据库,您可以使用 rails 中的 sendfile() 。

如果您真的必须将图像存储在数据库中

...那么它在概念上与 .NET 中的相同,但具体细节取决于您使用的 Pg 驱动程序,您没有指定。

有两种方法可以做到:

  • 存储和检索bytea,如您所问;和
  • 使用内置的大对象支持,这通常比使用bytea.

对于 bytea 可以的小图像:

  • 从客户端读取图像数据到局部变量
  • 通过将变量作为 bytea 传递将其插入数据库。假设您使用的是ruby-pg驱动程序,驱动程序中的test_binary_values示例应该对您有所帮助。

对于更大的图像(超过几兆字节) ,请lo改用:

对于更大的图像,请不要使用bytea. 它的理论最大值可能是 2GB,但实际上您需要 3 倍 RAM(或更多),因为图像大小会建议您避免使用bytea大图像或其他大型二进制数据。

PostgreSQL 有一个专用的lo(大对象)类型。在 9.1 上:

CREATE EXTENSION lo;
CREATE TABLE some_images(id serial primary key, lo image_data not null);

...然后用于lo_import从磁盘上的临时文件中读取数据,因此您不必一次将整个内容放入 RAM 中。

驱动程序为、等ruby-pg提供包装调用,并为本地文件访问提供了一个。请参阅这个有用的示例lo_createlo_openlo_import

请使用大物体而不是bytea.


*增量备份可以通过流复制、PITR / WAL 归档等进行,但再次增加数据库大小会使 WAL 管理等事情变得复杂。无论如何,除非您是专家(或“勇敢”),否则您应该进行pg_dump备份,而不是仅依靠复制和 PITR。将图像放入数据库也会——通过增加数据库的大小——大大减慢速度pg_basebackup,这在故障转移场景中可能很重要。

†</sup> adminpack通过 Pg 连接为超级用户提供本地文件访问。但是,您的 webapp 用户永远不应该拥有超级用户权限,甚至不应该拥有它所使用的表的所有权。通过单独的安全通道(例如WebDAV.

于 2012-08-13T06:48:09.187 回答