250插入后,Sqlite3库不会打开

时间:2012-07-26 00:19:58

标签: ruby sqlite sqlite3-ruby

我正在尝试使用ruby脚本将大量信息插入到Sqlite3数据库中。在执行250 db_prepare_location.execute之后,它停止工作说:

.rvm/gems/ruby-1.9.2-p290/gems/sqlite3-1.3.6/lib/sqlite3/statement.rb:67:in `step': unable to open database file (SQLite3::CantOpenException)
    from /Users/ashley/.rvm/gems/ruby-1.9.2-p290/gems/sqlite3-1.3.6/lib/sqlite3/statement.rb:67:in `execute'
    from programs.rb:57:in `get_program_details'
    from programs.rb:22:in `block in get_link'
    from /Users/ashley/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/csv.rb:1768:in `each'
    from /Users/ashley/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/csv.rb:1202:in `block in foreach'
    from /Users/ashley/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/csv.rb:1340:in `open'
    from /Users/ashley/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/csv.rb:1201:in `foreach'
    from programs.rb:20:in `get_link'
    from programs.rb:63:in `<module:Test>'
    from programs.rb:15:in `<main>'

这是我的代码:

require 'net/http'
require 'json'
require 'nokogiri'
require 'open-uri'
require 'csv'
require 'sqlite3'
require "bundler/setup"
require "capybara"
require "capybara/dsl"

Capybara.run_server = false
Capybara.default_driver = :selenium
Capybara.current_driver = :selenium

module Test
  class Tree
    include Capybara::DSL

    def get_link
      CSV.foreach("links.csv") do |row|
        link = row[0]
        get_details(link)
      end
    end

    def get_details(link)
      db = SQLite3::Database.open "development.sqlite3"
      address = []
      address_text = []
      visit("#{link}")
      name = find("#listing_detail_header").find("h3").text
      page.find(:xpath, "//div[@id='listing_detail_header']").all(:xpath, "//span/span").each {|span| address << span }
      if address.size == 4
        street_address = address[0].text
        address.shift
        address.each {|a| address_text << a.text }
        city_state_address = address_text.join(", ")
      else
        puts link
        street_address = ""
        city_state_address = ""
      end
      if page.has_css?('.provider-click_to_call')
        find(".provider-click_to_call").click
        phone_number = find("#phone_number").text.gsub(/[()]/, "").gsub(" ", "-")
      else
        phone_number = ""
      end
      if page.has_css?('.provider-website_link')
        website = find(".provider-website_link")[:href]
      else
        website = ""
      end
      description = find(".listing_details_list").find("p").text
      db_prepare_location = db.prepare("INSERT INTO programs(name, city_state_address, street_address, phone_number, website, description) VALUES (?, ?, ?, ?, ?, ?)")
      db_prepare_location.bind_params name, city_state_address, street_address, phone_number, website, description
      db_prepare_location.execute
    end
end


test = Test::Tree.new
test.get_link
end

这里有什么问题,我该怎么办才能修复它?如果需要其他信息,请与我们联系。

1 个答案:

答案 0 :(得分:3)

您可能正在运行文件描述符。每次调用get_details时,都会打开SQLite数据库:

db = SQLite3::Database.open "development.sqlite3"

但你从未明确地关闭它;相反,您依靠垃圾收集器来清理所有db并关闭所有文件描述符。每次打开数据库时,都需要分配文件描述符,关闭数据库会释放文件描述符。如果您以比GC更快的速度调用get_details,那么您将用完文件描述符,后续的SQLite3::Database.open调用将失败。

尝试在db.close的末尾添加get_details

您可能还必须关闭准备好的声明,因此您应该db_prepare_location.close之前db.close

def get_details
  #...
  db_prepare_location.close
  db.close
end

是的,Ruby有垃圾收集,但这并不意味着您不必手动管理资源。

另一个选项(DGM暗示)将在构造函数中打开与数据库的连接:

def initialize
  @db = SQLite3::Database.open "development.sqlite3"
end

然后将SQLite3::Database.open来电放入get_details并改为使用@db。您不再需要db.close get_details,但仍需要db_prepare_location.close来电。