前言
通常来说在关系型数据库中保存大对象有如下方式:
- 使用Blob或者Clob类型的字段,将大对象的内容保存到数据表中。
- 将大对象保存为文件放置到文件系统中。数据表只保存指向该文件系统的路径。
PG中没有提供MySQL或者Oracle中的Blob,Clob类型的字段。但PG提供的大对象处理方式简化了上述的方法2,无需人工去上传文件到文件系统然后再保存路径。将大对象直接上传到PG后,该对象本身的存储和生成该对象引用的过程无需使用者再费心。
接下来为大家介绍PG操作大对象的方式。
上传大对象
SELECT lo_from_bytea(%s, %s::bytea) as loid;
其中第一个参数为loid(Large object ID)。如果设定为0,则使用一个空闲的loid并返回。
第二个参数为大对象的byte数组。
获取大对象
SELECT lo_get(%s) as "data";
需要的参数为loid,即第一步上传大对象返回的结果。
删除大对象
SELECT lo_unlink(%s);
参数为loid。
返回1表示删除成功,-1表示删除失败。
查询PG中保存的所有大对象
select * from pg_largeobject;
该表包含如下字段:
- loid: 大对象的id。
- pageno: 保存大对象的页数。
- data: 大对象的数据(字节数组)。
通过如下语句可以查询到大对象的元数据:
select * from pg_largeobject_metadata;
该表包含如下字段:
- oid: 大对象的id。
- lomowner: 大对象的属主。
- locacl: 大对象的ACL(访问控制列表,权限相关)。
使用示例
首先使用lo_from_bytea函数上传大对象到pg。例如:
select lo_from_bytea(0, '\xffffff00')
该SQL执行成功之后会返回上传大对象的id(loid)。
这个ID相当于该大对象的身份信息,即以后查询,修改或者删除该大对象都要使用该ID。因此需要将他保存在业务表当中。
例如我们上传的大对象为文件内容。我们有如下文件表:
CREATE TABLE file (
create_time timestamptz NOT NULL,
update_time timestamptz NOT NULL,
id uuid NOT NULL,
file_name varchar(256) NOT NULL,
loid int4 NOT NULL,
meta jsonb NOT NULL
);
在上传完大对象之后,需要将返回的loid值保存在file表的loid字段中。
其他操作大对象的函数
- lo_put ( loid oid, offset bigint, data bytea ) → void:从offset处开始写入数据。如果新写入的数据比原来大对象从offset到结尾的数据量要大,大对象会自动扩大
- lo_get ( loid oid [, offset bigint, length integer ] ) → bytea:从offset出读取数据,读取长度为length。
- lo_creat( loid oid ) → oid:新建一个空的大对象。返回大对象的oid。如果传入的参数为
-1,则系统自动指定一个空闲的loid,然后返回。 - lo_import ( filename text ) → oid:导入PG服务器上的某个文件到PG,返回该大对象的oid。注意事项:因为涉及到服务器上数据的读写。因此不建议赋予普通用户使用该函数的权限。
- lo_export ( loid oid, filename text ) → int:导出大对象夫到PG服务器上指定文件,返回导出文件的长度。注意事项同上。