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

时间:2015-03-18 11:05:11

标签: ruby database activerecord serialization sqlite

我想将一个Sqlite内存数据库转储到带有Marshal的磁盘但是得到下面的错误,这里是完整的测试。用于保存在内存数据库中的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)

4 个答案:

答案 0 :(得分:1)

您可以使用sqlite3的Backup类。

# 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

答案 1 :(得分:0)

目前我使用以下方法,它是我的问题的正确答案,所以我将其打开,也许有人确实找到使用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">

答案 2 :(得分:0)

这是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

答案 3 :(得分:0)

这里是基于Max编辑的答案的最终解决方案的参考和完整性

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