【问题标题】:Passing large BLOBs to Stored Procedure将大型 BLOB 传递给存储过程
【发布时间】:2017-10-24 23:53:05
【问题描述】:

我有一个简单的(示例)脚本将文件上传到数据库(Oracle,如果重要的话):

<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 Reference 状态为 FileReadBinary( filepath )

注意: 此操作将文件读入局部变量范围内的变量中。它不适用于大文件,例如日志,因为它们会导致服务器崩溃。

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

【问题讨论】:

  • 无论如何,您都不应该通过 Web 界面加载那么大的文件。请求将在上传之前很久就超时。无论您覆盖请求超时多长时间,这似乎都需要一个不同的解决方案,例如将文件上传到 CF 之外的 FTP 服务器,并让其他一些进程将其加载到 Oracle 中。
  • 我同意这不是典型的用法,但肯定不会失败。我正在开发一个为 Web 请求生成数百 MB 答案的应用程序,它运行良好。当然,客户端和服务器在同一个局域网,但我想在这种情况下是一样的。

标签: oracle stored-procedures coldfusion blob


【解决方案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 会使用缓冲区来做到这一点,而不是将整个文件加载到内存中。

【讨论】:

    【解决方案2】:

    按照@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 方法提供每个参数;因此,对于具有可变数量参数的方法,VARARGS 参数必须作为数组传递(或者对于没有其他参数的空数组)。
    • ColdFusion 数值不会被隐式强制转换为 Java 数值文字,因此需要 JavaCast( 'int', value )
    • 上述示例中未包含错误处理。
    • 如果文件已上传,则需要将管理控制台中的“帖子数据的最大大小”和“请求限制内存”设置从默认大小增加到上传文件大小的适当限制(否则coldfusion.util.MemorySemaphore 在解析脚本之前处理上传时会抛出内存不足异常)。

    【讨论】:

      猜你喜欢
      • 2014-02-26
      • 2011-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多