首页 > 解决方案 > 字节 [] 上的休眠 @Lob 导致“long 类型的值错误”

问题描述

我试图byte[] content在 Spring Boot 下使用 Hibernate 懒惰地获取单个 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)
);

选择结果:

选择结果

使用版本:

PostgreSQL 10.4;springframework.boot 2.4.2;这个 Spring Boot 版本附带的休眠版本

标签: javapostgresqlhibernateblob

解决方案


bytea类型被内联到表中,而其他类型被分块到一个单独的表中,该表在 PostgreSQL 上称为 TOAST。为了访问这些值,数据库有一个通常被称为 LOB 定位器的概念,它本质上只是一个用于查找的 id。一些驱动程序/数据库只是以任何一种方式工作,但其他驱动程序/数据库可能需要匹配实际的物理表示。在您的情况下,使用@Lob是错误的,因为 AFAIKbytea被内联到一定大小并且 de-TOASTed 即在必要时在幕后自动物化。如果您使用的是 varbinary/blob 类型或类似的类型,则必须@Lob像在这种情况下那样使用,主表只包含这个长的 LOB 定位器。然后,驱动程序会知道您何时使用getBlob它必须执行一些select get_lob(?)查询来检索实际内容。


推荐阅读