读取BLOB字段会因为文件字段太大导致connect连接超时关闭而不能读全的情况的解决方案

方案一:

通过委托模式(类似这种),在Controller层的请求方法中实现事务层上的读取blob并转化成流

上代码:

控制层

/*** BLOB下载*/@RequestMappingpublic String downloadBlob(HttpServletRequest request,final HttpServletResponse response, String param, String fileName)throws Exception {String[] params = param.split(";");// 数据集IDString dataset_id = params[0];// 字段名String columnName = params[1];// 唯一键值UniqueKey uk = UniqueKey.parseUniqueKey(params[2]);if (fileName == null) {// 文件名为空的时候以主键值作为文件名fileName = uk.firstEntry().getValue().toString();}final String destFileName = fileName;DataSetMeta dataSetMeta = datasetService.retrieveDataSetMeta(dataset_id);DBDataAccessorWithBlob accessor = new DBDataAccessorWithBlob(dataSetMeta);accessor.handleBlob(columnName, uk, new BlobHandler() {// 处理BLOB对象,以流的形式写入response实现下载public void handle(Blob blob) throws Exception {InputStream inputStream = blob.getBinaryStream();// 设置response类型、文件名、大小等。response.setContentType("application/octet-stream");response.setCharacterEncoding("UTF-8");String downLoad = new String(destFileName.getBytes("GBK"),"ISO-8859-1");response.setHeader("Content-disposition","attachment;filename=\"" + downLoad + "\"");response.setHeader("Content-Length", String.valueOf(blob.length()));// 写入responseOutputStream output = null;try {byte[] bytes = new byte[1024];output = response.getOutputStream();int byteRead;while ((byteRead = inputStream.read(bytes)) != -1) {output.write(bytes, 0, byteRead);}output.flush();} finally {IOUtils.closeQuietly(inputStream);IOUtils.closeQuietly(output);response.flushBuffer();}}});return null;}

事务层:

public class DBDataAccessorWithBlob extends DBDataAccessor {public DBDataAccessorWithBlob(DataSetMeta dataSetMeta) {super(dataSetMeta);}public void handleBlob(String columnName, UniqueKey uk, BlobHandler blobHandler)throws Exception {BaseDBAccessor accessor = (BaseDBAccessor) getDataAccessor();if (dataSetMeta == null || dataSetMeta.getDataColumn() == null|| columnName == null || columnName.trim().equals("")) {return;}String DBDriver="";String DBurl="";String DBusername="";String DBpassword="";//通过jdbc创建并获取连接DriverManager.registerDriver((Driver) Class.forName(DBDriver).newInstance());Connection conn=DriverManager.getConnnection(DBurl,DBusername,DBpassword);通过连接池获取连接//Connection con = accessor.getConnection(dataSetMeta);try {// 查询结果字段String[] result_column_array = new String[] { columnName };// 构建SQL语句String sql = "";sql += accessor.buildSelectStament(dataSetMeta.getFullName(),result_column_array, true);sql += accessor.buildUniqueKeyWhere(uk);PreparedStatement ps = con.prepareStatement(sql);// 设置唯一键值String[] uk_column_array = uk.getFields();for (int i = 0; i < uk_column_array.length; i++) {String column = uk_column_array[i];ps.setObject(i + 1, uk.get(column));}ResultSet rs = ps.executeQuery();while (rs.next()) {Blob blob = rs.getBlob(columnName);blobHandler.handle(blob);}rs.close();ps.close();} catch (SQLException e) {throw e;} finally {try {con.close();} catch (SQLException e) {throw e;}}return;}public interface BlobHandler {public void handle(Blob blob) throws Exception;}
}

看出来上面的情况木有,在控制层的实现事务层的接口BlobHandler,而在事务层调用接口的方法。这样可以在未关闭之前已经将blob字段转换成流了,不用担心连接因读的时间过长而关闭的情况了。

第二种方案:

不能过jdbc的动态创建连接,DriverManager.getConnection()来获取连接,而是取连接池中存在的连接,因为连接池中的连接在代码手动关闭的时候并不是实际关闭了,而是将连接放入到连接池中去,程序仍然可以读取blob字段,因为blob并不是读取数据本事,而是数据的引用,因此这种方式,也能读全文件内容。

控制层:

/*** BLOB下载*/@RequestMappingpublic String downloadBlob(HttpServletRequest request,final HttpServletResponse response, String param, String fileName)throws Exception {String[] params = param.split(";");// 数据集IDString dataset_id = params[0];// 字段名String columnName = params[1];// 唯一键值UniqueKey uk = UniqueKey.parseUniqueKey(params[2]);if (fileName == null) {// 文件名为空的时候以主键值作为文件名fileName = uk.firstEntry().getValue().toString();}final String destFileName = fileName;DataSetMeta dataSetMeta = datasetService.retrieveDataSetMeta(dataset_id);DBDataAccessorWithBlob accessor = new DBDataAccessorWithBlob(dataSetMeta);Blob blob=accessor.handleBlob(columnName, uk, null);   // 处理BLOB对象,以流的形式写入response实现下载InputStream inputStream = blob.getBinaryStream();// 设置response类型、文件名、大小等。response.setContentType("application/octet-stream");response.setCharacterEncoding("UTF-8");String downLoad = new String(destFileName.getBytes("GBK"),"ISO-8859-1");response.setHeader("Content-disposition","attachment;filename=\"" + downLoad + "\"");response.setHeader("Content-Length", String.valueOf(blob.length()));// 写入responseOutputStream output = null;try {byte[] bytes = new byte[1024];output = response.getOutputStream();int byteRead;while ((byteRead = inputStream.read(bytes)) != -1) {output.write(bytes, 0, byteRead);}output.flush();} finally {IOUtils.closeQuietly(inputStream);IOUtils.closeQuietly(output);response.flushBuffer();}};

事务层:

public class DBDataAccessorWithBlob extends DBDataAccessor {public DBDataAccessorWithBlob(DataSetMeta dataSetMeta) {super(dataSetMeta);}public Blob handleBlob(String columnName, UniqueKey uk, BlobHandler blobHandler)throws Exception {BaseDBAccessor accessor = (BaseDBAccessor) getDataAccessor();if (dataSetMeta == null || dataSetMeta.getDataColumn() == null|| columnName == null || columnName.trim().equals("")) {return;}通过连接池获取连接Connection con = accessor.getConnection(dataSetMeta);try {// 查询结果字段String[] result_column_array = new String[] { columnName };// 构建SQL语句String sql = "";sql += accessor.buildSelectStament(dataSetMeta.getFullName(),result_column_array, true);sql += accessor.buildUniqueKeyWhere(uk);PreparedStatement ps = con.prepareStatement(sql);// 设置唯一键值String[] uk_column_array = uk.getFields();for (int i = 0; i < uk_column_array.length; i++) {String column = uk_column_array[i];ps.setObject(i + 1, uk.get(column));}ResultSet rs = ps.executeQuery();while (rs.next()) {blob = rs.getBlob(columnName);}rs.close();ps.close();} catch (SQLException e) {throw e;} finally {try {con.close();} catch (SQLException e) {throw e;}}return blob;}
}

转载于:https://my.oschina.net/grindwheel/blog/369755

浏览器下载文件,读取BLOB字段会因为数据太大导致数据库连接connect超时关闭的解决方案...相关推荐

  1. 分块读取Blob字段数据(Oracle)

    试过了MSSQL的分块读取Blob字段,又尝试在Oracle下完成,发现还是可行的. 首先建立一个存储过程: create or replace procedure PRO_GET_BLOB(     ...

  2. asp.net 浏览器下载文件的四种方式

    其实不是自己想要的,自己希望能够弹一个窗口出来选择保存的路径 protected void Button1_Click(object sender, EventArgs e){protected vo ...

  3. 钉钉内置浏览器下载文件(钉钉跨域下载文件、图片等)

    刚开始在网上查询到很多资料其中最为广泛的是用<a>download下载,但是会遇到图片.txt.MP4等文件无法下载被浏览器直接打开,后来尝试用blob的方法进行字节流转换,虽然成功了,但 ...

  4. Springboot实现浏览器下载文件

    public void getUnbondFile(HttpServletResponse response) throws FileNotFoundException, UnsupportedEnc ...

  5. 解决:Safari浏览器下载文件,后缀多拼接了.html

    你是否遇到同样的问题? 最后效果: 问题: 其他浏览器下载文件正常 Safari浏览器下载word文件,后缀多拼接了.html,导致打开下载文件乱码,下载的文件名称为vcard.vcf,手动去掉多余的 ...

  6. Android之解决PC端上传http表单格式文件手机解析文件名乱码问题和PC浏览器下载文件的文件名显示乱码问题

    1 问题 问题1. 手机写socket作为服务器,PC浏览器上传http表单格式文件,然后手机端解析携带中文的文件名我解析是乱码. 问题2. 手机写了socket作为服务器,PC浏览器下载文件,但是浏 ...

  7. springboot Java实现多文件的zip压缩操作 + 通过浏览器下载文件的两种方式

    注只适配utf-8的场景,待完善! 压缩为zip文件 通过java程序输出文件 /*** 功能:压缩多个文件成一个zip文件* @param srcfile:源文件列表* @param zipfile ...

  8. Python+Selenium练习篇13-设置浏览器下载文件默认地址

    本文介绍如何设置浏览器下载文件默认地址 设置Selenium自动化下载的浏览器默认地址 本人使用浏览器Chrome,python3.7 代码如下: # coding=utf-8 from seleni ...

  9. 解决浏览器下载文件时中文文件名乱码的问题

    解决浏览器下载文件时中文文件名乱码的问题 很多时候我们需要在后台为前端提供文件下载的功能,但是当文件名中有中文时我们不能直接将文件名返回,需要对中文的文件名进行处理后再返回. 一.文件下载contro ...

最新文章

  1. python 内置函数
  2. Ubuntu下搜狗输入法乱码(二)
  3. 我一哥们,在东莞和五名女孩被抓了.....
  4. linux权限体系有哪些角色,详解Linux下系统权限
  5. C#整理1——进制转换
  6. java 继承对象 初始化_java中具有继承关系的类及其对象初始化顺序
  7. 对是否要用Linux的思考
  8. 笛卡尔遗传规划Cartesian Genetic Programming (CGP)简单理解(1)
  9. HDU 2685 I won't tell you this is about number theory
  10. Systemd基础篇:systemd vs SysVinit
  11. 时间序列--平稳性介绍及检验方法
  12. Linux下文件、文件夹大小排序及文件内容排序
  13. 转帖node详细教程
  14. 【LeetCode LCP 3】机器人大冒险
  15. 当android调试遇到ADB server didn't ACK以及顽固的sjk_daemon进程
  16. Java中如何通过经纬度坐标获取两个点之间的直线距离
  17. 九龙证券|新三板再现最“壕”分红!北交所公司不遑多让
  18. Orbit Downloader 小巧无广告的下载工具,超赞的在线视频下载能力,比迅雷清爽多了!
  19. Vue高级语法(一) | 自定义指令详解
  20. Kubernetes:开源 K8s 管理工具 Rancher 认知

热门文章

  1. 拉格朗日松弛求解问题
  2. CA基本常识:X.509标准
  3. 使用python合并多个txt文件
  4. 贝叶斯调参——bayes_opt
  5. 武汉光庭导航面试经历
  6. VMware克隆Linux虚拟机
  7. 几种典型静电场的场强、电势
  8. Linux系统的进程和计划任务
  9. Java线程池及配置参数详解
  10. Linux查看CPU、内存、硬盘、操作系统相关详细信息