【问题标题】:Lazy fetching single column (class attribute) with Hibernate使用 Hibernate 延迟获取单列(类属性)
【发布时间】:2012-07-16 14:18:28
【问题描述】:

我正在使用一张旧表,如下所示:

+------------------+--------------+------+-----+---------+-------+
| Field            | Type         | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+-------+
| BINARY_DATA_ID   | varchar(255) | NO   | PRI |         |       |
| BINARY_DATA      | longblob     | YES  |     | NULL    |       |
| BINARY_DATA_NAME | varchar(255) | YES  |     | NULL    |       |
+------------------+--------------+------+-----+---------+-------+

主要问题是BinaryData Java 类加载了BINARY_DATA 列,即使我只需要BINARY_DATA_NAME。我知道构建此架构的最佳方法是将数据从元数据(如文件名)中拆分出来,以便它们存在于单独的表中。从那里开始,使数据延迟加载是微不足道的。一开始就应该这样做。

很遗憾,由于组织限制,我可能无法执行上述操作。作为一种解决方法,是否可以使用一些注释使该列延迟加载,而不是将内容拆分到单独的表中?我修改了BinaryData 类,使其具有内部静态BinaryDataData@Embedded,属性为@Basic(fetch=FetchType.LAZY)

@Entity
@Table
@Proxy(lazy=false)
@Inheritance(strategy=InheritanceType.JOINED)
public class BinaryData implements Serializable, Persistable<BinaryData>, Cloneable {

    private static final long serialVersionUID = /** blah */;

    @Id @Column @GeneratedValue(generator="uuid") @GenericGenerator(name="uuid", strategy="uuid")
    private String id;

    @Column
    private String binaryDataName;

    @Embedded
    @Basic(fetch = FetchType.LAZY)
    private BinaryDataData binaryData;

    @Transient
    private String cacheId;

    /**
     * Hibernate constructor
     */
    public BinaryData() { /* Creates a new instance of Attachment. */}

    public BinaryData(byte[] binaryData, String binaryDataName) {
        this.binaryData = new BinaryDataData(ArrayUtils.clone(binaryData));
        this.binaryDataName = binaryDataName;
    }

    /**
     * Returns the BinaryData byte stream.
     *
     * @return binaryData byte stream
     */
    @Embedded
    @Basic(fetch = FetchType.LAZY)
    public byte[] getBinaryData() {
        if (this.binaryData == null) {
            return new byte[0];
        }
        return binaryData.getActualData();
    }

    @Embeddable
    public static class BinaryDataData implements Serializable {
        @Column(length=32*1024*1024, columnDefinition="longblob", name="BINARY_DATA") @Lob
        private byte[] actualData;

        public BinaryDataData() { }

        public BinaryDataData(byte[] data) {
            this.actualData = data;
        }

        public byte[] getActualData() {
            if (this.actualData == null) {
                return new byte[0];
            }
            return this.actualData;
        }

        public void setBinaryData(byte[] newData) {
            this.actualData = newData;
        }

        @Override public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof BinaryDataData)) {
                return false;
            }
            final BinaryDataData other = (BinaryDataData) obj;
            if (!Arrays.equals(actualData, other.actualData)) {
                return false;
            }
            return true;
        }
    }

    /** onwards... */

不幸的是,这不起作用。即使未请求二进制数据,我看到的 SQL 仍然显示对象的完整获取:

select ideaattach0_.BINARY_DATA_ID as BINARY1_9_, ideaattach0_1_.BINARY_DATA as BINARY2_9_, ideaattach0_1_.BINARY_DATA_NAME as BINARY3_9_, ideaattach0_.IDEA_BUCKET_ID as IDEA2_136_ from IDEA_ATTACHMENT ideaattach0_ inner join BINARY_DATA ideaattach0_1_ on ideaattach0_.BINARY_DATA_ID=ideaattach0_1_.BINARY_DATA_ID where ideaattach0_.BINARY_DATA_ID=?

有什么想法吗?谢谢。

【问题讨论】:

  • 只选择那些必需的列来创建一个“视图”对象。你试过了吗?

标签: java mysql sql hibernate lazy-loading


【解决方案1】:

对于 maven 项目,需要在 pom.xml 中添加以下插件依赖:

<plugin>
    <groupId>org.hibernate.orm.tooling</groupId>
    <artifactId>hibernate-enhance-maven-plugin</artifactId>
    <version>${hibernate.version}</version>
    <executions>
        <execution>
            <configuration>
                <failOnError>true</failOnError>
                <enableLazyInitialization>true</enableLazyInitialization>
            </configuration>
            <goals>
                <goal>enhance</goal>
            </goals>
        </execution>
    </executions>
</plugin>

我已经在我的项目中检查过它并且它有效,实体示例:

@Entity(name = "processing_record")
public class ProcessingRecord {

/**
 * Why uuid: https://www.clever-cloud.com/blog/engineering/2015/05/20/why-auto-increment-is-a-terrible-idea/
 */
@Id
@Column(name = "record_id")
@org.hibernate.annotations.Type(type = "pg-uuid")
private UUID id;

...

/**
 * Processing result.
 */
@Column(name = "result")
@Basic(fetch = FetchType.LAZY)
private String result;
...

更多详情请看以下文章:LINK

【讨论】:

    【解决方案2】:

    我知道此查询的日期,但是,我也会尝试使用映射为列子集的投影值类,并将该投影与指定的命名查询一起使用,该查询实例化该投影值对象,而不是这里引用的基础对象。

    我正在研究使用此方法的解决方案,因此我目前没有完整的示例。但是,基本思想是您将创建一个使用“选择新 Projection_Object_Target”语法的 JPA 查询,其中字段在“Projection_Object_Target”的构造函数中直接引用。

    I.E.使用构造函数表达式如下:

    SELECT NEW fully.qualified.package.name.ProjectionObject(baseObject.column_target_0,baseObject.column_target_1,...,baseObject.column_target_n) FROM BaseObjectMappedInDBTable AS baseObject
    

    通用示例用例:

    String queryStr =
      "SELECT NEW fully.qualified.package.name.ProjectionObject(baseObject.column_target_0) " +
      "FROM BaseObjectMappedInTable AS baseObject";
    TypedQuery<ProjectionObject> query =
      em.createQuery(queryStr, ProjectionObject.class);
    List<ProjectionObject> results = query.getResultList();
    

    【讨论】:

      【解决方案3】:

      来自Hibernate, Chapter 19. Improving performance

      惰性属性获取:访问实例变量时获取属性或单值关联。 这种方法需要构建时字节码检测,而且很少需要。

      【讨论】:

      • 无赖...这令人失望。 Hibernate 使用中又一个令人沮丧的时刻。我想知道为什么它会默认忽略这个?
      • 这很有趣。实际上,我今天在 Pro JPA2 书中遇到了这个问题,并认为它很有用。但是现在我知道 Hibernate 不支持它!引用:“在使用此功能之前,您应该了解有关延迟属性获取的一些相关点。首先,延迟获取属性的指令仅是对持久性提供者的提示,以帮助应用程序实现更好的性能。提供者不需要尊重请求,因为如果提供者继续加载属性,实体的行为不会受到影响。"
      • 它不是“不支持”。正如已经指出的,它只需要字节码增强。通常它需要构建时 stepo 来执行增强,尽管在容器管理的 JPA 提供程序的情况下它可以在运行时完成(查看 hibernate.ejb.use_class_enhancer 设置)。而且,迈克,它“默认情况下被忽略”,因为默认情况下您的类没有得到增强。以概述的方式之一增强您的课程。
      • @SteveEbersole 它需要字节码instrumentation,而不是字节码增强。更多信息stackoverflow.com/questions/26550866/…
      • 您链接到的帖子上的答案完全不正确。这些短语都指的是同一个概念,其中一个通常用于描述 5.0 之前的过程,另一个用于描述 5.0 及以后的过程。两者都描述了要求 Hibernate 更改(增强、检测)您的域模型类。
      猜你喜欢
      • 2018-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-03
      • 2011-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多