在数据库中上传图像
我希望将上传的图像保存在PostgreSQL数据库的bytea
列中。 我正在寻找有关如何将Rails中的图像保存到bytea
列的建议,最好使用示例。
我使用Rails 3.1和“pg”驱动程序连接到PostgreSQL。
将图像存储在数据库中通常不是一个好主意
请参阅讨论是否最好将图像存储在BLOB或URL中? 和文件 – 在数据库中还是没有? 。 请注意,这些问题及其答案与PostgreSQL无关。
这有一些PostgreSQL特有的皱纹。 PostgreSQL没有任何增量转储function* ,因此如果您使用pg_dump
备份,则必须为每个备份转储所有图像数据。 存储空间和传输时间可能是一个问题,特别是因为您应该保留数周的备份,而不仅仅是一个最近的备份。
如果图像很大或很多,您可能需要考虑在文件系统中存储图像,除非您非常需要对它们进行事务性,符合ACID标准的访问。 将文件名存储在数据库中,或者仅根据有用的密钥建立文件命名约定。 这样,您就可以对映像目录进行简单的增量备份,并将其单独管理到数据库中。
如果将图像存储在FS中,则无法通过PostgreSQL数据库连接轻松访问它们。 OTOH你可以直接从文件系统直接通过HTTP为他们提供服务,比你必须首先从数据库中查询它们时更加高效。 特别是如果图像在FS上,而不是从数据库中,则可以使用rails中的sendfile() 。
如果你真的必须将图像存储在数据库中
…然后它在概念上与在.NET中相同,但确切的细节取决于您使用的Pg驱动程序,您没有指定。
有两种方法可以做到:
- 存储和检索
bytea
,正如您所询问的那样; 和 - 使用内置的大对象支持,这通常比使用
bytea
更好。
对于bytea正常的小图像:
- 将客户端的图像数据读入局部变量
- 通过将变量作为bytea传递到DB中。 假设您正在使用
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_create
, lo_open
等提供包装调用 ,并为本地文件访问提供lo_import
。 看到这个有用的例子 。
请使用大对象而不是bytea
。
*通过流复制,PITR / WAL归档等可以实现增量备份,但是再次增加数据库大小会使WAL管理变得复杂。 无论如何,除非你是专家(或“勇敢”),否则你应该采取pg_dump
备份,而不是单独依靠复制和PITR。 将图像放入数据库也会 – 通过增加数据库的大小 – 大大减慢pg_basebackup
,这在故障转移方案中很重要。
† adminpack通过Pg连接为超级用户提供本地文件访问。 但是,您的webapp用户永远不应拥有超级用户权限,甚至不应拥有与其一起使用的表的所有权。 您的文件是否通过WebDAV
等单独的安全通道进行读写。
- Rails 3查询:使用’select’和’order’时出错
- 使用Rails 4 Activerecord将多个列计数合并到单个查询中
- Postgres查询ILIKE和“%#{}%”
- 查询Postgres数组列类型
- Rails 4 / postgresql index – 我应该使用一个datetime列作为索引filter,它可以有无限数量的值吗?
- Rails:删除级联vs依赖destroy
- rails postgres ERROR:类型为double precision的输入语法无效
- 在Postgres的一张巨大的桌子上,Kaminari的COUNT(*)很慢
- Rails + PostgreSQL SSL解密失败