`

将文件保存到数据库,并取出

 
阅读更多

这几天在做将文件保存到数据库的一个工作,因为在cloud中规定不能将文件download下来并且保存在server上。

要做的工作是:

1. 从FTP上download下来字节流并且保存到数据库

2.从数据库读出这个数据流并且显示相应的数据

 

步骤:

1.建立表ad_download_file,字段有fileid,filename,filedata。用BLOB存储文件

CREATE TABLE ad_download_file (
  filename VARCHAR2(50) NOT NULL,
  fileid   INTEGER      NOT NULL,
  filedata BLOB         NULL
)
 

2.因为cloud规定只能用存储过程,因此建了一个存储过程用于插入文件

CREATE OR REPLACE PROCEDURE sp_insert_file(fname IN VARCHAR,fdata out BLOB
) AS
countOfdata int;
BEGIN
select count(*) into countOfdata from ad_download_file where fname = filename;
if countOfdata = 0  then
insert into ad_download_file(fileid,filename,filedata) values(SEQ_AD_DOWNLOAD_FILE_ID.NEXTVAL,fname,empty_blob());
end if;
select filedata into fdata from ad_download_file where fname = filename FOR UPDATE;
END;
/

 在存储过程中,先判断有没有相同名字的文件已经存在,如果不存在,则先插入一个空的blob到数据库。在最后查出这条数据的filedata。注意最后一条select语句后面有个“FOR UPDATE".用于锁定当前这行数据。

3.java 代码

 

  public ArrayList doExecuteProcedure(String query, BaseVO valueObject) throws SWTException
    {
	ArrayList outputList = new ArrayList();
	Connection con = null;
	CallableStatement callTest = null;
	try
	{

	    DBQueryDetails dBQueryDetails = ApplicationDataConfig.getDaomap().lookupQueryHandler(query);
	    setBaseVO(valueObject);

	    con = initDBConnection(dBQueryDetails.getDatabaseName());

	    Logger.debug("connection Object =" + con);

	    boolean autoCommit = con.getAutoCommit();
	    con.setAutoCommit(false);
	    ArrayList<String> inputParamNamesArrayList = dBQueryDetails.getInputParamNamesArrayList();
	    Logger.debug("inputParamNamesArrayList =" + inputParamNamesArrayList);

	    if (inputParamNamesArrayList != null && inputParamNamesArrayList.size() > 0)
	    {
		intializeArrayListInputs(inputParamNamesArrayList, con);
	    }

	    callTest = con.prepareCall("call " + dBQueryDetails.getQuery());

	    ArrayList<String> inputParamNames = dBQueryDetails.getInputParamNames();
	    ArrayList inputParamValues = intializeQueryInputs(inputParamNames);

	    int i = 1;
	    for (int j = 0; j < inputParamValues.size(); j++, i++)
	    {
		callTest.setObject(i, inputParamValues.get(j));
	    }
	    ArrayList<String> outputParamNames = dBQueryDetails.getOutputParamNames();
	    Class VOClass = baseVO.getClass();
	    HashMap<String, String> fieldDataTypes = getFieldDataTypes(VOClass, outputParamNames);
	    for (int j = 0; j < outputParamNames.size(); j++, i++)
	    {
		callTest.registerOutParameter(i, getJavaToOracleDatatype(fieldDataTypes.get(outputParamNames.get(j))));
	    }

	    callTest.execute();
            //将数据通过反射设置到对象,并且返回对象链表
	    outputList = populateVO(i, callTest, outputParamNames, fieldDataTypes);

	    con.commit();
	    con.setAutoCommit(autoCommit);

	}
	catch (SQLException e)
	{
	    Logger.error("DBAction.doExecuteProcedure() ==> " + e.getMessage(), e);
	    throw new SWTException(e);
	}
	catch (Exception e)
	{
	    Logger.error("DBExecute.doExecuteProcedure() ==> " + e.getMessage());
	    throw new SWTException(e);
	}
	finally
	{
	    try
	    {
		if (callTest != null)
		{
		    callTest.close();
		    callTest = null;
		}
	    }
	    catch (SQLException ex)
	    {
		Logger.error("DBAction.doExecuteProcedure() ==> " + ex.getMessage(), ex);
		throw new SWTException(ex);
	    }
	    if (con != null)
	    {
		Logger.debug("doExecuteProcedure close conn:" + con);
		connMgr.freeConnection(ApplicationDataConfig.getConfiguration().getDbPoolName(), con);
	    }
	}
	return outputList;
    }

 //将数据通过反射设置到对象,并且返回对象链表
 private ArrayList populateVO(int i, CallableStatement callTest, ArrayList<String> outputParamNames,
	    HashMap<String, String> fieldDataTypes) throws SWTException
    {
	ArrayList outputList = new ArrayList();
	InputStream input = null;
	OutputStream blobOutput = null;
	try
	{
	    Class VOClass = baseVO.getClass();
	    Object VOObject = VOClass.newInstance();

	    for (int j = i - outputParamNames.size(), k = 0; j < i; j++, k++)
	    {
		String tempFieldName = outputParamNames.get(k);
		String tempMethName = createMethodName(tempFieldName, "set");
		Method method = VOClass.getMethod(tempMethName, Class.forName(fieldDataTypes.get(tempFieldName)));
		String typeName = fieldDataTypes.get(tempFieldName);

		if (DBConstants.BIGDECIMAL.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getDouble(j));
		}
		if (DBConstants.BOOLEAN.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getBoolean(j));
		}
		if (DBConstants.BYTE.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getByte(j));
		}
		if (DBConstants.SQL_DATE.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getDate(j));
		}
		if (DBConstants.UTIL_DATE.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getDate(j));
		}
		if (DBConstants.DOUBLE.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getDouble(j));
		}
		if (DBConstants.FLOAT.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getFloat(j));
		}
		if (DBConstants.INTEGER.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getInt(j));
		}
		if (DBConstants.LONG.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getLong(j));
		}
		if (DBConstants.OBJECT.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getObject(j));
		}
		if (DBConstants.SHORT.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getShort(j));
		}
		if (DBConstants.TIME.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getTime(j));
		}
		if (DBConstants.SQL_TIMESTAMP.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getTimestamp(j));
		}
		if (DBConstants.STRING.equalsIgnoreCase(typeName))
		{
		    method.invoke(VOObject, callTest.getString(j));
		}
		if (DBConstants.BLOB.equalsIgnoreCase(typeName))
		{
		    // When have outputStream in the object, then update to the
		    // database;
		    method.invoke(VOObject, callTest.getBlob(j));

		    // get the OutputStream parameter from the baseVO
		    String getMethName = createMethodName(tempFieldName, "get");
		    BLOB blob = (BLOB) callTest.getBlob(j);
		    if (blob != null)
		    {
			Object obj = null;
			String outputStreamName = null;

			try
			{ 
//通过反射拿到后缀名为OutputStream变量,例如
// private BLOB filedata;
// private ByteArrayOutputStream filedataOutputStream;
//filedataOutputStream用于保存数据库返回的文件数据,或者要传到数据库的文件数据
//这样做是因为文件的数据必须在connection关闭前都从数据库中拿出来。如果只返回Blob对象
//那么Blob对象中只保存了一行的数据
                            outputStreamName = tempFieldName + "OutputStream";
			    Method getOutputStreamMethod = VOClass.getMethod(createMethodName(outputStreamName, "get"));
			    obj = getOutputStreamMethod.invoke(baseVO);
			}
			catch (Exception e)
			{
			    Logger.info("DBAction.populateVO() ==> " + e.getMessage(), e);
			}
// when OutputStream is empty,need set the data into
// OutputStream object
  //判断是要更新数据还是要取数据,如果OutputStream是空的表示要取数据,否则是更新数据 
			if (obj == null)
			{
                            //拿到二进制数组字节流,并且写入到字节数组中
                            Method setOutputStreamMethod = VOClass.getMethod(createMethodName(outputStreamName, "set"), VOClass
				    .getDeclaredField(outputStreamName).getType());
			    ByteArrayOutputStream baot = new ByteArrayOutputStream();
			    input = blob.getBinaryStream();
			    int data = -1;
			    while ((data = input.read()) != -1)
				baot.write(data);

			    setOutputStreamMethod.invoke(VOObject, baot);
			}
// when OutputStream is not empty,update OutputStream
// object into database
 //通过toByteArray()方法将数据转成字节数组
			else
			{
			    ByteArrayOutputStream baot = (ByteArrayOutputStream) obj;
			    blobOutput = blob.setBinaryStream(0);
			    blobOutput.write(baot.toByteArray());
			    blobOutput.flush();
			}
		    }
		}
	    }

	    outputList.add(VOObject);
	}
	catch (Exception e)
	{
	    Logger.error("DBAction.populateVO() ==> " + e.getMessage(), e);
	    throw new SWTException(e);
	}
	finally
	{

	    try
	    {
		if (input != null)
		{
		    input.close();
		}
		if (blobOutput != null)
		{
		    blobOutput.close();
		}
	    }
	    catch (IOException e)
	    {
		// TODO Auto-generated catch block
		Logger.error("DBAction.populateVO() ==> " + e.getMessage(), e);
	    }

	}
	return outputList;
    }

总结:其实这个很简单,写这篇文章的目的是记录一下怎么去做大文件存取。并总结一下要注意的地方。一共有三点

1.必须把setAutoCommit()设置成false,因为如果是true,那么select出blob对象的时候,就commit了,那么BLOB对象也就断开了和数据库的链接

2.在存文件到BLOB对象之前需要先SELECT出BLOB对象,并且用FOR UPDATA锁住这行,以便在java程序中更新

3.在connection close之前需要拿出BLOB的所有数据。

4.在文件保存的时候肯定涉及到Byte和String 之间的转换,可以用下面代码将ByteArrayOutputStream转成BufferedReader

BufferedReader in = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(readByteArrayOutputStream(fileName,
            ProcessesConstants.SP_SELECT_FILE).toByteArray())));
 

 

 

分享到:
评论

相关推荐

    图片BASE64加密保存到数据库Blob类型中(放入数据库,并取出生成图片)

    图片BASE64加密保存到数据库Blob类型中(放入数据库,并取出生成图片),完整的demo例子,可运行。

    将图片以字节流存到数据库再从数据库获取显示

    想实现的,现在实现了,希望能帮到需要的。

    C#将文件(图片)路径保存到sqlserve数据库中

    使用C#语言,将文件(图片)路径保存到sqlserve数据库中,并且从数据库中读取出路径,找到相应的文件。

    delphi access 保存取出文件

    delphi 数据库 保存 取出 任意类型文件

    mysql存储和提取文件

    2、保存文件(含可执行文件)到MySQL数据库中,包括文件大小超过1M时的异常处理; 3、从MySQL数据库中读取文件并保存至本地; 4、MySQL数据防止重复插入功能; 5、MySqlHelpher操作类,完全由我本人实现,此类包含...

    Qt从数据库中提取数据给变量赋值

    Qt中执行sql语句,当需要变量存取从数据库中获取的值,首先取出一行数据,然后按列将数据分别赋给变量

    VB连接远程数据库读取并保存数据源程序

    内容索引:VB源码,数据库应用,连接远程数据库 一个网络与数据库相结合的VB实例,连接远程数据库读取数据,并尝试保存...如果可以连接远程数据库,那么新建的用户将被保存,并且可以读取出远程数据库内的所有用户信息。

    易语言创想工作站源码,易语言创想服务器源码,易语言数据库服务器

    易语言数据库服务器源码,数据库服务器,记录保存密码信息,取出保存密码信息,请求更新数据,读加密配置项,写加密配置项,取加密配置节名,取加密配置项名,删除加密配置小节,配置文件_写用户信息,配置文件_删除用户,配置...

    毕业设计:ASP基于USB KEY文件加密工具-USB key管理系统(源代码)

    在KEY的管理方面我们需要把KEY里面记录的信息都保存到数据库里面,方便我们查询、修改、添加和删除KEY里面的信息。对每把锁都进行管理,防止有同号锁出现。如果加密锁因为某种情况损坏或者是丢失了,那么可以通过...

    dbImages读取数据库的BLOB

    可以使用CdbImage进行读取数据库的BLOB,并取出数据,或者保存为图片等操作,请结合本人相关blog进行阅读。

    使用python将mysql数据库的数据转换为json数据的方法

    本文将涉及到如何使用Python访问Mysql数据库及读取获取数据(前提需要安装MySQLdb第三方库哦),以及如何将数据转换为json数据,最后保存成文件输出。 代码如下:注释比较详细了。 # coding=utf-8 ''' Created on ...

    ORACLE数据库智能化管理系统2012

    数据库状态及运行情况综合查看,使您了解ORACLE运行状况及空间、日志归档、数据文件等使用情况更直观,并可智能生成数据库热备份脚本和备份恢复方案,为您的数据库保驾护航,使您高枕无忧。 本系统可执行SQL分组语句后...

    vss如何使用(图解)

    文件保存在VSS数据库中的项目(project)里。你无须管理存储在VSS 中的文件正本,除非你要检查或与其它拷贝进行比较。 VSS为每一位用户提供了一份备份文件放入工作文件夹(working folder),供用户对文件进行查看与编辑...

    在ASP.net中保存/取出图片入/从SQL数据库

    一、把图片存入数据库中用到以下几个方面的知识:1. 使用流对象2. 查找准备上传的图片的大小和类型3.怎么使用InputStream方法插入图片的必要条件1.#Form 标记的 enctype 属性应该设置成 enctype=”multipart/form-...

    visual source safe 教程

    文件保存在VSS数据库中的项目(project)里。你无须管理存储在VSS 中的文件正本,除非你要检查或与其它拷贝进行比较。 VSS为每一位用户提供了一份备份文件放入工作文件夹(working folder),供用户对文件进行查看与编辑...

    Visual stdio source safe 教程

    文件保存在VSS数据库中的项目(project)里。你无须管理存储在VSS 中的文件正本,除非你要检查或与其它拷贝进行比较。 VSS为每一位用户提供了一份备份文件放入工作文件夹(working folder),供用户对文件进行查看与编辑...

    宏乐声纹对比控件v10.1.767G最新安装版

    通过这个控件可以获得声音句子的纹理,...户可以将不同的特征文件与数据库一一对应保存,然后通过对比函数从数据库取出不同的特征文件与当前的录音结果对比,从而知道当前的声纹与数据库内的哪一个声纹最吻合。我们还为

    宏乐语音识别控件10.1.767G官方安装版

    用户可以将不同的特征文件与数据库一一对应保存,然后通过对比函数从数据库取出不同的特征文件与当前的录音结果对比,从而知道当前的声纹与数据库内的哪一个声纹最吻合。 我们还为掌上电脑,或学习机提供DLL评分插件

    Android开发--多线程下载加断点续传

    在进行下载之前去访问数据库是否有记录存在,如果没有执行第一次下载的初始化,如果存在记录但下载文件不存在时,删掉数据库中的记录之后进行第一次下载的初始化,如果有记录且文件存在,则从数据库中取出信息。...

    毕业设计,基于SpringBoot+Vue+MySql开发的前后端分离的电商平台,内含Java完整源代码,数据库脚本

    毕业设计,基于SpringBoot+Vue+MySql...用户将信息保存到LocalStorage中,并在以后将token放入请求头中 后端通过拦截器实现:后端收到请求后,会先取出请求头中的token,并根据token查询用户信息,然后把用户信息放入T

Global site tag (gtag.js) - Google Analytics