PostgreSQL里存储二进制类型有两种:bytea类型或lo(Large Object)类型
bytea类型存储列要小于1GB
lo扩展类型可参考:
http://www.postgres.cn/docs/11/lo.html
byte类型测试
创建表结构
postgres=# create table test_bytea(id int,info bytea);
生成1GB文件
postgres=# \! dd if=/dev/zero of=test_bytea bs=1k count=1048576 && sync
1048576+0 records in
1048576+0 records out
1073741824 bytes (1.1 GB) copied, 3.42339 s, 314 MB/s
文件入库
postgres=# insert into test_bytea values(1,pg_read_binary_file('/home/postgres/test_bytea'));
ERROR: requested length too large
生成文件稍小于1GB
postgres=# \! dd if=/dev/zero of=test_bytea bs=1k count=1048575 && sync
1048576+0 records in
1048576+0 records out
1073741824 bytes (1.1 GB) copied, 3.42339 s, 314 MB/s
入库测试
postgres=# insert into test_bytea values(1,pg_read_binary_file('/home/postgres/test_bytea'));
INSERT 0 1
JDBC-Java文件入库
public static void main(String[] args) throws Exception{
File file = new File("c:/work/movie.mkv");//文件大小不超过1G
FileInputStream fis = new FileInputStream(file);
Class.forName("org.postgresql.Driver");
Connection con = DriverManager.getConnection("jdbc:postgresql://192.168.99.223:6000/postgres","XXX","XXX");
PreparedStatement ps = con.prepareStatement("insert into test_bytea values (2,?)");
ps.setBinaryStream(1, fis, (long)file.length());
ps.execute();
con.close();
}
JDBC-Java读数据输出到文件
public static void main(String[] args) throws Exception{
Class.forName("org.postgresql.Driver");
Connection con = DriverManager.getConnection("jdbc:postgresql://192.168.99.223:6000/postgres","XXX","XXX");
PreparedStatement ps = con.prepareStatement("select info from test_bytea where id=2;");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
OutputStream ops = null;
InputStream ips = null;
File file = new File("c:/work/out.mkv");
ips = rs.getBinaryStream(1);
byte[] buffer = new byte[1024*1024];
ops = new FileOutputStream(file);
for (int i; (i = ips.read(buffer)) > 0;)
{
ops.write(buffer, 0, i);
ops.flush();
}
ops.close();
}
con.close();
}
lo类型测试
创建扩展及表结构
postgres=# create extension lo;
postgres=# create table test_lo(id int,info lo);
创建管理触发器
postgres=# create trigger test_lo before UPDATE OR DELETE ON test_lo FOR EACH ROW EXECUTE FUNCTION lo_manage(info);
需要建立触发器使用lo_manage进行管理,以免形成孤立大对象
生成2G文件
postgres=# \! dd if=/dev/zero of=test_lo bs=1M count=2048 && sync
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 2.21557 s, 969 MB/s
文件入库
postgres=# insert into test_lo values(1,lo_import('/home/postgres/test_lo'));
导出lo文件
postgres=# select lo_export(test_lo.info,'/home/postgres/test_ext_lo') from test_lo where id=1;
lo_export
-----------
1
(1 row)
postgres=# \! ls -lh test_ext_lo
-rw-r--r-- 1 postgres postgres 2.0G Mar 3 18:22 test_ext_lo
lo类型原生表只存储一个oid作为引用指针,并不实际存数据
postgres=# \dt pg_largeobject*
List of relations
Schema | Name | Type | Owner
------------+-------------------------+-------+----------
pg_catalog | pg_largeobject | table | postgres
pg_catalog | pg_largeobject_metadata | table | postgres
(2 rows)
pg_largeobject_metadata存储lo类型的元数据信息,包括类型的宿主和访问权限
postgres=# \d pg_largeobject_metadata
Table "pg_catalog.pg_largeobject_metadata"
Column | Type | Collation | Nullable | Default
----------+-----------+-----------+----------+---------
oid | oid | | not null |
lomowner | oid | | not null |
lomacl | aclitem[] | | |
Indexes:
"pg_largeobject_metadata_oid_index" UNIQUE, btree (oid)
pg_largeobject存储实际数据,最终使用byeta类型
postgres=# \d pg_largeobject
Table "pg_catalog.pg_largeobject"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
loid | oid | | not null |
pageno | integer | | not null |
data | bytea | | not null |
Indexes:
"pg_largeobject_loid_pn_index" UNIQUE, btree (loid, pageno)
lo类型使用注意事项
需要创建触发器,对update和delete操作使用lo_manage函数管理,不然会产生孤立大对象。
保持联系
从2019年12月开始写第一篇文章,分享的初心一直在坚持,本人现在组建了一个PG乐知乐享交流群,欢迎关注我文章的小伙伴进群吹牛唠嗑,交流技术,互赞文章。
如果群二维码失效可以加我微信。
最后修改时间:2022-10-23 10:29:28
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。