2017-05-24 93 views
2

我有一个简单的(例如)脚本文件上传到数据库(Oracle中,如果它的问题):传递大的BLOB存储过程

<cfscript> 
param string filename; 

if (FileExists(filename)) 
{ 
    result = new StoredProc(
    datasource = "ds", 
    procedure = "FILE_UPLOAD", 
    result  = "NA", 
    parameters = [ 
     { value = FileReadBinary(filename), type = "in", cfsqltype = "CF_SQL_BLOB" } 
    ] 
).execute(); 
} 
</cfscript> 

然而,ColdFusion CFML ReferenceFileReadBinary(filepath)

注意: 此操作将文件读取到本地变量作用域中的变量中。它不适用于诸如日志之类的大文件,因为它们可以关闭服务器。

如果我不应该使用FileReadBinary(filepath),我应该如何上传一个大的(0.5 - 1Tb)文件?

+1

不管怎样,您都不应该通过Web界面加载大型文件。该请求在上传之前会超时。无论您重写请求超时的时间长短如何,这似乎都需要一种不同的解决方案,例如将文件上传到FTP服务器,而不是CF之外,并让其他一些进程将其加载到Oracle中。 –

+1

我同意这不是一个典型的用法,但不一定会失败。我正在开发一个应用程序,为Web请求生成几百MB的答案,并且工作正常。当然,客户端和服务器都在同一个局域网中,但我认为在这种情况下它是一样的。 – Galcoholic

回答

1

至于建议的@Galcoholic,您可以利用底层Java类和使用CallableStatement.setBlob(int, InputStream)

<cfscript> 
param string filename; 

// Get the necessary Java classes: 
Files = createObject('java', 'java.nio.file.Files'); 
Paths = createObject('java', 'java.nio.file.Paths'); 

// Do not timeout the request 
setting requesttimeout = 0; 

try { 
    input = Files.newInputStream(Paths.get(filename, []), []); 

    connection = createObject('java', 'coldfusion.server.ServiceFactory') 
        .getDataSourceService() 
        .getDataSource('ds') 
        .getConnection() 
        .getPhysicalConnection(); 
    statement = connection.prepareCall('{call FILE_UPLOAD(?)}'); 
    statement.setBlob(JavaCast('int', 1), input); 
    statement.executeUpdate() 
} 
finally 
{ 
    if (isDefined("statement")) 
    statement.close(); 
    if (isDefined("connection")) 
    connection.close(); 
} 
</cfscript> 

注:

  • 任何争论都必须为Java方法来提供;所以对于具有可变数量参数的方法,则参数必须作为数组传递(或者没有附加参数的空数组)。
  • ColdFusion数值不会被隐式强制为Java数字文字,因此需要JavaCast('int', value)
  • 错误处理不包括在上面的例子中。
  • 如果文件已上传,则管理控制台中的“发布数据最大数量”和“请求调节内存”设置将需要从默认大小增加到适合上传文件大小的适当限制(否则coldfusion.util.MemorySemaphore将在解析脚本之前处理上载时抛出内存不足异常)。
1

如果使用Java是一个选项,那么您可以将InputStream对象传递给PreparedStatement以填充Blob字段。事情是这样的,要添加异常处理和所有其他的东西:

Connection con = someDataSource.getConnection(); 
String sql = "INSERT INTO MY_TABLE(MY_BLOB) VALUES(?)"; 
PreparedStatement ps = con.prepareStatement(sql); 
InputStream fis = new FileInputStream("MyBigFile.big"); 
ps.setBlob(1, fis); 
ps.executeUpdate(); 

我认为Java将使用缓冲区去做,而不是整个文件加载到内存中。