将图像直接存储在数据库中还是作为base64数据存储?

Posted

技术标签:

【中文标题】将图像直接存储在数据库中还是作为base64数据存储?【英文标题】:Storing image in database directly or as base64 data? 【发布时间】:2012-04-01 03:08:03 【问题描述】:

在数据库中存储图像的常用方法是在存储数据之前将图像转换为base64数据。此过程将使大小增加 33%。或者,可以直接将图像存储为BLOB;例如:

$image = new Imagick("image.jpg");
$data = $image->getImageBlob();
$data = $mysqli->real_escape_string($data);
$mysqli->query("INSERT INTO images (data) VALUES ('$data')");

然后用

显示图片
<img src="data:image/jpeg;base64,' .  base64_encode($data)  . '" />

使用后一种方法,我们节省了 1/3 的存储空间。为什么在 MySQL 数据库中将图像存储为 base64 更为常见?

更新:关于将图像存储在数据库中的优缺点存在很多争论,大多数人认为这不是一种实用的方法。无论如何,在这里我假设我们将图像存储在数据库中,并讨论这样做的最佳方法。

【问题讨论】:

将数据保存到文件中,只在数据库中存储文件位置或url @Fredrik 如果决定将数据存储到文件中,为什么要使用 base64 数据?我们可以简单地保存原始图像文件。 我认为您是从 iPhone 或其他设备发送的。然后你不想发送原始数据,而是用 JSON 或其他东西发送 base64 字符串。 问任何人,永远不要将这类数据直接存储在数据库中。常识 @Fredrik 不,我说的是一个网站。即使在这种情况下,最好将base64数据转换为图像BLOB并通过ImageMagick保存为普通图像文件。 【参考方案1】:

我认为图像(文件)通常不存储在 base64 编码的数据库中。相反,它们以原始二进制形式存储在二进制(blob)列或文件中。

Base64 仅用作传输机制,不用于存储。例如,您可以将 base64 编码的图像嵌入到 XML 文档或电子邮件消息中。

Base64 也是流友好的。您可以即时编码和解码(不知道数据的总大小)。

虽然 base64 适合传输,但不要存储您的图像 base64 编码

Base64 不提供校验和或任何具有任何存储价值的东西。

Base64 编码比原始二进制格式增加了 33% 的存储需求。它还增加了必须从持久存储读取的数据量,这通常仍然是计算中的最大瓶颈。读取更少的字节并动态编码它们通常更快。仅当您的系统受 CPU 限制而不是 IO 限制,并且您定期以 base64 输出图像时,才考虑存储在 base64 中。

内联图像(嵌入在 html 中的 base64 编码图像)本身就是一个瓶颈——您通过网络发送的数据要多 33%,并且是连续发送的(网络浏览器必须等待内联图像才能完成)下载页面 HTML)。

如果您仍希望存储 base64 编码的图像,请确保您不将 base64 编码的数据存储在 UTF8 列中,然后对其进行索引。

【讨论】:

很好的说明;但是如果你搜索一下,你会发现很多存储为 base64 的教程和一些二进制存储的教程。 Base64 不提供校验和或任何具有任何存储价值的东西。如果您提供一个链接,并附有一个参数以将其用作存储,我会为您揭穿它。 :) 我不明白这不是公认的答案,将图像存储在为存储图像(如 S3每次运行查询时都必须为数据库中的每个文档检索一个大字符串 您并不总是希望将文件存储在 CDN 上,也许它们在公司内部是私有的......在数据库中存储二进制文件确实有优势,例如为开发人员提供便利......我们存储 blob用于临时缓存二进制 pdf 报告(48 小时),因此数据库存储空间不是问题。这完全取决于用例。没有对错。 文件既可以位于 CDN 上,也可以位于公司的私有内部文件中。例如 CloudFront(因为提到了 S3),允许私有 CDN。【参考方案2】:

Pro base64:您处理的编码表示是一个非常安全的字符串。它既不包含控制字符也不包含引号。后一点有助于防止 SQL 注入尝试。我不认为将值添加到“手动编码”SQL 查询字符串会出现任何问题。

Pro BLOB:数据库管理器软件知道它必须期待什么类型的数据。它可以为此进行优化。如果您将 base64 存储在 TEXT 字段中,它可能会尝试为它构建一些索引或其他数据结构,这对于“真实”文本数据来说非常好和有用,但对于图像数据毫无意义并且浪费时间和空间。它是较小的,如字节数,表示形式。

【讨论】:

非常有用的比较。我的担心主要是关于安全性。我不确定保存二进制文件是否会为 SQL 注入打开任何安全漏洞。 这应该取决于对数据库数据的“正确”和“安全”处理。由于我不熟悉 php,你似乎使用什么,我不能给你提示。在 java 中,我使用的工具(Hibernate / JPA)为我解决了这个问题。 :) 转义输入可以防止 SQL 注入攻击,而不是存储机制。我承认我从来不需要在查询中手动输入图像。 “安全字符串”参数可能是使用 base64 进行传输而不是存储的原因。 图像不应该直接存储在数据库 imo 中。最好使用为存储此类文件(如 Amazon S3)而优化的数据库/服务,它可以提供自己的 CDN 和缓存。这样,您就不必担心每次执行查询时都会通过检索如此长的字符串来降低数据库性能或担心数据库的存储/内存【参考方案3】:

只想举一个例子,为什么我们决定将图像存储在 DB 中而不是文件或 CDN 中,它是存储签名的图像。

我们尝试通过 CDN、云存储、文件来实现这一点,最终决定将其存储在数据库中,并对这一决定感到高兴,因为当我们移动、升级脚本和迁移站点时,我们在随后的活动中证明了这一点是正确的几次。

就我而言,我们希望签名与属于文档作者的记录一起使用。

以文件格式存储可能会丢失或意外删除。

我们在 MySQL 中将其存储为 blob 二进制格式,然后在文本字段中存储为 based64 编码图像。更改为 based64 的决定是由于某种原因导致尺寸更小,加载速度更快。由于某种原因,Blob 正在减慢页面加载速度。

在我们的案例中,这种将签名图像存储在 DB 中的解决方案(无论是 blob 还是 based64)由以下驱动:

    大多数签名图片都非常小。 我们不需要索引存储在 DB 中的签名图像。 索引是在主键上完成的。 我们可能要移动或切换服务器,将物理图像文件移动到不同的服务器,可能会导致由于链接更改而找不到图像。 不好意思要求作者重新签名。 与将其公开为可在安全性受到威胁时下载的文件相比,将其保存在数据库中更为安全。存储在 DB 中可以让我们更好地控制其访问。 任何未来的迁移、网页设计、托管、服务器的更改,我们都无需担心将签名文件名与物理文件进行协调,这一切都在数据库中!

交流

【讨论】:

【参考方案4】:

我建议查看 NoSQL 等现代数据库,并且我同意 user1252434 的帖子。例如,我将一些 storing large objects and files in mongodb。

【讨论】:

从我在 bson 规范中看到的内容来看,MongoDb 然后将字节数组存储为不是 base64 编码的,而是作为原始字节,以它们的长度为前缀。

以上是关于将图像直接存储在数据库中还是作为base64数据存储?的主要内容,如果未能解决你的问题,请参考以下文章

angularJS 从 base64 制作二进制数据图像并作为图像文件发送到服务器

如何将存储在数据库中的 Base64 字符串集合转换为普通图像存储在本地目录中

MySQL - Base64 vs BLOB

使用 Thymeleaf 显示 Base64String 图像

使用 Firebase 存储上传 base64 图像

MySQL - Base64 与 BLOB