You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+Liquibase中SQL脚本读取Classpath文件失败问题咨询

解决PostgreSQL通过pg_read_binary_file读取Spring Boot classpath文件失败的问题

问题场景

使用Kotlin开发Spring Boot应用,通过Liquibase执行SQL迁移与数据填充。已创建maps表及对应SavedMapEntity实体类,在changelog脚本调用的SQL插入文件中,尝试用pg_read_binary_file读取classpath:liquibase/map/下的文件时,PostgreSQL报文件不存在错误,但该文件确实存在于resources/liquibase/map目录。

相关代码

创建表脚本

CREATE TABLE maps (
   id            BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL PRIMARY KEY,
   camera_map    OID                                     NOT NULL
);

Kotlin实体类

@Entity
@Table(
name = "maps", schema = "fleet",
)
class SavedMapEntity : BaseEntity() {

@Lob
@Basic(fetch = FetchType.LAZY)
@Column(name = "camera_map", nullable = false)
var cameraMap: Blob? = null

}

Liquibase Changelog脚本

<changeSet id="11-map-v_1.0.0_00006" author="fleet_management">
    <sqlFile path="liquibase/sql/script/v1/11-map/v_1.0.0_000006_insert_map.sql"
             splitStatements="false"/>
    <comment>
        Add default sim floor, department, and map
    </comment>
</changeSet>

插入数据SQL示例

DO
$$
DECLARE
    temp_camera_map    bytea;
    temp_camera_map_oid     oid;
BEGIN

    temp_camera_map := pg_read_binary_file('classpath:liquibase/camera_map')::bytea;

    temp_camera_map_oid :=
            lo_import('/tmp/temp_camera_map.bin');

    INSERT INTO maps (camera_map)
    VALUES (temp_image_oid);

END
$$;

错误信息

Caused by: org.postgresql.util.PSQLException: ERROR: could not open file "classpath:liquibase/map/sim_occupancy_map" for reading: No such file or directory

问题原因

  1. pg_read_binary_file的局限性:该函数是PostgreSQL服务器端函数,仅能读取数据库服务器本地文件系统的文件,无法识别Spring Boot的classpath:路径——这个路径是应用层面的资源定位符,数据库服务器无法解析访问。
  2. SQL变量错误:示例SQL中使用了未定义的temp_image_oid变量,正确应为temp_camera_map_oid。

解决方案

方案1:利用Liquibase读取classpath资源并插入

Liquibase可直接访问classpath资源,无需依赖数据库服务器读取文件。通过Liquibase的函数将文件转成Base64,再在SQL中解码为bytea,最后创建大对象插入:

<changeSet id="insert-map-fixed" author="fleet_management">
    <!-- 定义classpath下的文件路径 -->
    <property name="mapFilePath" value="classpath:liquibase/map/sim_occupancy_map" dbms="postgresql"/>
    <sql>
        DO
        $$
        DECLARE
            temp_camera_map bytea := decode('${base64Encode(mapFilePath)}', 'base64');
            temp_camera_map_oid oid;
        BEGIN
            -- 直接从bytea创建大对象,无需临时文件
            temp_camera_map_oid := lo_from_bytea(0, temp_camera_map);
            INSERT INTO maps (camera_map) VALUES (temp_camera_map_oid);
        END
        $$;
    </sql>
</changeSet>

方案2:将文件复制到数据库服务器可访问路径(不推荐)

若坚持使用pg_read_binary_file,需将resources/liquibase/map/下的文件复制到数据库服务器本地文件系统(如PostgreSQL数据目录/var/lib/postgresql/data/,需确保权限),然后修改SQL中的路径为服务器绝对路径:

temp_camera_map := pg_read_binary_file('/var/lib/postgresql/data/sim_occupancy_map')::bytea;

此方法灵活性差,换环境需重复操作,不适用于多环境部署场景。

方案3:修正SQL变量错误

无论采用哪种方案,需先将SQL中的temp_image_oid替换为temp_camera_map_oid,避免变量未定义错误。

内容的提问来源于stack exchange,提问作者Burak Dağlı

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:27:03