【问题标题】:Upload images in database上传图片到数据库
【发布时间】:2012-08-13 06:28:59
【问题描述】:

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

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

【问题讨论】:

  • 请显示您为解决问题而编写的代码。
  • 现在我只是将文件加载到文件夹中,但我需要将它保存在数据库中。我一直在编程 ASP.NET,现在正在学习 ruby​​。我知道如何在 .NET 中做到这一点,我需要 Rails 上的示例。
  • @user1466717 您使用的是哪个 PostgreSQL Ruby 驱动程序? ruby-pg?
  • 我使用 gem pg rubygems.org/gems/pg

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


【解决方案1】:

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

查看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 直接从文件系统为它们提供服务,这比您必须首先从数据库查询它们时曾经希望的效率要高得多。如果您的图像在 FS 上,但不是来自数据库,则特别是 can use sendfile() from rails

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

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

有两种方法:

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

对于可以使用 bytea 的小图像:

  • 将图像数据从客户端读取到局部变量中
  • 通过将变量作为 bytea 传递将其插入 DB。假设您使用的是 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 等单独的安全通道读取和写入文件。

【讨论】:

  • 思路如下。我的文件将存储在数据库和文件系统中。如果文件从文件系统中删除,它将再次自动从数据库文件中加载并存储在文件夹中。
  • @user1466717 呃,为什么?这是两全其美的。你想用这种方法解决什么问题?潜在的问题是什么,您想要这样做的原因是什么?
  • @user1466717 顺便说一句,答案更新为the examples in the ruby-pg tests 的链接以获取bytea 访问权限。
  • 当你查看页面图片时会从文件系统发出。如果文件传输或意外删除,则第一个页面加载是从基础加载并从头开始配置的图片。这将保存所有图像,并且不会在每次页面加载时加载数据库。
  • @jug 指的是数据库中的大对象。 lo 伪类型为您处理此问题,无需自定义编码,因此它比手动滚动触发器更安全。要管理外部文件,您可以NOTIFY 一个LISTENing 进程告诉它删除文件;理想情况下,您的数据库不应拥有比绝对需要更多的文件系统访问权限,因此不应自行删除它们。
猜你喜欢
  • 1970-01-01
  • 2020-12-07
  • 2014-03-29
  • 2013-12-25
  • 2018-06-27
  • 2015-04-10
相关资源
最近更新 更多