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]