通过DataMapper从SQLite内存数据库中出现“无此表”错误

5

我有一个使用DataMapper作为ORM与内存中的SQLite数据库通信的Ruby程序。这一直运行良好,但最近我添加了一个新的DM类和相应的表。令我惊讶的是,在auto_migrate期间出现了问题!

以下是由DataMapper生成的SQL:

~ (0.000390) PRAGMA table_info("sensationd_channels")
~ (0.000010) PRAGMA table_info("sensationd_commands")
~ (0.000009) PRAGMA table_info("sensationd_configurations")
~ (0.000052) PRAGMA table_info("sensationd_measurements")
~ (0.000028) SELECT sqlite_version(*)
~ (0.000035) DROP TABLE IF EXISTS "sensationd_channels"
~ (0.000009) PRAGMA table_info("sensationd_channels")
~ (0.000423) CREATE TABLE "sensationd_channels" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "channel" INTEGER NOT NULL, "name" VARCHAR(50), "precision" INTEGER DEFAULT 11, "gain" INTEGER DEFAULT 1, "differential" BOOLEAN DEFAULT 'f', "configuration_id" INTEGER NOT NULL)
~ (0.000191) CREATE INDEX "index_sensationd_channels_configuration" ON "sensationd_channels" ("configuration_id")
~ (0.000015) DROP TABLE IF EXISTS "sensationd_commands"
~ (0.000009) PRAGMA table_info("sensationd_commands")
~ (0.000153) CREATE TABLE "sensationd_commands" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "action" INTEGER DEFAULT 1, "complete" BOOLEAN DEFAULT 'f', "issued_at" TIMESTAMP, "completed_at" TIMESTAMP)
~ (0.000015) DROP TABLE IF EXISTS "sensationd_configurations"
~ (0.000009) PRAGMA table_info("sensationd_configurations")
~ (0.000155) CREATE TABLE "sensationd_configurations" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "created_on" TIMESTAMP, "modified_on" TIMESTAMP, "name" VARCHAR(50) NOT NULL, "active" BOOLEAN)
~ (0.000015) DROP TABLE IF EXISTS "sensationd_measurements"
~ (0.000009) PRAGMA table_info("sensationd_measurements")
~ (0.000152) CREATE TABLE "sensationd_measurements" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "timestamp" TIMESTAMP, "measurement" VARCHAR(65535) NOT NULL, "channel_id" INTEGER NOT NULL, "channel_configuration_id" INTEGER NOT NULL)
~ (0.000175) CREATE INDEX "index_sensationd_measurements_channel" ON "sensationd_measurements" ("channel_id", "channel_configuration_id")
~ (0.000083) SELECT "id", "created_on", "modified_on", "name", "active" FROM "sensationd_configurations" WHERE "active" = 't' ORDER BY "id" LIMIT 1
~ (0.000073) INSERT INTO "sensationd_configurations" ("created_on", "modified_on", "name", "active") VALUES ('2011-08-01T12:36:18-07:00', '2011-08-01T12:36:18-07:00', 'Test U6-Pro Configuration, differential.', 't')
~ (0.000109) SELECT "id", "action", "complete", "issued_at", "completed_at" FROM "sensationd_commands" ORDER BY "issued_at" DESC LIMIT 1
~ (0.000086) INSERT INTO "sensationd_channels" ("channel", "name", "precision", "gain", "differential", "configuration_id") VALUES (0, '0', 11, 0, 't', 1)
~ no such table: sensationd_commands (code: 1, sql state: , query: SELECT "id", "action", "complete", "issued_at", "completed_at" FROM "sensationd_commands" ORDER BY "issued_at" DESC LIMIT 1, uri: sqlite3::memory:?scheme=sqlite&user=&password=&host=&port=&query=&fragment=&adapter=sqlite3&path=:memory:)

看起来创建表格的过程没问题,但是在几行之后就找不到表格了。我认为这可能是由于我配置错误的数据库连接,但是其他的表格都可以找到并且正常工作。
相关软件版本:
- Ruby 1.9.2p289(通过 RVM 安装) - SQLite3 @3.7.7.1(通过 MacPorts 安装) - DataMapper gem v 1.1.0
有没有人知道这是什么问题,以及我能做什么来解决它?

1
我一直遇到同样的问题,但是没有找到解决方案 :( - Ben Crouse
在我的情况下,在进一步测试后,看起来可能是一个线程问题。在创建表后立即在新线程中过快地访问表似乎会导致DataMapper发出使SQLite感到不适的SQL。将第二个线程中的数据库访问稍后移动可以使其正常工作,尽管两种情况下记录的SQL序列都有效。 - Aaron
2个回答

4
问题出在线程池上,这是 DataMapper(或更确切地说是 DataObjects,DataMapper 使用的数据库驱动程序)自动完成的。数据库连接不会在线程之间共享。对于像 postgresql、mysql 或甚至 sqlite3 这样的“文件支持”的数据库来说,这很好(甚至有益)。但对于 sqlite3 的内存存储来说,连接就等同于数据库本身。因此,为此增加的线程将因此失败。另外,经过一段不活动时间(约 1 分钟?),线程将被清除且数据库也将消失。
如果问题在此处,我不确定是否有简单的解决方法。您可能可以修改 do_sqlite3 来避免此问题。另一种基本上与其速度相当的替代方案是,在 ramdrive 上使用一个文件支持的 sqlite3 数据库。

这听起来很有可能。我今天将进行测试,通过返回“有问题”的数据库访问模式,然后在内存和磁盘存储之间进行切换。 - Aaron
我不能绝对肯定这是问题所在,但如果我将所有其他代码保持不变,并从内存存储切换到磁盘存储,则问题确实会消失。感谢您的帮助! - Aaron
1
虽然有点晚了,但或许可以帮到某些人。你可以使用特殊的文件名 file::memory:?cache=shared 来使用内存 SQLite 共享缓存。这样可以让不同的数据库连接共享同一个内存数据库。https://www.sqlite.org/inmemorydb.html - Robertiano
@Robertiano,你应该将这个作为额外的回答写下来。这是这里最有价值的评论。 - Lukas_Skywalker

3

我按照@Lukas_Skywalker的建议将我的评论复制为答案。

虽然有些晚了,但也许能帮到某些人。您可以使用内存SQLite共享缓存,使用特殊文件名file::memory:?cache=shared。这允许单独的数据库连接共享相同的内存数据库。sqlite.org/inmemorydb.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接