我需要在我的rails应用程序中保存db中的大对象。我认为我可以在SQL中创建一个表
CREATE TABLE files (
id serial NOT NULL,
name string NOT NULL,
blob_oid oid NUT NULL
)
然后将数据存储在Ruby中
conn.exec("BEGIN")
lo = conn.lo_import(data)
conn.exec("COMMIT")
file = File.new
file.name = file_name; file.blob_oid = lo.id
file.save
首先,这是正确的吗?其次,我如何描述File in Rails的模型。 Rails中Friend.blob_oid
的数据类型是什么?我可以使用Rails中的迁移创建文件表吗?
答案 0 :(得分:5)
如果将Rails附带的ActiveRecord与其中一个适配器一起使用,则数据库类型到Rails或Ruby类型的唯一正式映射通常在适配器中的NATIVE_DATABASE_TYPES
常量中定义,该常量通过其{返回{1}}方法。对于Rails 3.2.x中的PostgreSQL,它位于native_database_types
here。因此,对于该适配器,Rails中的“二进制”类型映射到PG中的“bytea”类型。对于某些类型,您可以使用名为activerecord-native_db_types_override的gem覆盖它映射到的数据库类型。但是,我们想要使用大型对象,所以......
<强>迁移强>
正如Jim Deville在评论中指出的那样,您可以在表格中指定自定义类型列,如:
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
如果您需要执行更多非标准操作,您还可以使用t.column :some_oid, 'blob_oid', :null => false
使用直接SQL创建表。并且,如果您有在迁移之外进行的现有旧架构或SQL更改,请考虑在execute("SQL GOES HERE;")
中使用structure.sql(config.active_record.schema_format = :sql
选项,然后执行:config/application.rb
)。
大对象读/写/检查长度/删除
复制了一些修改澄清等更新:我们可以但不需要在lo_read / lo_write / lo_lseek之前放置一个begin,并且在asse {block}中执行lo_close,因为每个PG documentation“剩下的任何大对象描述符在交易结束时打开将自动关闭。“ (感谢Diogo提供的信息)
rake db:structure:dump
使用模型或基础中的原始连接,而不是 require 'pg'
...
def read
(...).transaction do
lo = connection.lo_open(identifier)
content = connection.lo_read(lo, file_length)
connection.lo_close(lo)
content
end
end
def write(file)
(...).transaction do
lo = connection.lo_open(identifier, ::PG::INV_WRITE)
size = connection.lo_write(lo, file.read)
connection.lo_close(lo)
size
end
end
def delete
connection.lo_unlink(identifier)
end
def file_length
(...).transaction do
lo = connection.lo_open(identifier)
size = connection.lo_lseek(lo, 0, 2)
connection.lo_close(lo)
size
end
end
,例如connection
(见this)。
ActiveRecord::Base.connection.raw_connection
正在模型或基础上调用事务,例如(...).transaction
(见this)。
ActiveRecord::Base.transaction
是您需要传入/设置或从仅执行identifier
获取的oid。
其他例子/信息:
后者和一些答案here表明您可能需要考虑与数据库分开存储大型文件,例如:这样您就可以使用云存储了。但是,如果仅将路径/ ID存储到由DB管理的非的外部文件,则会丢失ACID一致性(一个或多个DB记录可能指向一个或多个不存在的文件或可能存在一个或多个文件,这些文件在数据库中没有一个或多个关联的记录。在文件系统上存储文件的另一个参数是你可以流文件,但是PG大对象以postgres管理的方式在文件系统上存储文件,以确保ACID一致性并允许流式传输(你不能用普通的BLOB做) / Rails二进制类型)。所以,这取决于;有些人发现使用路径引用存储在单独的存储中是一个更好的选择,有些人更喜欢通过大对象实现ACID一致性。
轻松的方式