图片怎么存储到数据库里「建议收藏」

我们存储图片到数据库里一般有两种方式将图片保存的路径存储到数据库(文件路径或者ftp路径)将图片以二进制数据流的形式直接写入数据库字段中(base64)FTP:FTP服务器(FileTransferProtocolServer)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务。FTP是FileTransferProtocol(文件传输协议)。顾名思义,就是专门用来传输文件的协议。简单地说,支持FTP协议的服务器就是FTP服务器。关于图片或者文件在数据库.

大家好,又见面了,我是你们的朋友全栈君。

存储图片到数据库里一般有两种方式

  • 将图片保存的路径存储到数据库(文件存放在服务器的路径或者ftp服务器的路径)
  • 将图片以二进制数据流的形式直接写入数据库字段中(base64的形式),base64

图片在数据库的存储用途一般为

  • 用户上传的头像,文章插图,文章首页图片等等
  • 其他方面的图片

一般存储图片有两种做法:

  1. 把图片直接以二进制形式存储在数据库中,一般数据库提供一个二进制字段来存储二进制数据。比如mysql中有个blob字段。oracle数据库中是blob或bfile类型
  2. 图片存储在磁盘上(服务器上),数据库字段中保存的是图片在服务器上存储的路径。

将图片转换成二进制存储:

大体思路:

  1. 将读取到的图片用自己的程序转化成二进制形式。(一般会有内置函数,可以快速转出为base64格式),Nodejs的话可以这样转化
  2. 再结合insert into语句插入数据表中的blob类型字段中去。
  3. 从数据库取出图片展示的时候。则是直接发送图片内容
  4. 然后前端接收到二进制,展示到需要的位置即可

总结:处理代码不是很麻烦,使用nodejs很容易就可以处理。但是,我们用得更多的是存储图片的路径,实际图片是在磁盘上保存的(图片二进制放到数据库,把数据库的负担弄重了)。需要代码的话,可以看我nodejs里面对图片的处理。

互联网环境中,大访问量,数据库速度和性能方面很重要。一般在数据库存储图片的做法比较少,更多的是将图片路径存储在数据库中,展示图片的时候只需要连接磁盘路径把图片载入进来即可。因为图片是属于大字段。一张图片要占用1M甚至几十M,所以使用数据库很浪费资源,但是如果图片量很小的情况下可以尝试,或者直接在后台开辟空间存储文件(这样也给服务器造成了不小的压力),所以最好还是使用第三方文件上传平台,像七牛云,阿里云,腾讯云等等(坐等打钱)。

牵扯到一些基本的数据库调优,比如这篇文章分为标题、作者、添加时间、更新时间、文章内容、文章关键字等等。

文章内容一般是比较长的。经常使用text字段去存储。文章的内容就属于大字段。一般文章内容可以拆分到单独一个表中去。不要与文章信息存储在一张表里面。

个人的理解:mysql中一张表的数据是全部在一个数据文件中的。如果大字段的数据也存储在里面。程序展示列表,比如文章列表。这个时候根本不需要展示文章内容的。但是仍然会影响速度,数据库查找数据其实就是扫描那个数据文件,文件容量越小,速度就会越快(为什么单表的容量在1g-2g的时候基本上要分表了)。拆分出去到一张单独的表,就是单独的文件了。举一反三,相互独立,分离的思想不仅在系统开发中用到,在现实生活中经常存在的。

总结:三种东西永远不要放到数据库里,图片,文件,二进制数据。

原因

  • 对数据库的读/写的速度永远都赶不上文件系统处理的速度
  • 数据库备份变的巨大,越来越耗时间
  • 对文件的访问需要穿越你的应用层和数据库层
  • 把图片缩略图存到数据库里?很好,那你就不能使用nginx或其它类型的轻量级服务器来处理它们了。

关于mysql中的blob类型

bolb(binary large object)二进制大对像就像int型那样,分为blobMEDIUMBLOBLONGBLOB。其实就是从小到大

  • blob 容量为64KB
  • MEDIUMBLOB 容量为16M
  • LONGBLOB 容量为4G。

说实话,图片用这样子存储用得还真少。使用java的序列化函数进行序列化的值,有人存入这个字段中去。

mysql中blob字段存储图片有个通信大小的设置:

图片要传输给mysql存储起来,那么需要涉及到数据通信。mysql中有个配置是限制通信数据大小的。

my.conf配置文件中的max_allowed_packet,mysql默认的值是1M。

好多图片尤其是原始图可能不止1m。传输的数据(也就是图片)超过这个设置大小。结果就会出错

其实所谓的性能,最关键是数据库性能。因为随着数据库数据量增大,大部分时间耗费是在php,java等语言等待数据库返回数据的过程中耗费时间。

网站访问量大了后,具体的语言不是瓶颈,瓶颈都在数据库。用c,python,php,java 都能操作mysql数据库获取数据。语言之间可能存在速度执行差异,但是其实这种差别已经很小了。至少我觉得,给予用户感觉不到明显。执行相差0.0001秒用户感觉并没有明显的区别。可能说,大并发(很多用户同时访问)的时候,就会体现到差别了。其实我觉得,大并发访问是数据库瓶颈。等待数据库给予数据。没达到一定级别实在体现不了差别。数据库数据量达到一定级别。语言相差0.001s会给予用户体验上的差别。所以,这也是为什么php很适合做web开发了。解析页面速度快(解释型语言,不需要编译)。可以用java来与数据库打交道获取数据。php不直接操作数据库,而是调用java提供的数据接口,获取数据,马上展示在页面中。这是利用了php的页面执行速度快的一个优势。

二、数据库中保存图片路径

一般是这样子的:

按照年月日生成路径。具体是按照年月日还是按照年月去生成路径,根据自己需要(不一定是按照日期去生成)。

理解为什么要分散到多个文件夹中去才是关键,涉及到一个原理就明白了:

  1. 操作系统对单个目录的文件数量是有限制的。当文件数量很多的时候。从目录中获取文件的速度就会越来越慢。所以为了保持速度,才要按照固定规则去分散到多个目录中去。
  2. 图片分散到磁盘路径中去。数据库字段中保存的是类似于这样子的”images/2012/09/25/ 1343287394783.jpg”
  3. 原来上传的图片文件名称会重新命名保存,比如按照时间戳来生成,1343287394783. jpg。这样子是为了避免文件名重复,多个人往同一个目录上传图片的时候会出现。
  4. 反正用什么样的规则命名图片,只要做到图片名称的唯一性即可。
  5. 比如网站的并发访问量大,目录的生成分得月细越好。比如精确到小时,一个小时都可以是一个文件夹。同时0.001秒有两个用户同时在上传图片(因为那么就会往同一个小时文件夹里面存图片)。因为时间戳是精确到秒的。为了做到图片名称唯一性而不至于覆盖,生成可以在在时间戳后面继续加毫秒微秒等。总结的规律是,并发访问量越大。就越精确就好了。

有个方面总结一下:为什么保存的磁盘路径,是”images/2012/09/25/1343287394783.jpg”,而不是” /images/2012/09/25/ 1343287394783.jpg”(最前面带有斜杠)?

  1. 连那个斜杠都不要。这里也是做到方便以后系统扩展。
  2. 在页面中需要取出图片路径展示图片的时候,如果是相对路径,则可以使用”./”+”images/2012/09/25/1343287394783.jpg”进行组装。
  3. 如果需要单独的域名(比如做cdn加速的时候)域名,img1.xxx.com,img2.xxx.com这样的域名
  4. 直接组装 “http://img1.xxx.com/”+”images/2012/09/25/1343287394783.jpg”
  5. 当然数据库是可以在前面加斜杠/保存起来,/images/2012/09/25/ 1343287394783.jpg
  6. 其实不方便统一。比如相对路径载入图片的时候,则是”.”+” /images/2012/09/25/ 1343287394783.jpg”
  7. 可能我还没体会到坏处,以后会遇到问题的。不过,遵循惯例不加斜杠” images/2012/09/25/ 1343287394783.jpg”就对了。

涉及到一个新问题:为什么大部分系统都不会域名保存进去,像这样子http://www.xxx.com/images/2012/09/25/1343287394783.jpg保存到数据库中

  1. 了解的知识越多,越有利于我们做决定。可能就是一个”感觉区别不是很大”的影响下,去做一个决定,反而对后面是比较大的影响的。至少是增加自己的工作量了。
  2. 其实把域名保存进去,也不是什么滔天大罪的事情。但凡是经验丰富的开发人员都不会这样子做。这是一个经验积累出来的,所以上海那个网友也对此并没有明显的概念很正常,他说他不知道cdn方面的(当然觉得存个域名进去没什么大不了的)。需要了解cdn知识,什么情况下会用到cdn知识。
  3. 虽然是做开发人员,不需要关注运维和服务器之类的知识。不过了解一些就有利于理解了。
  4. 这里涉及到cdn加速。关于cdn原理(就是内容分发网络),我理解其本质就是为了解决距离远产生的速度问题,使用就近的服务。

CDN

  1. 从中国请求美国一台服务器上的图片。一般比较慢,因为距离这么远,网络传输是存在损耗的,距离越远,传输的时间就越长。一般会看到浏览器左下角显示:“已响应,正在传输数据…”。这不是服务器本身问题了。实际上服务器早就响应请求,把数据发给客户端,但是网络问题,就一直在传输,没传完了。
  2. 在中国,是南北距离远的问题。南北还会涉及到跨网,南方用户使用电信居多,北方用户网通居多。两个线路需要跨越,会有时间延迟。
  3. cdn加速就是适应这个需求产生的:现在不请求美国的服务器。直接在中国安放节点(节点是比较笼统的词语,可以理解成一台服务器,也可以理解成一个机房,就是一个点嘛),请求距离近的节点。这样子就不需要那么远的距离了。

以前在长沙的网站,团购以城市分站的形式。北京和长沙用的是同一套程序。服务器在长沙。北京用户访问北京站的时候,实际上需要远距离访问长沙的服务器。速度怎么都快不起来。跟服务器性能完全没关系。当时不懂这些。不清楚怎么折腾。就想办法去做js代码压缩,浏览器缓存之类的。实际上瞎折腾。不是说这些前端优化不重要,哲学上有主次矛盾之分,瓶颈在哪里就去突破哪里。没解决主要矛盾,问题并不会迎刃而解。当时也不是数据库瓶颈。如果去优化数据库。也不会明显改善。就那点数据量。根本就达不到瓶颈。哪里谈得上主要矛盾。随着后来去其他公司工作,接触一些东西,类似不找瓶颈的优化例子发生在身边好几次了,先没找到瓶颈就瞎去优化。我的同事可能是抱着多多益善的心态去做的,但主要矛盾(技术上说是瓶颈)没找到,也没改善。

当时如果没想到是距离问题。也就不会想到cdn,当时其实我根本不知道cdn服务。我只知道,google这些网站肯定在中国部署的服务器,要不然,中国用户还去访问美国的服务器,那再好的服务器都会速度慢的。

由于自己搭建cdn环境和机房的资金比较大(需要大量的服务器),也需要人力维护。反正一般的公司弄不起,其实根本不划算。淘宝以前用商用的cdn服务,后来商用的扛不住了,就搭建了自己的cdn网。我不知道新浪有没有自己搭建,但其实我觉得跟淘宝的特点有关,店铺很多,无论是商品还是交易记录总计起来商品很多的图片,图片都是静态的部分,cdn本来就是用来做静态的(图片,css,js等)请求分发用的。

之前在网上看到一句话,cdn网络不是一般的公司玩得起的。

一般的公司自己搭建cdn网络成本高,所以就有商业的cdn提供付费租用服务,这是一项很成熟的业务,很多这样的公司,大部分全国性的互联网公司都会使用到cdn。

总结:cdn服务。对于静态内容是非常适合的。所以像商品图片,随着访问量大了后,租用cdn服务,只需要把图片上传到他们的服务器上去。

例子:北京访问长沙服务器,距离太远。我们完全可以把商品图片,放到北京的云服务(我们觉得现在提供给网站使用的云存储其实就是cdn,给网站提供分流和就近访问)上去。这样子北京用户访问的时候,实际上图片就是就近获取。不需要很长距离的传输。

自己用一个域名img.xxx.com来载入图片。这个域名解析到北京的云服务上去。

做法:数据库中保存的是” images/2012/09/25/1343287394783.jpg”,

这些图片实际上不存储在web服务器上。上传到北京的cdn服务器上去。

我从数据库取出来,直接”img.xxx.com/”+” images/2012/09/25/1343287394783.jpg”

比如如果还有多个,就命名img1.xx.com、img2.xx.com

反正可以随便。所以如果把域名直接保存进去。就显得很麻烦了。迁移麻烦。

像淘宝,凡客,亚马逊这些电子商务网站,我们看到请求的时候,下面往往会有

img1.xxx.cdn.com

img2.xxx.cdn.com

其实他们保存在数据库中的是相对路径。有些是不需要在数据库保存的,缩略图可以实时访问的时候用程序生成(节省很多存储空间)

实际上,把域名保存在数据库中,非常不利于系统迁移。一旦换个域名的话,原来保存在数据库中的是“www.abc.om/images/xxxxxx“,因为路径都在数据库中写死了。下回换个域名就用不了了。那个时候自己去写sql语句批量更新字段吧。

几个术语:

  • ICP(Internet Content Provider),也就是网络内容提供者。联想到我们运营一个网站需要icp备案了吗?你自己运营网站,你就是icp服务商
  • IDC(Internet Data Center),互联网数据中心。IDC的概念,目前还没有一个统一的标准。通俗点,就是提供机房托管(服务器租用和托管),域名注册之类的。

关于淘宝的图片存储

了解到:淘宝以前使用了商用的存储。但是没法满足需求。据说,到2010年,淘宝网后端保存着286亿张图片。商用的系统系统没法满足需求的时候。他们就自己开发了一个tfs(Taobao File System)。大规模的小文件在磁盘上读取,需要磁盘磁头频繁的寻道和换道。大并发情况下和大量的操作确实很麻烦。其实借鉴了当时google公布的gfs(Google File System)设计论文。google有相册服务。为每个用户提供上传图片存储。

有个观点比较好:对于老板们而言,往往觉得,用钱能解决的都不算问题。但问题在于,你遇到的问题,别人都没遇到过。那这个时候你就没有经验可以参考或者直接拿来使用。只有自己参考一些思路去创造技术了。

三、关于图片进行云存储(cdn加速)

曾经看过这个,这个是比较适合创业公司的。价格相对便宜https://www.upyun.com/

其实,现在的云存储本质就是一个cdn服务商。你把静态的图片上传到他提供的服务器上去(ftp方式上传或者api形式编写程序上传)。他为你做就近节点访问。

计费方式:按照流量付费,99元购买100g。怎么算流量。每次访问文件的大小累加,比如一个1m的文件,访问一次流量就加1m。

我个人理解,对于图片的量不大的情况下,使用这种云服务,好处不是节省存储空间。你自己的服务器100g的空间可能创业型公司都没用完,不是什么存储空间不够用,然后去用云存储。以前我对cdn比较模糊,有这么点理解,或者以为是分散网站web服务器流压力,服务器分流。这些好处是有的。但是,只要理解了cdn产生的背景和解决的关键问题后,就会明白云存储关键好处在于:给用户就近节点访问,加速。

我觉得,如果不是出于这个考虑,或者达不到这样的目的。用其他方案也完全可以替代。何必使用云存储呢?就是你无非有实力做到全国多个节点去部署服务,才需要租用cdn来帮你,毕竟他们是规模产生的效益,专注于解决这个领域。

使用腾讯云、阿里云、华为云不香吗?

下面是具体存储方法代码:

  一、保存图片的上传路径到数据库:
  string uppath="";//用于保存图片上传路径
  //获取上传图片的文件名
  string fileFullname = this.FileUpload1.FileName;
  //获取图片上传的时间,以时间作为图片的名字可以防止图片重名
  string dataName = DateTime.Now.ToString("yyyyMMddhhmmss");
  //获取图片的文件名(不含扩展名)
  string fileName = fileFullname.Substring(fileFullname.LastIndexOf("\\") + 1);
  //获取图片扩展名
  string type = fileFullname.Substring(fileFullname.LastIndexOf(".") + 1);
  //判断是否为要求的格式
  if (type == "bmp" || type == "jpg" || type == "jpeg" || type == "gif" || type == "JPG" || type == "JPEG" || type == "BMP" || type == "GIF")
  { 

   //将图片上传到指定路径的文件夹
   this.FileUpload1.SaveAs(Server.MapPath("~/upload") + "\\" + dataName + "." + type);
   //将路径保存到变量,将该变量的值保存到数据库相应字段即可
   uppath = "~/upload/" + dataName + "." + type;
  }
  二、将图片以二进制数据流直接保存到数据库:
  引用如下命名空间:
  using System.Drawing;
  using System.IO;
  using System.Data.SqlClient;
  设计数据库时,表中相应的字段类型为iamge
  保存:
  //图片路径
  string strPath = this.FileUpload1.PostedFile.FileName.ToString ();
  //读取图片
  FileStream fs = new System.IO.FileStream(strPath, FileMode.Open, FileAccess.Read);
  BinaryReader br = new BinaryReader(fs);
  byte[] photo = br.ReadBytes((int)fs.Length);
  br.Close();
  fs.Close();
  //存入
  SqlConnection myConn = new SqlConnection("Data Source=.;Initial Catalog=stumanage;User ID=sa;Password=123");
  string strComm = " INSERT INTO stuInfo(stuid,stuimage) VALUES(107,@photoBinary )";//操作数据库语句根据需要修改
  SqlCommand myComm = new SqlCommand(strComm, myConn);
  myComm.Parameters.Add("@photoBinary", SqlDbType.Binary, photo.Length);
  myComm.Parameters["@photoBinary"].Value = photo;
  myConn.Open();
  if (myComm.ExecuteNonQuery() > 0)
  { 

   this.Label1.Text = "ok";
  }
  myConn.Close();
  读取:
  ...连接数据库字符串省略
  mycon.Open();
  SqlCommand command = new
  SqlCommand("select stuimage from stuInfo where stuid=107", mycon);//查询语句根据需要修改
  byte[] image = (byte[])command.ExecuteScalar ();
  //指定从数据库读取出来的图片的保存路径及名字
  string strPath = "~/Upload/zhangsan.JPG";
  string strPhotoPath = Server.MapPath(strPath);
  //按上面的路径与名字保存图片文件
  BinaryWriter bw = new BinaryWriter(File.Open(strPhotoPath,FileMode.OpenOrCreate));
  bw.Write(image);
  bw.Close();
  //显示图片
  this.Image1.ImageUrl = strPath;
  采用这两种方式可以根据实际需求灵活选择。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/127839.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • java图书馆新地址_最受Java开发者喜爱的5款开源IDE盘点

    java图书馆新地址_最受Java开发者喜爱的5款开源IDE盘点开源最前线(ID:OpenSourceTop)猿妹编译项目地址:https://opensource.com/article/20/7/ide-java在TIOBE编程语言排行中,Java始终排在前三名,现今有700万到1000万的Java开发人员。许多应用程序的所有代码都是用Java编写的,这意味着集成开发环境(IDE)很重要,因为它是开发人员编写、测试和运行Java程序必备的工具…

  • Linux内核有没有rootfs,Linux内核rootfs的初始化过程[通俗易懂]

    Linux内核有没有rootfs,Linux内核rootfs的初始化过程[通俗易懂]由于在下水平相当有限,不当之处,还望大家批评指正^_^在Linuxshell中执行mount命令,通常可以看到某个做了文件系统的磁盘分区或flash分区或内存文件系统做为所谓的根文件系统被mount到了挂载点/处。实际上内核中最初始的根文件系统,并不是来自内核外部,他是由内核自己构建出来的。为了说明这个过程,我们先说说mount的过程。系统调用sys_mount是在fs/namespace.c…

  • JRTPLIB_刘伯温传简介

    JRTPLIB_刘伯温传简介jrtplib是一个基于C++、面向对象的RTP封装库,最新的版本是3.9.1(2011年11月)。为了与RFC3550相兼容,3.x.x版本经过完全重写,现在它提供了一些非常有用的组件,这些组件为构建各种各样的RTP应用程序开发提供了有用的帮助。较旧的2.x版本依然可用,但是不兼容RFC3550。1.特性    jrtplib支持定义于RFC3550中的RTP协议,它使得发送和接

  • springboot——kaptcha

    springboot——kaptcha导入包: <dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>配置类:p…

  • vscode配置php开发环境_vscode搭建c语言环境

    vscode配置php开发环境_vscode搭建c语言环境提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、准备工作?二、安装phpstudy和vscode1.进入官网,下载相应的版本2.读入数据总结前言搭建php开发环境需要下载vscode和phpstudy,本教程为以Windows64bit为例一、准备工作?首先下载vscode和phpstudyvscode下载地址phpstudy下载地址二、安装phpstudy和vscode1.进入官网,下载相应的版本vscodewindwos版本提供两种安装方式

  • notepad复制列[通俗易懂]

    notepad复制列[通俗易懂]notepad复制列

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号