byte[] 上的休眠 @Lob 导致 "Bad value for type long"
Hibernate @Lob on byte[] causes "Bad value for type long"
我正在尝试在 Spring 引导下使用 Hibernate 延迟获取单个 byte[] content
java 属性,访问 PostgreSQL 数据库。所以我把测试应用程序放在一起测试不同的解决方案。其中之一要求我在 属性 上使用 @Lob
注释,所以我做到了。现在从数据库中读取实体会导致非常奇怪的错误,准确地说:
Bad value for type long : \x454545454545445455
值 \x45...
是 bytea 列的值而不是 bigint 列的值,为什么它试图强制它进入 long,即使它是错误的列?为什么一列上的注释会以某种方式影响另一列?
至于修复,删除 @Lob
似乎有效(至少在我的堆栈中),但问题对我来说仍然无法解释,我想知道发生了什么,而不是盲目地继续前进。是错误还是我完全误解了什么?
实体:
@Entity
@Table(name = "blobentity")
public class BlobEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob //this annotation breaks code
@Column(name = "content")
@Basic(fetch = FetchType.LAZY)
private byte[] content;
@Column(name = "name")
private String name;
//getters/setters
}
存储库:
@Repository
public interface BlobRepo extends JpaRepository<BlobEntity, Long> {
}
调用代码:
@Autowired
BlobRepo blobrepo;
@GetMapping("lazyBlob")
public String blob () {
var t = blobrepo.findAll().get(0);
var name = t.getName();
var dataAccessedIfLazy = t.getContent();
return t.getName();
}
Postgres DDL:
CREATE TABLE test.blobentity (
id bigserial NOT NULL DEFAULT nextval('test.blobentity_id_seq'::regclass),
"name" varchar NULL,
"content" bytea NULL,
CONSTRAINT blobentity_pk PRIMARY KEY (id)
);
Select 结果:
使用的版本:
PostgreSQL 10.4; springframework.boot2.4.2;此 spring 引导版本
附带的休眠版本
bytea
类型被内联到 table 而其他类型被分块到一个单独的 table 中,在 PostgreSQL 上称为 TOAST。为了访问这些值,数据库有一个通常称为 LOB 定位器的概念,它本质上只是一个用于查找的 ID。有些 drivers/databases 两种方式都可以,但其他人可能需要匹配实际的物理表示。在您的情况下,使用 @Lob
是错误的,因为 AFAIK bytea
被内联到一定大小并被反烤,即如有必要会在幕后自动实现。如果您使用 varbinary/blob 类型或类似类型,则必须使用 @Lob
,因为在这种情况下,主 table 仅包含此 LOB 定位器,它很长。然后,当您使用 getBlob
请求值时,驱动程序知道它必须执行一些 select get_lob(?)
查询以检索实际内容。
我正在尝试在 Spring 引导下使用 Hibernate 延迟获取单个 byte[] content
java 属性,访问 PostgreSQL 数据库。所以我把测试应用程序放在一起测试不同的解决方案。其中之一要求我在 属性 上使用 @Lob
注释,所以我做到了。现在从数据库中读取实体会导致非常奇怪的错误,准确地说:
Bad value for type long : \x454545454545445455
值 \x45...
是 bytea 列的值而不是 bigint 列的值,为什么它试图强制它进入 long,即使它是错误的列?为什么一列上的注释会以某种方式影响另一列?
至于修复,删除 @Lob
似乎有效(至少在我的堆栈中),但问题对我来说仍然无法解释,我想知道发生了什么,而不是盲目地继续前进。是错误还是我完全误解了什么?
实体:
@Entity
@Table(name = "blobentity")
public class BlobEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Lob //this annotation breaks code
@Column(name = "content")
@Basic(fetch = FetchType.LAZY)
private byte[] content;
@Column(name = "name")
private String name;
//getters/setters
}
存储库:
@Repository
public interface BlobRepo extends JpaRepository<BlobEntity, Long> {
}
调用代码:
@Autowired
BlobRepo blobrepo;
@GetMapping("lazyBlob")
public String blob () {
var t = blobrepo.findAll().get(0);
var name = t.getName();
var dataAccessedIfLazy = t.getContent();
return t.getName();
}
Postgres DDL:
CREATE TABLE test.blobentity (
id bigserial NOT NULL DEFAULT nextval('test.blobentity_id_seq'::regclass),
"name" varchar NULL,
"content" bytea NULL,
CONSTRAINT blobentity_pk PRIMARY KEY (id)
);
Select 结果:
使用的版本:
PostgreSQL 10.4; springframework.boot2.4.2;此 spring 引导版本
附带的休眠版本bytea
类型被内联到 table 而其他类型被分块到一个单独的 table 中,在 PostgreSQL 上称为 TOAST。为了访问这些值,数据库有一个通常称为 LOB 定位器的概念,它本质上只是一个用于查找的 ID。有些 drivers/databases 两种方式都可以,但其他人可能需要匹配实际的物理表示。在您的情况下,使用 @Lob
是错误的,因为 AFAIK bytea
被内联到一定大小并被反烤,即如有必要会在幕后自动实现。如果您使用 varbinary/blob 类型或类似类型,则必须使用 @Lob
,因为在这种情况下,主 table 仅包含此 LOB 定位器,它很长。然后,当您使用 getBlob
请求值时,驱动程序知道它必须执行一些 select get_lob(?)
查询以检索实际内容。