精华内容
下载资源
问答
  • 但也有很多认为像图片这样的数据存放在数据库中也有好处:易于备份,且备份速度绝对比备份文件快,比较容易数据迁移等等。其实这两种方法都有优缺点,具体使用哪种方法要视情况而定。个人倾向于使用数据库存取图片...
  • 图片怎么存储到数据库

    千次阅读 多人点赞 2020-12-24 12:07:26
    我们存储图片数据库里一般有两种方式 将图片保存的路径存储到数据库(文件路径或者ftp路径) 将图片以二进制数据流的形式直接写入数据库字段中(base64) FTP:FTP服务器(File Transfer Protocol Server)...

    在这里插入图片描述

    FTP:FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务。 FTP是File Transfer Protocol(文件传输协议)。顾名思义,就是专门用来传输文件的协议。简单地说,支持FTP协议的服务器就是FTP服务器。

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

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

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

    • 商品图片,用户上传的头像
    • 其他方面的图片

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

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

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

    大体思路:

    1. 将读取到的图片用自己的程序转化成二进制形式。(一般会有内置函数,可以快速转出base64格式)
    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。大规模的小文件在磁盘上读取,需要磁盘磁头频繁的寻道和换道。大并发情况下和大量的操作确实很麻烦。其实借鉴了当时google公布的gfs设计论文。google有相册服务。为每个用户提供上传图片存储。

    估计,google是率先实现这种小文件网络存储系统的。

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

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

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

    介绍提到,我们在全国各地部署了55个CDN节点,500多台服务器,电信,联通,移动和教育网的4线带宽。

    其实,现在的云存储本质就是一个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;
      采用这两种方式可以根据实际需求灵活选择。
    
    展开全文
  • ssh图片数据库,简单版 想把图片存进数据库不知从何下手的,把这个下下来改改就OK了
  • 复习到数据库中数据的不一致性,简单记录一下。 本文的例子来源于数据库系统概论第五版(王珊、萨师煊著)。 1. 例子 首先看一个简单的例子: 考虑飞机订票系统的一个活动序列: (1)甲售票点(事务T1)读出某航班...

    最近在复习准备找工作。复习到数据库中数据的不一致性,简单记录一下。
    本文的例子来源于数据库系统概论第五版(王珊、萨师煊著)。

    1. 例子

    首先看一个简单的例子:
    考虑飞机订票系统的一个活动序列:
    (1)甲售票点(事务T1)读出某航班的机票余额A,设A=16.
    (2)乙售票点(事务T2)读出同一航班的机票余额A,也为16.
    (3)甲售票点卖出一张机票,修改余额A←A-1.所以A为15,把A写回数据库.
    (4)乙售票点也卖出一张机票,修改余额A←A-1.所以A为15,把A写回数据库.
    结果明明卖出两张机票,数据库中机票余额只减少1。
    这种情况称为数据库的不一致性。这种不一致性是由事务的并发操作引起的。在并发的操作情况下,如果没有任何的并发控制机制,对事务T1、T2的两个事务的操作序列的调度是随机的。若按照上面的调度序列执行,T1事务的修改就被丢失了(丢失可以理解成为失效)。这是由于第4步中T2事务对A进行修改了,并且写回数据库覆盖了T1事务做出的修改。
    并发操作带来的数据不一致性包括丢失修改、不可重复读和读“脏”数据。
    课本原文中并没有提到虚读(也有人称为幻读)。

    1.1 丢失修改

    两个事务T1和T2读入同一数据并修改,T2提交的结果破坏了T1提交的结果,导致了T1的修改失效了。飞机订票的例子就属于此类。

    1.2 脏读

    读"脏"数据是指当事务T1修改某一数据时,事务T2读取同一数据后,T1由于某种原因撤销修改了,这时T1已修改过的数据恢复原值,而T2读到的数据是撤销修改之前的数据,那么此时T2的数据就与数据库中的数据不一致,则T2读到的数据就为"脏"数据,即不正确的数据。

    1.3 不可重复读

    不可重复读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次读取结果。具体的,不可重复读包括三种情况:
    (1)事务T1读取某一数据后,事务T2对其做了修改,当事务1再次读该数据时,得到与前一次不同的值。例如,T1读取B=100进行运算,T2读取同一数据B,对其进行修改后将B=200写回数据库。T1为了对读取值校对重读B,B已为200,与第一次读取值不一致。
    (2)事务T1按一定条件从数据库中读取了某些数据记录后,事务T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录神密地消失了。
    (2)事务T1按一定条件从数据库中读取某些数据记录后,事务T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。

    1.4 虚读

    事务A首先根据条件索引得到N条数据,然后事务B在N条之外删除或者增加了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了虚读。虚读貌似是MySql中的概念?
    这么看的话,虚读不就是不可重复读中的第二、三种情况吗???

    2. 数据库的隔离级别

    产生上述四类数据不一致性的主要原因是并发操作破坏了事务的隔离性。并发控制就是要用正确的方式调度并发操作,使一个用户事务的执行不受其它事务的干扰,从而避免造成数据的不一致性。
    有了以上的数据不一致性,那么数据库肯定要有相应的处理事务并行办法。
    数据库的隔离级别越高,越能解决更多的数据不一致性问题。但是也是要牺牲的性能也逐渐递增。
    以下事务隔离级别逐渐增加。

    2.1 不支持事务

    这种通常不讨论。

    2.2 未提交读

    顾名思义,就是在事务A未提交的时候,事务B可以进行读写。这种级别下,数据库会出现丢失修改、不可重复读、脏读和虚读等数据不一致性问题。

    2.3 已提交读

    顾名思义,就是只有在事务A已经提交的时候,事务B才可以进行读写。这种级别下,数据库不会出现在事务A执行过程中,B去读写的情况,那么B也不会出现脏读了。所以此级别可以避免脏读,但是不能避免可重复读以及虚读。

    2.4 可重复读

    顾名思义,这种级别可以避免不可重复读,也能避免脏读。但不能避免虚读。

    2.5 可序列化

    最高隔离级别。可以避免所有的数据不一致性问题。
    个人理解:事务的隔离级别本质其实是底层使用了不同的封锁协议。因为封锁是实现并发控制的一个非常重要的技术。
    在这里插入图片描述
    图片来源于:https://blog.csdn.net/u013474436/article/details/53437220
    补充:
    基本的封锁类型有两种:排它锁(又称为X锁或者写锁)和共享锁(又称为S锁或者读锁)。
    读锁之间可以共享,写锁既不能共享写锁也不能共享读锁。

    展开全文
  • Java web实现图片上传服务器、同步保存数据库以及如何在前端页面展示教程一、上传二、后端代码处理三、数据库读取图片在前端页面展示(重点) 大概流程: 1.上传插件的选择:此篇博文选择的是jQuery的zyupload文件...

    Java web实现图片上传服务器、同步保存数据库以及如何在前端页面展示教程


    大概流程:
    1.上传插件的选择:此篇博文选择的是jQuery的zyupload文件上传插件;
    2.上传请求发起后,java代码的处理:你是要将上传的图片只保存在服务器还是只保存在数据库还是说两者都采取。上传到服务器很简单,保存到数据库也很简单,但是此处需要考虑业务,图片保存在数据库时采用哪种保存方式(本博文业务来自于项目,因为图片数量巨多,故在数据库是通过保存图片的路径实现的,并非二进制流);
    3.图片保存在数据库后,在前段页面的回显功能。

    一、上传

    目前上传图片的插件很多,我在做这个需求的时候也用到了好几款图片上传插件,没有一个完美的插件,多多少少都有问题,必要的时候需要改作者的源码。我选择的是zyupload插件。下面说说使用教程。
    1.点击此处下载zyupload,网上也有一大堆,大家可以随便去找都可以。
    2.使用方法:
    下载插件压缩包后,解压。把css文件zyupload-1.0.0.css和js文件zyupload-1.0.0.js以及图标文件夹images引入到你的项目,images文件夹跟zyupload.css文件在同一个目录下。如图:
    在这里插入图片描述
    3.创建一个上传组件对象:

    <input type="button"onclick="javascrtpt:window.location.href='<%=path%>/uploadPhotoIndex'" value="上传照片">
    

    这行代码就是创建了一个按钮,点击后打开上传图片的页面。因为我用的是SSM加shiro框架,所有页面都是在Controller中统一处理的,(我的处理代码如下)这里显得有点啰嗦,大家可以直接转xxx.jsp就可以了。

    	/**
    	 * 上传图片主页
    	 */
    	@RequestMapping(value = "/uploadPhotoIndex")
    	public String uploadPhotoIndex() {
    		return "bs/uploadPhoto";
    	}
    

    4.上传页面代码:

    <%@ page language="java" contentType="text/html; charset=utf-8"
    	pageEncoding="utf-8"%>
    <%
    	String path = request.getContextPath();
    %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="multipart/form-data; charset=utf-8">
    <title>Insert title here</title>
    <link rel="stylesheet" type="text/css"href="<%=path%>/css/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="<%=path%>/css/zyupload-1.0.0.css" />
    <script type="text/javascript" src="<%=path%>/js/jquery-3.1.1.min.js"></script>
    <script type="text/javascript" src="<%=path%>/js/zyupload-1.0.0.js"></script>
    </head>
    <body>
    	<div id="demo" class="demo"></div>
    </body>
    <script type="text/javascript">
    	var path='<%=path%>';
    	$(function(){
    		// 初始化插件
    		$("#demo").zyUpload({
    			width            :   "100%",                 // 宽度
    			height           :   "400px",                 // 宽度
    			itemWidth        :   "150px",                 // 文件项的宽度
    			itemHeight       :   "210px",                 // 文件项的高度
    			url              :  path+"/test/uploadPhoto",  // 上传文件的路径
    			fileType         :   ["jpg","png","PNG","JPG"],// 上传文件的类型
    			multiple         :   true,                    // 是否可以多个文件上传
    			dragDrop         :   true,                    // 是否可以拖动上传文件
    			del              :   true,                    // 是否可以删除文件
    			finishDel        :   false,  				  // 是否在上传文件完成后删除预览
    			/* 外部获得的回调接口 */
    			onSelect: function(files, allFiles){                    // 选择文件的回调方法
    				console.info("当前选择了以下文件:");
    				console.info(files);
    				console.info("之前没上传的文件:");
    				console.info(allFiles);
    			},
    			onDelete: function(file, surplusFiles){                     // 删除一个文件的回调方法
    				console.info("当前删除了此文件:");
    				console.info(file);
    				console.info("当前剩余的文件:");
    				console.info(surplusFiles);
    			},
    			onSuccess: function(file,response){                    // 文件上传成功的回调方法
    				console.info("此文件上传成功:");
    				console.info(file);
    			},
    			onFailure: function(file){                    // 文件上传失败的回调方法
    				console.info("此文件上传失败:");
    				console.info(file);
    			},
    			onComplete: function(responseInfo){           // 上传完成的回调方法
    				console.info("文件上传完成");
    				console.info(responseInfo);
    				myConfirm('提示', '所有照片上传成功!是否将已上传的照片更新到数据库?', insertPhoto, function(){});
    			}
    		});
    	});
    	function insertPhoto(){
    		$.ajax({
    			type : 'post',
    			contentType : 'application/json',
    			url : path + '/test/insertPhoto',
    			processData : false,
    			dataType : 'json',
    			data : JSON.stringify({}),
    			success : function(data) {
    				if (data.requestResult.success) {
    					myAlert("提示", data.requestResult.successMsg);
    				} else {
    					myAlert("提示", data.requestResult.errorMsg);
    				}
    			},
    			error : function() {
    				myAlert("警告", "请求失败");
    			}
    		});
    	}
    </script>
    </html>
    

    body里面就一句,创建一个实例对象就可以,然后通过$("#demo").zyUpload({})去初始化它。下面的五个方法特别重要,可以借用来扩展你的业务。我是在图片全部上传到服务器后调用了onComplete: function(responseInfo){}这个方法,去询问是否将上传的图片更新到数据库,为什么这么做,因为保存图片到数据库的时候如果throw异常不好处理,可能后端保存失败了,但是前端提示成功了,或者压根就不提示。为了方便处理异常,我还是选择了通过ajax去保存图片路径到数据库。
    5.前端上传效果:
    创建一个上传按钮
    上传页面
    在这里插入图片描述

    二、后端代码处理

    1.先贴上传到服务器代码:

    	@RequestMapping(value = "test/uploadPhoto")
    	public String uploadPhoto(@RequestParam("file") MultipartFile[] file, HttpServletRequest request) throws Exception {
    		String firstPath = "E:\\tempPhotos";// 存入数据库的路径前缀
    		for (int i = 0; i < file.length; i++) {// 循环存入文件并组合路径
    			MultipartFile thisfile = file[i];
    			String fileName = thisfile.getOriginalFilename();// 得到文件名称
    			File tempFile = new File(firstPath, fileName);
    			if (fileName != "" && !thisfile.isEmpty()) {
    				if (!tempFile.getParentFile().exists()) {// 检测是否存在目录
    					tempFile.getParentFile().mkdirs();
    				}
    				thisfile.transferTo(tempFile);// 写入文件
    			}
    		}
    		return "bs/uploadPhoto";//上传成功返回上传图片页面。
    	}
    

    2.保存图片到数据库代码:

    	前端通过ajax请求实现插入的,图片上传完成后会调用此请求,上述前段代码已提及,上传和保存分开是为了便于处理异常,ajax实现的异步刷新感觉体验好
    	@RequestMapping(value = "test/insertPhoto")
    	public @ResponseBody Response insertPhoto1()throws Exception {
    		Response response = new Response();//这个是我用来消息处理的工具类。你们可以用自己的替换
    		String temppath = "E:\\tempPhotos";// 临时上传的图片目录
    		String targetpath = "E:\\photos";// 最终备份的图片目录
    		File tempfile = new File(temppath);
    		File targetfile = new File(targetpath);
    		if (!targetfile.getCanonicalFile().exists()) {// 检测是否存在目录
    			targetfile.getCanonicalFile().mkdirs();
    		}
    		String[] fileName = tempfile.list();
    		Photos = null;声明一个图片实体
    		List<Photos> photos = new ArrayList<>();
    		try {
    			for (int i = 0; i < tempfile.list().length; i++) {
    					photos = new Photos();
    					//因为图片命名是编号_姓名的方式,所以这里做了一个处理,
    					int index = fileName[i].indexOf("_");
    					photos .setBh(fileName[i].substring(0, index));
    					//这里是关键,存入图片的路径。比如图片命名是:123_张三.jpg
    					存进去就是  /photos/123_张三   这样的,采用相对路径的办法,实际地址是E:\photos\tempPhotos\123_张三.jpg,关键就在于图片在前端展示的时候有个大坑,稍后会讲到。
    					photos.setPhoto("/photos/" + fileName[i]);
    					photolist.add(photos );
    			}
    				//通过mybatis框架通过list插入图片数据。效率比使用for循环好多了
    				int m = photosService.updatePhotoList(photolist);
    				if (m > 0) {
    					response.getRequestResult().setSuccess(true);
    					response.getRequestResult().setSuccessMsg("照片更新到数据库成功!");
    				}else {
    					response.getRequestResult().setSuccess(false);
    					response.getRequestResult().setErrorMsg("<font color=\"red\">照片更新到数据库失败!<br/>请检查照片名称是否正确或者上传时照片类型是否选对!</font>");
    				}
    		} catch (java.lang.StringIndexOutOfBoundsException e) {
    			response.getRequestResult().setSuccess(false);
    			response.getRequestResult().setErrorMsg("照片更新到数据库失败!<br/>失败原因:照片名称分割时出现字符串下标越界异常!<br/>解决方案:检查上传图片的命名是否符合规范要求!<br/>");
    		}catch (Exception e) {
    			response.getRequestResult().setSuccess(false);
    		response.getRequestResult().setErrorMsg(e.getMessage().substring(e.getMessage().lastIndexOf(":")));
    		}
    		// 插入图片到数据库以后先将临时上传的图片备份(复制整个临时图片文件夹到photos目录下)
    		org.apache.commons.io.FileUtils.copyDirectoryToDirectory(tempfile, targetfile);
    		// 删除临时图片文件夹
    		org.apache.commons.io.FileUtils.deleteDirectory(tempfile);
    		return response;
    

    三、数据库读取图片在前端页面展示(重点)

    1.采用MySQL数据库进行存储,存储图片的方式是通过保存图片的相对路径(非blob),如图:
    在这里插入图片描述
    2.前端绑定:
    既然数据库存储的是路径,那么就直接把图片路经查询出来放到图片标签img里面不就美滋滋了!(这里会打脸,尤其新手)。
    在这里插入图片描述
    前端我用的knockout js,绑定数据就是通过data-bind方式,大家用自己熟悉的就可以。上面一行代码就等同于:
    在这里插入图片描述
    大家看看src="",是不是跟数据库存的值是一样的。但是显示效果是什么样子呢?看下图:
    在这里插入图片描述
    图片找不到?找不到?哪里的问题?原因在于Tomcat服务器只能扫描到项目下的资源,很明显咱们图片上传后存放的真实路径在这里:
    在这里插入图片描述
    这个不是项目的路径,并且咱们用的是相对路径存放的照片在数据库。解决办法就是通过Tomcat添加虚拟路径来解决。看下面:
    1.双击你的Tomcat服务器打开。
    在这里插入图片描述
    2.选择Modules ,再在右上角选择Add External Web Module,出现如图小弹出框。在第一个输入框填入存放图片的物理路径,第二个输入框填映射地址(比如数据库你存放的格式是/photos/abc.png,那么这里就是/photos),为了更清楚解释,请下图看关系:
    在这里插入图片描述
    3.再上一步的操作基础上,还需要一一步操作就可以完成了,打开发布该项目的Tomcat,找到conf下的server.xml打开,在标签内加上一句
    在这里插入图片描述
    到此,一切结束了。
    4.测试结果:一切正常了
    在这里插入图片描述
    5,由于是项目里面的一个功能,所以源码没办法分享,大家要是哪里遇到困难,请留言,一起讨论,或者觉得本文有不足之处,望各路大神指出。感激不尽!

    展开全文
  • 数据库存储图片路径并显示图片

    千次阅读 2016-11-24 23:05:00
    这几天在做图片的上传和显示,上传时保存图片到文件夹中并将其存储路径保存到数据库里,显示时用数据绑定显示 让此图片控件连接上图片所在的路径 之前在网上收集了相关资料,大多数表示这个路径应该是绝对路径...

      这几天在做图片的上传和显示,上传时保存图片到文件夹中并将其存储路径保存到数据库里,显示时用数据绑定显示

    让此图片控件连接上图片所在的路径

    之前在网上收集了相关资料,大多数人表示这个路径应该是绝对路径而不是相对路径,所以一开是存储路径的保存是这样的

    但是运行结果是。。。。

    这里的头像是无法显示的

    后来在学长的帮助下,将存储路径修改为

    这是一个相对路径,VS读取数据中从这个“异次元空间”文件夹里开始寻找(也就是从根目录里开始),下属文件夹里images寻找20161124213555917.jpg是成功的,如果像一开始那样的路径是寻找不到的,所以显示为空白

    下面是正常运行的结果:

    成功!

    下面是上传图片的相关代码

     1 if (upload1.HasFile)//判断控件是否有文件路径
     2                 {
     3                     string filename = upload1.FileName;//取得文件名
     4                     filename = filename.Substring(filename.LastIndexOf(".") + 1);//取得后缀
     5                     if (filename.ToLower() == "jpg" || filename.ToLower() == "gif")//判断类型
     6                     {
     7                         string img = DateTime.Now.ToString("yyyyMMddHHmmssfff") + "." + filename;
     8                         upload1.SaveAs(Server.MapPath("images/") + img);
     9                         string picture = ("images/") + img;
    10                         //传到根目录的images文件夹+重命名的文件名,也可以用原来的图片的名称,自己定。上传成功;
    11                         string sql = "insert into tabUsers values('" + ID + "','" + name + "','" + hspwd + "','" + sex + "','" + year+ "','"+mail+"','" + question1 + "','" + hsanswer + "','" + picture + "')";
    12                         int result2 = Class.Put(sql);
    13                         if (result2 == 1)
    14                             Binddata();
    15                         else if (result2 != 1)
    16                         {
    17                             Response.Write("<script>alert('注册失败!');</script>");
    18                             return;
    19                         }
    20                     }
    21                     else
    22                     {
    23                         Response.Write("<script>alert('图片格式只支持jpg和gif');</script>");
    24                         return;//提示错误
    25                     }
    26                 }
    27                 else
    28                 {
    29                     Response.Write("<script>alert('请选相片!');</script>");
    30                     return;//提示错误
    31                 }              

    注意里面的“

    string picture = ("images/") + img;

    ” ,保存路径

    转载于:https://www.cnblogs.com/wxy990118/p/6099918.html

    展开全文
  • 后来时间紧,就没有再了,实际可以合并为一个。) chooseCharacter....
  • 快速教学mysql数据库,增删

    万次阅读 2016-11-07 22:34:33
    行(col): 每一行用来描述某个/物的具体信息;值(value): 行的具体信息, 每个值必须与该列的数据类型相同;键(key): 表中用来识别某个特定的\物的方法, 键的值在当前列中具有唯一性。 MySQL脚本的基本组成 与常规...
  • 小程序云开发更新数据库,用云函数实现一个点赞的功能,完整代码付效果图。 首先,要创建一个云函数。如图: 云函数说明:这是一个点赞的云函数的实现代码,他接收两个参数(id,redu),分别是唯一标识id,和...
  • 使用IDEA对mysql数据库进行简单增删查操作

    万次阅读 多人点赞 2019-06-26 18:27:07
    这里有其他分享的链接: link. 图片: 2、打开IDEA,打开Project Structure(在File中),点击Modules, 点击右侧的+号选第一个jars of directories,找到你刚刚解压缩的位置,选中文件mysql-c...
  • matlab人脸识别论文

    万次阅读 多人点赞 2019-10-11 17:41:51
    这个过程是一对多或者一对一的匹配过程,前者是确定输入图像为图象库中的哪一个(即人脸识别),后者是验证输入图像的的身份是否属实(人脸验证). 以上两个环节的独立性很强。在许多特定场合下人脸的检测与定位...
  • Linux运维工程师学习成长路线

    万次阅读 多人点赞 2019-12-14 20:52:46
    2、测试岗位,找码农写的bug,然后让码农好后上线。 3、 运维岗位 ,需要搭建好线上服务环境及架构,并保证代码无误上线,及线上业务正常能够用户访问。 开发-测试-运维分工 : 在企业中,整个...
  • 测试开发笔记

    万次阅读 多人点赞 2019-11-14 17:11:58
    CMM与CMMI的区别 23 第五章 SQL 24 约束: 29 1主键约束 29 2 非空约束 not null 30 3 外键约束 FOREIGN KEY 30 4 默认约束 31 5 检查约束 check 31 6 唯一约束 unique 32 SQL语句 32 创建数据库. 32 表、字段、...
  • 数据库又称作数据集合,如果没有数据库管理人员需要一条一条的进行输入数据,于是有发明了一条C语言语句,可以循环使用(增删查)比如双十一的购物车就是数据库的体现,把想要的数据整理到一个文件中,在互联网...
  • 基于SSM的校园二手交易平台的设计与实现

    万次阅读 多人点赞 2018-05-06 14:24:44
    数据库:MySQL 框架:Spring + Spring MVC + MyBatis 服务器:Tomcat 前端解析框架:Thymeleaf 开发工具:Idea 2017 版本管理工具:Maven 版本控制工具:GitHub 下载地址:...
  • 基于Java和MySQL的图书管理系统

    万次阅读 多人点赞 2018-06-20 21:41:17
    设计:wangyunpeng_bio 项目需求 随着计算机的普及和应用水平的提高,经过考察比较,决定利用自己的Java知识开发小型的图书管理系统,方便图书的管理。 图书管理系统是典型的信息管理系统。本次作业利用JAVA...
  • Redis面试题集

    千次阅读 多人点赞 2019-09-16 10:19:31
    合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必...
  • 最近在做项目的时候有一个需求,是要从相机中或相册中获取图片,而且还要将其存入SQLite,最开始的时候我想的是直接将图片存入数据库,但是后来在Google上发现不行,sqlite不支持这种类型,但是我看到了它支持Blob...
  • 其次,本次发文的目的主要是为了给C#初学者一个小小的参考,懂得如何连接数据库去进行增删查改,能更好的入门;最后,希望大家可以通过我的实例代码得到一定的收获,为日后的学习奠定基础。 有需要本资源的请点击此...
  • 浦发银行 信息科技岗 大数据方向 面经

    万次阅读 多人点赞 2018-08-09 23:00:31
    我的三个题目是: 字符串反转 数列求和 字符串缩写 (悄咪咪说一句,还可以看到大家的做题状态和排名,而且好像是手,不是很懂) 结构化面试 结构化面试就是正常的面试,大概一个十分钟左右的样子,多,面试...
  • 最近很多反映,当spring+springmvc+mybatis整合之后,不知道图片的上传、回显、展示、下载如何实现。其实ssm框架已经帮我们封装好了这块,我们要做的就是进行相关的配置和调用。今天我就配置这块进行一个简单讲解...
  • 5 分钟理解数据库死锁

    千次阅读 多人点赞 2021-05-07 22:03:39
    本文简要介绍了数据库死锁产生的原因和解决方法。 加锁(Locking)是数据库在并发访问时保证数据一致性和完整性的主要机制。任何事务都需要获得相应对象上的锁才能访问数据,读取数据的事务通常只需要获得读锁(共享...
  • 在此先感谢论坛博客的各位大佬,因为实在是查了太多资料,连我自己究竟是在哪里拼拼凑凑出解决办法的过程都差不多快模糊了,第一次安装数据库,花了3天终于搞定了,博主的很多教程都是旧版本的指令,根本无法运行。...
  • 关系型数据库,是指采用了关系模型来组织数据的数据库,其以行和列的形式存储数据,以便于用户理解,关系型数据库这一系列的行和列称为表,一组表组成了数据库。用户通过查询来检索数据库中的数据,而查询是一个...
  • 这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
     Java 3DMenu 界面源码,有说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java源码...
  • 出来,就是数据库中blob字段显示不出来,然后发送邮件的时候,图片也读取不出来,请问这个要怎么修改,才能在邮件发送的时候让收件可以看到这个图片????????????????? 如果是路径问题,这个要在哪里去修改它的路径...
  • 所有的联系Uri,与联系相关数据库字段均在此定义。这个类中有很多的内部接口和内部类,用来翻译一些表,例如Data内部类,RawContacts内部类等。 通信录是一个3层的数据存储模型,这三个数据模型就是...
  • 帝国系统数据库端口号修改

    千次阅读 2012-04-01 17:29:35
    1、帝国系统数据库端口号修改  e/class/config.php 这个是数据库配置文件,里面包含了整个系统的基本配置信息 2、帝国cms后台登录 提示登录成功又提示您还未登录 今天接收别人发过来的企业网站,...
  • 数据库订单表设计

    万次阅读 多人点赞 2019-01-16 15:08:19
    数据库设计原则是: 1. 为提高读的性能,尽可能把写的操作拆分到另一张表,因为对表的更新操作会导致锁表,会降低数据表的读取的性能。 2. 交易时一些关联信息可能在后来会修改或删除,如商品、收货地址等,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 130,289
精华内容 52,115
关键字:

数据库被人改了图片