为什么我的简单Ruby SQLite3示例失败了?

时间:2010-11-23 05:16:56

标签: ruby database sqlite dbi

在我学习Ruby的过程中,我一直在阅读Mr. Neighborly's Humble Little Ruby Book

大多数示例都很容易理解,为我提供了很好的Ruby介绍,但是我无法轻松地运行与DB相关的示例。

我正在尝试运行此代码:(稍微修改了本书中给出的示例)

#!/usr/bin/ruby
require 'rubygems'
require 'dbi'

DBI.connect('DBI:SQLite3:testdb', 'ruby', 'ruby') do | dbh |
  dbh.do('CREATE TABLE slugs(name varchar(20), age int);') rescue puts "TABLE slugs already exists."

  sql = "INSERT INTO slugs (name, age) VALUES (?, ?)"

  dbh.prepare(sql) do |st|
    1.upto(20) do |i|
      st.execute("slug #{i}", "#{i}")
    end
  end

end

运行时,它会在数据库中插入一行,然后它会出现以下错误:

/var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:41:in `bind_param': library routine called out of sequence (SQLite3::MisuseException)
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:41:in `bind_params'
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:37:in `each'
    from /var/lib/gems/1.8/gems/sqlite3-ruby-1.3.2/lib/sqlite3/statement.rb:37:in `bind_params'
    from /var/lib/gems/1.8/gems/dbd-sqlite3-1.2.5/lib/dbd/sqlite3/statement.rb:71:in `bind_params'
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/statement.rb:115:in `execute'
    from /media/dev/ruby-prax/moi.rb:12
    from /media/dev/ruby-prax/moi.rb:11:in `upto'
    from /media/dev/ruby-prax/moi.rb:11
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/database.rb:61:in `prepare'
    from /media/dev/ruby-prax/moi.rb:10
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi/handles/driver.rb:41:in `connect'
    from /var/lib/gems/1.8/gems/dbi-0.4.5/lib/dbi.rb:148:in `connect'
    from /media/dev/ruby-prax/moi.rb:5
TABLE slugs already exists.

目前我在Ubuntu 10.04上。 版本信息:

tlee@tim-ubuntu:/media/dev/ruby-prax$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]
tlee@tim-ubuntu:/media/dev/ruby-prax$ gem list

*** LOCAL GEMS ***

abstract (1.0.0)
daemons (1.1.0)
dbd-mysql (0.4.4)
dbd-odbc (0.2.5)
dbd-sqlite3 (1.2.5)
dbi (0.4.5)
deprecated (3.0.0, 2.0.1)
erubis (2.6.6)
eventmachine (0.12.10)
extlib (0.9.15)
json_pure (1.4.6)
mysql (2.8.1)
rack (1.2.1)
sqlite3-ruby (1.3.2)
thin (1.2.7)
thor (0.14.1)
tlee@tim-ubuntu:/media/dev/ruby-prax$ sqlite3 --version
3.6.22
tlee@tim-ubuntu:/media/dev/ruby-prax$ 

我做错了什么?

3 个答案:

答案 0 :(得分:3)

我遇到了同样的问题。当您多次使用准备好的INSERT语句时,有关于DBD失败的SQLite驱动程序的issue on github。就个人而言,由于Ruby / DBI显然不再被维护,我已经在回答RDBI的答案中采取了建议。迁移到RDBI需要非常少的代码更改。

答案 1 :(得分:1)

您的表定义是:

slugs(name varchar(20), age int);

但你想插入:

st.execute("slug #{i}", "#{i}")

请注意"#{i}"不是整数,而是字符串。将其更改为i,如下例所示:

st.execute("slug #{i}", i) 

然后看看会发生什么。

答案 2 :(得分:0)

我不知何故认为Ruby上的几个sqlite3库缺少语句类的重置和清除方法。

当重复执行相同的SQL语句时,会准备一次语句并使用一组新值执行。但是在执行语句之后并且在重新绑定之前,它需要被重置(并且经常被清除)。关键是重置已使用的语句比编译和优化"更快。同样的SQL一遍又一遍。大多数人可能都知道这一切......但这里是相关部分的SQLite文档的链接:

https://www.sqlite.org/c3ref/stmt.html

我没有在SQLite3 :: Statement类中看到重置和清除方法,所以这些可能会以某种方式错过此实现,或者在重用时有一些其他机制可以自动重置/清除,但是这种机制是某种方式没有触发。但是,文档中甚至没有提到它......至少我找不到它。

我认为SQLite3 :: Statement类中缺少clear_bindings和reset方法。

https://github.com/sparklemotion/sqlite3-ruby/issues/158