使用 Marshal 将 Sqlite 内存数据库转储到磁盘

Dump a Sqlite memory database to disk with Marshal

我想使用 Marshal 将 Sqlite 内存数据库转储到磁盘,但出现以下错误,这里是完整测试。用于保存在内存数据库中的 Sqlite API 似乎只能在 C 中使用。

require 'sqlite3'
require 'active_record'

ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:database  => ":memory:"
)

ActiveRecord::Schema.define do
  create_table :tests do |table|
    table.column :word, :string
  end
end

class Test < ActiveRecord::Base;end
Test.create(word: 'test')

puts Test.all.length
c = ::ActiveRecord::Base.connection
File.open('sqlite_db.marshal','wb') { |f| f.write(Marshal.dump(c)) }
# => error `dump': can't dump hash with default proc (TypeError)

可以使用sqlite3的Backup class.

# populate ActiveRecord here...

sdb = ::ActiveRecord::Base.connection.raw_connection

ddb = SQLite3::Database.new('backup.sqlite3')

b = SQLite3::Backup.new(ddb, 'main', sdb, 'main')
b.step(-1)
b.finish

目前我使用以下方法,它不是我问题的正确答案,所以我将保持打开状态,也许有人确实使用 Marshal 找到了解决方案 在这里,我打开第二个到磁盘数据库的连接,并在前后加载和写入该连接。

require 'sqlite3'
require 'active_record'

class Test < ActiveRecord::Base
  establish_connection(
    :adapter  => "sqlite3",
    :database => ":memory:"
  )
end

class Test2 < ActiveRecord::Base
  establish_connection(
    :adapter  => "sqlite3",
    :database => "testing.db"
  )
  self.table_name    = :tests
end

def db_load
  ActiveRecord::Schema.define do
    @connection = Test.connection
    create_table :tests do |table|
      table.column :word, :string
    end
  end
  Test2.all.each do |m|
    Test.create m.attributes
  end
end

def db_write
  Test2.delete_all
  Test.all.each do |m|
    Test2.create m.attributes
  end
end

def db_test klasse
  klasse.all.each do |record|
    p record
  end
end

db_load
db_test Test
Test.create(word: 'test3')
db_write
db_test Test2

给予

-- create_table(:tests)
   -> 0.0060s
#<Test id: 1, word: "test">
#<Test id: 2, word: "test2">
#<Test2 id: 1, word: "test">
#<Test2 id: 2, word: "test2">
#<Test2 id: 3, word: "test3">

这里是 Max 提出的技术示例。 它不是使用 Marshal 也不是用于 Activerecord 而是 ussefull,所以这里供参考

require 'sqlite3'
require 'active_record'

ActiveRecord::Base.establish_connection(:adapter => "sqlite3",:database  => ":memory:")

sdb = SQLite3::Database.new(':memory:')

sdb.execute "CREATE TABLE IF NOT EXISTS Cars(Id INTEGER PRIMARY KEY, Name TEXT, Price INT)"
sdb.execute "INSERT INTO Cars VALUES(1,'Audi',52642)"
sdb.execute "INSERT INTO Cars VALUES(2,'Mercedes',57127)"
sdb.execute "INSERT INTO Cars VALUES(3,'Skoda',9000)"
sdb.execute "INSERT INTO Cars VALUES(4,'Volvo',29000)"
sdb.execute "INSERT INTO Cars VALUES(5,'Bentley',350000)"
sdb.execute "INSERT INTO Cars VALUES(6,'Citroen',21000)"
sdb.execute "INSERT INTO Cars VALUES(7,'Hummer',41400)"
sdb.execute "INSERT INTO Cars VALUES(8,'Volkswagen',21600)"


ddb = SQLite3::Database.new('backup.sqlite3')

b = SQLite3::Backup.new(ddb, 'main', sdb, 'main')
b.step(-1)
b.finish

stm = ddb.prepare "SELECT * FROM Cars LIMIT 5" 
rs = stm.execute 

rs.each do |row|
  puts row.join "\s"
end

给予

1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000

此处基于最大编辑答案的最终解决方案供参考和完整性

require 'sqlite3'
require 'active_record'

ActiveRecord::Base.establish_connection(
  :adapter => "sqlite3",
  :database  => ":memory:"
)

ActiveRecord::Schema.define do
  create_table :tests do |table|
    table.column :word, :string
    table.column :index, :string
  end
end

class Test < ActiveRecord::Base;end
Test.create(word: 'test', index: 0)
Test.create(word: 'test2', index: 1)

sdb = ::ActiveRecord::Base.connection.raw_connection
ddb = SQLite3::Database.new('backup_sqlite3.db')

backup = SQLite3::Backup.new(ddb, 'main', sdb, 'main')
backup.step(-1)
backup.finish

ddb.execute("select * from tests").each do |record|
  p record
end