我看到其他线程说明了如何为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。
任何帮助都会很棒
答案 0 :(得分:0)
所以我找到了让它发挥作用的方法,但我不喜欢它。它是对数据库的非常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
答案 1 :(得分:0)
Oracle-DB上的查询超时适用于Rails 4和JRuby
使用JRuby,您可以使用JBDC-function 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