【问题标题】:how to set query timeout for oracle 11 in ruby如何在 ruby​​ 中为 oracle 11 设置查询超时
【发布时间】:2014-07-30 07:05:02
【问题描述】:

我看到其他线程说明了如何为 mySql 执行此操作,甚至如何在 java 中执行此操作,但没有说明如何在 ruby​​ 中设置查询超时。

我正在尝试使用 OJDBC7 在 Jruby 中使用 setQueryTimeout 函数,但找不到如何在 ruby​​ 中执行此操作。我尝试了以下方法:

@c.connection.instance_variable_get(:@connection).instance_variable_set(:@query_timeout, 1)
@c.connection.instance_variable_get(:@connection).instance_variable_set(:@read_timeout, 1)
@c.connection.setQueryTimeout(1)

我还尝试修改我的 database.yml 文件以包含

adapter: jdbc
  driver: oracle.jdbc.driver.OracleDriver
  timeout: 1

以上都没有任何效果,除了 setQueryTimeout 引发了方法错误。

任何帮助都会很棒

【问题讨论】:

标签: ruby-on-rails ruby oracle activerecord timeout


【解决方案1】:

所以我找到了一种让它工作的方法,但我不喜欢它。这是非常hackish和对数据库的孤立查询,但它至少允许我的应用程序继续执行。我仍然很想找到一种方法来取消该语句,这样我就不会孤立需要超过 10 秒的查询。

query_thread = Thread.new {
   #execute query
}

begin
  Timeout::timeout(10) do
    query_thread.join()
  end
rescue
  Thread.kill(query_thread)
  results = Array.new
end

【讨论】:

    【解决方案2】:

    Oracle-DB 上的查询超时适用于 Rails 4 和 JRuby

    使用 JRuby,您可以使用 JBDC 函数 statement.setQueryTimeout 来定义查询超时。

    这突然需要修补 oracle-enhanced_adapter,如下所示。 这个例子是一个迭代器查询的实现,没有将结果存储在数组中,它也使用了查询超时。

    # hold open SQL-Cursor and iterate over SQL-result without storing whole result in Array
    # Peter Ramm, 02.03.2016
    
    # expand class by getter to allow access on internal variable @raw_statement
    ActiveRecord::ConnectionAdapters::OracleEnhancedJDBCConnection::Cursor.class_eval do
      def get_raw_statement
        @raw_statement
      end
    end
    
    # Class extension by Module-Declaration : module ActiveRecord, module ConnectionAdapters, module OracleEnhancedDatabaseStatements
    # does not work as Engine with Winstone application server, therefore hard manipulation of class ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
    # and extension with method iterate_query
    
    ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
    
      # Method comparable with ActiveRecord::ConnectionAdapters::OracleEnhancedDatabaseStatements.exec_query,
      # but without storing whole result in memory
      def iterate_query(sql, name = 'SQL', binds = [], modifier = nil, query_timeout = nil, &block)
        type_casted_binds = binds.map { |col, val|
          [col, type_cast(val, col)]
        }
        log(sql, name, type_casted_binds) do
          cursor = nil
          cached = false
          if without_prepared_statement?(binds)
            cursor = @connection.prepare(sql)
          else
            unless @statements.key? sql
              @statements[sql] = @connection.prepare(sql)
            end
    
            cursor = @statements[sql]
    
            binds.each_with_index do |bind, i|
              col, val = bind
              cursor.bind_param(i + 1, type_cast(val, col), col)
            end
    
            cached = true
          end
    
          cursor.get_raw_statement.setQueryTimeout(query_timeout) if query_timeout
    
          cursor.exec
    
          if name == 'EXPLAIN' and sql =~ /^EXPLAIN/
            res = true
          else
            columns = cursor.get_col_names.map do |col_name|
              @connection.oracle_downcase(col_name).freeze
            end
            fetch_options = {:get_lob_value => (name != 'Writable Large Object')}
            while row = cursor.fetch(fetch_options)
              result_hash = {}
              columns.each_index do |index|
                result_hash[columns[index]] = row[index]
                row[index] = row[index].strip if row[index].class == String   # Remove possible 0x00 at end of string, this leads to error in Internet Explorer
              end
              result_hash.extend SelectHashHelper
              modifier.call(result_hash)  unless modifier.nil?
              yield result_hash
            end
          end
    
          cursor.close unless cached
          nil
        end
      end #iterate_query
    
    
    end #class_eval
    
    
    
    
    class SqlSelectIterator
    
      def initialize(stmt, binds, modifier, query_timeout)
        @stmt           = stmt
        @binds          = binds
        @modifier       = modifier              # proc for modifikation of record
        @query_timeout  = query_timeout
      end
    
      def each(&block)
        # Execute SQL and call block for every record of result
        ActiveRecord::Base.connection.iterate_query(@stmt, 'sql_select_iterator', @binds, @modifier, @query_timeout, &block)
      end
    
    end
    

    像这个例子一样使用上面的类 SqlSelectIterator:

    SqlSelectIterator.new(stmt, binds, modifier, query_timeout).each do |record|
      process(record) 
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-28
      • 2011-07-25
      • 1970-01-01
      • 2016-12-18
      • 2011-09-15
      • 1970-01-01
      相关资源
      最近更新 更多