2017-05-24 99 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將使用緩衝區去做,而不是整個文件加載到內存中。