PostgreSQL 的大对象(Large Object)操作

PostgreSQL 的大对象(Large Object)操作

shell 复制代码
-- 查看所有大对象的 OID 和创建时间
SELECT oid, lomowner, lomacl
FROM pg_largeobject_metadata;

-- 删除大对象
SELECT lo_unlink(oid);

-- 查看大对象元数据
SELECT * FROM pg_largeobject_metadata;

-- 查看大对象的实际数据块(通常很大,不建议全量查询)
SELECT * FROM pg_largeobject WHERE loid = 12345; -- 替换为实际的大对象OID

-- 查看单个表的大小(包含索引和相关对象)
SELECT pg_size_pretty(pg_total_relation_size('表名'));

springboot 整合 PostgreSQL 的大对象(Large Object)操作

java 复制代码
package com.huayi.iepms.common.utils.pg;

import org.postgresql.largeobject.LargeObject;
import org.postgresql.largeobject.LargeObjectManager;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * PostgreSQL大对象工具类
 * @author: zrf
 * @date: 2025/08/25 16:09
 */
@Component
public class PostgresLargeObjectUtil {

    private final JdbcTemplate jdbcTemplate;

    public PostgresLargeObjectUtil(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 从输入流创建大对象并返回OID
     */
    @Transactional
    public long createLargeObject(InputStream inputStream) throws SQLException {
        // 获取数据库连接并关闭自动提交
        Connection connection = jdbcTemplate.getDataSource().getConnection();
        connection.setAutoCommit(false);

        try {
            // 获取PostgreSQL大对象管理器
            LargeObjectManager lobjManager = connection.unwrap(org.postgresql.PGConnection.class)
                    .getLargeObjectAPI();

            // 创建大对象,返回OID
            long oid = lobjManager.createLO(LargeObjectManager.READ | LargeObjectManager.WRITE);

            // 打开大对象并写入数据
            try (LargeObject largeObject = lobjManager.open(oid, LargeObjectManager.WRITE)) {
                OutputStream outputStream = largeObject.getOutputStream();
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }

            connection.commit();
            return oid;
        } catch (Exception e) {
            connection.rollback();
            throw new SQLException("创建大对象失败", e);
        } finally {
            connection.close();
        }
    }

    /**
     * 根据OID读取大对象内容到输出流
     */
    @Transactional(readOnly = true)
    public void readLargeObject(long oid, OutputStream outputStream) throws Exception {
        Connection connection = jdbcTemplate.getDataSource().getConnection();
        
        try {
            LargeObjectManager lobjManager = connection.unwrap(org.postgresql.PGConnection.class)
                    .getLargeObjectAPI();

            try (LargeObject largeObject = lobjManager.open(oid, LargeObjectManager.READ)) {
                InputStream inputStream = largeObject.getInputStream();
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        } finally {
            connection.close();
        }
    }

    /**
     * 删除大对象(释放磁盘空间)
     */
    @Transactional
    public void deleteLargeObject(long oid) throws SQLException {
        Connection connection = jdbcTemplate.getDataSource().getConnection();
        connection.setAutoCommit(false);
        
        try {
            LargeObjectManager lobjManager = connection.unwrap(org.postgresql.PGConnection.class)
                    .getLargeObjectAPI();
            lobjManager.delete(oid);
            connection.commit();
        } catch (Exception e) {
            connection.rollback();
            throw new SQLException("删除大对象失败", e);
        } finally {
            connection.close();
        }
    }
}