在数据库中上传图像

时间:2012-08-13 06:28:59

标签: ruby ruby-on-rails-3 postgresql ruby-on-rails-3.1

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

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

1 个答案:

答案 0 :(得分:9)

将图像存储在自己的数据库

中通常不是一个好主意

查看有关is it better to store images in a BLOB or just the URL?Files - in the database or not?的讨论。请注意,这些问题及其答案与PostgreSQL无关。

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

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

如果您将图像存储在FS中,则无法通过PostgreSQL数据库连接轻松访问它们。 OTOH你可以直接从文件系统直接通过HTTP为他们提供服务,而不是曾经希望当你必须首先从数据库中查询它们时。特别是你can use sendfile() from rails如果你的图像在FS上,而不是在数据库中。

如果您确实必须将图像存储在数据库

...然后它在概念上与.NET相同,但确切的细节取决于您使用的Pg驱动程序,您没有指定。

有两种方法可以做到:

  • 按照您的要求存储和检索bytea;和
  • 使用内置的大对象支持,这通常比使用bytea更好。

对于bytea正常的小图像:

  • 将客户端的图像数据读入本地变量
  • 通过将变量作为bytea传递到数据库中。假设您正在使用ruby-pg驱动程序,驱动程序中的test_binary_values示例应该可以帮助您。

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

对于较大的图片,请不要使用bytea。它的理论最大值可能是2GB,但是in practice you need 3x the RAM (or more) as the image size would suggest因此您应该避免对大图像或其他大型二进制数据使用bytea

PostgreSQL有一个dedicated lo (large object) type。在9.1只:

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

...然后使用lo_import从磁盘上的临时文件中读取数据,这样您就不必立即将整个内容放在RAM中。

驱动程序ruby-pglo_createlo_open等提供wrapper calls,并为本地文件访问提供lo_import。请参阅this useful example

请使用大型对象而不是bytea


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

adminpack通过Pg连接为超级用户提供本地文件访问。但是,您的webapp用户永远不会拥有超级用户权限,甚至拥有其使用的表的所有权。您的文件是通过WebDAV等单独的安全通道进行读写。