chenxu8989 opened a new issue, #4393:
URL: https://github.com/apache/hertzbeat/issues/4393

   ### Is there an existing issue for this?
   
   - [x] I have searched the existing issues
   
   ### Current Behavior
   
   在 PostgreSQL 部署环境下调用 AI 对话相关接口(HertzBeat v1.9.0 自定义镜像,Spring 
profile=prod,Hibernate ddl-auto=update)会抛出 `JpaSystemException: Unable to 
access lob stream`,根因是 `org.postgresql.util.PSQLException: 
大型对象无法被使用在自动确认事物交易模式。`
   
   具体表现:
   
   - `POST /api/chat/stream`(`ConversationServiceImpl.streamChat`)在调用 
`messageDao.findByConversationIdOrderByGmtCreateAsc(...)` 
时失败,调用链:`ChatController.streamChat` → `ConversationServiceImpl.streamChat:95` → 
`$Proxy280.findByConversationIdOrderByGmtCreateAsc` → Hibernate 
`ClobJdbcType.doExtract` → `DataHelper.extractString` → 
`PgClob.getCharacterStream` → `AbstractBlobClob.getLo` → 
`LargeObjectManager.open`。
   - `GET 
/api/chat/conversations/{id}`(`ConversationServiceImpl.getConversation:187`)触发同样的异常。
   - 异常会被 `org.apache.hertzbeat.manager.support.GlobalExceptionHandler` 捕获并打印 
`[database error happen]-Unable to access lob stream`。
   
   ### Expected Behavior
   
   - AI 对话流式接口 `/api/chat/stream` 能正常返回 SSE 流式响应,不再抛 LOB 异常。
   - `/api/chat/conversations` 与 `/api/chat/conversations/{id}` 正常返回对话历史与消息列表。
   - 在 PostgreSQL 部署(`org.postgresql.Driver`)下不依赖事务包裹即可正确读取消息内容字段。
   
   ### Steps To Reproduce
   
   1. 启动使用 PostgreSQL 17 作为元数据库的 
HertzBeat(`spring.profiles.active=prod`,`driver-class-name=org.postgresql.Driver`,`jpa.hibernate.ddl-auto=update`,`flyway.enabled=false`)。
   2. 确认 `ChatMessage` 实体(`hzb_ai_message` 表)的 `content` 列在 PostgreSQL 上以 OID 
形式存在:
      ```sql
      \d hzb_ai_message
      -- Column  |       Type        | ...
      -- content | oid               |
      ```
      这是由 `ChatMessage.content` 上的 `@Lob` + `String` 在 Hibernate 
ddl-auto=update 下的默认映射(PostgreSQL 上 `@Lob String` → `oid`)。
   3. 通过已认证用户调用 AI 对话接口,先 POST `/api/chat/conversations` 创建会话,再 POST 
`/api/chat/stream` 发送一条消息:
      ```bash
      CONV_ID=$(curl -s -X POST http://localhost:1157/api/chat/conversations \
    -H 'Authorization: ...' | jq -r '.data.id')
      curl -N -X POST http://localhost:1157/api/chat/stream \
        -H 'Content-Type: application/json' \
        -H 'Authorization: ...' \
        -d "{\"message\":\"hello\",\"conversationId\":$CONV_ID}"
      ```
   4. 服务端 `hertzbeat` 容器日志抛出:
      ```
      org.postgresql.util.PSQLException: 大型对象无法被使用在自动确认事物交易模式。
    at 
org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:243)
        at org.postgresql.jdbc.AbstractBlobClob.getLo(AbstractBlobClob.java:272)
        at org.postgresql.jdbc.PgClob.getCharacterStream(PgClob.java:54)
        at 
org.hibernate.type.descriptor.java.DataHelper.extractString(DataHelper.java:254)
      ```
   5. 再调用 `GET /api/chat/conversations/$CONV_ID` 同样复现异常,调用栈指向 
`ConversationServiceImpl.getConversation:187`。
   
   ### Environment
   
   ```markdown
   HertzBeat version(s): hertzbeat 1.9.0
   - Spring profile: `prod`
   - 数据库: PostgreSQL 17(容器镜像 `pgvector/pgvector:pg17`)
   - JDBC: `jdbc:postgresql://postgres:5432/hertzbeat`
   - JPA / Hibernate: `ddl-auto=update`,`Flyway=enabled:false`
   ```
   
   ### Debug logs
   
   ```log
   [hertzbeat] | org.springframework.orm.jpa.JpaSystemException: Unable to 
access lob stream
   [hertzbeat] |   at 
org.springframework.orm.jpa.hibernate.HibernateExceptionTranslator.convertHibernateAccessException(HibernateExceptionTranslator.java:223)
   [hertzbeat] |   at 
org.springframework.orm.jpa.hibernate.HibernateExceptionTranslator.convertHibernateAccessException(HibernateExceptionTranslator.java:131)
   [hertzbeat] |   ...
   [hertzbeat] |   at 
jdk.proxy2/jdk.proxy2.$Proxy280.findByConversationIdOrderByGmtCreateAsc(Unknown 
Source)
   [hertzbeat] |   at 
org.apache.hertzbeat.ai.service.impl.ConversationServiceImpl.streamChat(ConversationServiceImpl.java:95)
   [hertzbeat] |   ...
   [hertzbeat] |   at 
org.apache.hertzbeat.ai.controller.ChatController.streamChat(ChatController.java:86)
   [hertzbeat] |   ...
   [hertzbeat] | Caused by: org.hibernate.HibernateException: Unable to access 
lob stream
   [hertzbeat] |   at 
org.hibernate.type.descriptor.java.DataHelper.extractString(DataHelper.java:261)
   [hertzbeat] |   at 
org.hibernate.type.descriptor.java.StringJavaType.wrap(StringJavaType.java:125)
   [hertzbeat] |   at 
org.hibernate.type.descriptor.java.StringJavaType.wrap(StringJavaType.java:26)
   [hertzbeat] |   at 
org.hibernate.type.descriptor.jdbc.ClobJdbcType$1.doExtract(ClobJdbcType.java:55)
   [hertzbeat] |   ...
   [hertzbeat] | Caused by: org.postgresql.util.PSQLException: 
大型对象无法被使用在自动确认事物交易模式。
   [hertzbeat] |   at 
org.postgresql.largeobject.LargeObjectManager.open(LargeObjectManager.java:243)
   [hertzbeat] |   at 
org.postgresql.jdbc.AbstractBlobClob.getLo(AbstractBlobClob.java:272)
   [hertzbeat] |   at 
org.postgresql.jdbc.PgClob.getCharacterStream(PgClob.java:54)
   [hertzbeat] |   at 
org.hibernate.type.descriptor.java.DataHelper.extractString(DataHelper.java:254)
   
   [hertzbeat] | 2026-09-21 10:57:54 [http-nio-1157-exec-7] WARN  
org.apache.hertzbeat.manager.support.GlobalExceptionHandler - [database error 
happen]-Unable to access lob stream
   [hertzbeat] | org.springframework.orm.jpa.JpaSystemException: Unable to 
access lob stream
   [hertzbeat] |   ...
   [hertzbeat] |   at 
jdk.proxy2/jdk.proxy2.$Proxy280.findByConversationIdOrderByGmtCreateAsc(Unknown 
Source)
   [hertzbeat] |   at 
org.apache.hertzbeat.ai.service.impl.ConversationServiceImpl.getConversation(ConversationServiceImpl.java:187)
   ```
   
   附注:
   - 在开发默认的 H2 数据库上无法复现,因为 H2 上 `@Lob String` 映射为 `CLOB`/`VARCHAR`,不走 
PostgreSQL 的 Large Object 路径。
   - 上游 Apache HertzBeat 
`hertzbeat-common-spring/src/main/java/org/apache/hertzbeat/common/entity/ai/ChatMessage.java:75`
 仍保留 `@Lob` 注解。截至当前 master(commit `307ef0d49`),相关 AI 
修复(#3911、#4208、#4280、#4315、#4317)均未触及 `@Lob`。
   - 期望根因:实体字段声明 `@Lob + String` 在 PostgreSQL 上被 Hibernate 映射为 OID(Large 
Object)。读取 Large Object 必须处于显式事务中,但 `streamChat`/`getConversation` 调用 
`messageDao.findByConversationIdOrderByGmtCreateAsc` 时不在事务上下文,PG JDBC 驱动拒绝读取,抛出 
`大型对象无法被使用在自动确认事物交易模式`。
   
   ### Anything else?
   
   - 相关 Issue / PR(已检索,均未解决此问题):
     - #3911 `[bugfix]: AI conversation message loading issue`(commit 
`aac5bafe4`,修复 LazyInitializationException,未触及 `@Lob`)
     - #4208 `fix(ai): correct conversation message handling`(commit 
`aee4fcc19`,修复 `conversationId` insertable 标志错误,未触及 `@Lob`)
     - #4280 `maintenance: scope AI conversations by creator`(多租户隔离,未触及 `@Lob`)
     - #4315 `fix(ai): create conversation when conversation ID is 
missing`(自动建会话,未触及 `@Lob`)
     - #4317 `fix(ai): persist parameters for scheduled skills`(调度任务参数,未触及 
`@Lob`)
   - 建议的修复方向(仅作参考,非强制):
     1. 将 `ChatMessage.content` 的 `@Lob` 改为 `@Column(columnDefinition = "TEXT", 
nullable = false)`,让 Hibernate 在 PostgreSQL 上映射为 `text` 而非 `oid`,绕过 Large 
Object 路径。
     2. 给 `ConversationServiceImpl.getConversation` 与 `getAllConversations` 加 
`@Transactional(readOnly = true)`(`streamChat` 不加,因为返回 `Flux`,事务会阻塞 SSE 流式推送并占用 
Hikari 连接池)。
     3. 由于 `ddl-auto=update` 不会自动把 `oid` 列降级为 `text`,需要在 PG 上手工执行一次 `ALTER 
TABLE hzb_ai_message ALTER COLUMN content TYPE TEXT USING content::text;`(OID 是 
PG 中的数字,可直接 cast 为 text)。
   - 自定义镜像 `hertzbeat-ext` 
的部署栈:`/home/chenxu/project/custom-monitoring/docker-stack/docker-compose.yaml` 
中 `hertzbeat` 服务,`profiles.active=prod`,`flyway.enabled=false`。
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: 
[email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to