【问题标题】:Dump a Sqlite memory database to disk with Marshal使用 Marshal 将 Sqlite 内存数据库转储到磁盘
【发布时间】:2015-05-21 03:19:06
【问题描述】:

我想用 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)

【问题讨论】:

    标签: ruby database activerecord serialization sqlite


    【解决方案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
    

    【讨论】:

    • 适用于常规 sqlite,谢谢,但我想从我的示例中转储 activerecord 数据库
    • ::ActiveRecord::Base.connection 不检索底层 sqlite3 数据库连接吗?
    • 然后我得到了我的问题中的错误,我不能接受你的回答,因为它没有使用 Marshal,目前我使用一个解决方案,我将在这里发布作为答案,但我由于同样的原因,也不能接受
    • 我的意思是:您不能将问题中代码中的c 用作我的答案中的sdb 吗?还是c 不是sqlite3 数据库连接?我知道您的问题要求使用 Marshal,但这对我来说似乎是个坏主意。 SQLite 和 Marshal 都是设计用于在磁盘上保存/加载数据的工具。混合它们应该是不必要的,只是自找麻烦。
    • @peter 我发现了问题。您需要使用raw_connection 来获取 sqlite3 连接。然后我的答案有效。我已经对其进行了编辑以反映这一点。
    【解决方案2】:

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

    【讨论】:

    • 请使用您问题上的编辑链接添加更多信息。 Post Answer 按钮应仅用于问题的完整答案。
    • 那会很混乱,不是吗,而且如果没有更好的出现,这是一个可能的答案,所以我不同意
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      此处以供参考和完善基于 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-29
        • 2018-08-03
        • 1970-01-01
        • 1970-01-01
        • 2012-03-24
        • 1970-01-01
        • 2011-03-13
        • 1970-01-01
        相关资源
        最近更新 更多