Spring,Hibernate,Blob懒加载

时间:2010-04-09 06:26:38

标签: java mysql hibernate lazy-loading blob

我在Hibernate中需要有关延迟blob加载的帮助。 我在我的Web应用程序中有这些服务器和框架:MySQL,Tomcat,Spring和Hibernate。

数据库配置的一部分。

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="user" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    <property name="driverClass" value="${jdbc.driverClassName}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>

    <property name="initialPoolSize">
        <value>${jdbc.initialPoolSize}</value>
    </property>
    <property name="minPoolSize">
        <value>${jdbc.minPoolSize}</value>
    </property>
    <property name="maxPoolSize">
        <value>${jdbc.maxPoolSize}</value>
    </property>
    <property name="acquireRetryAttempts">
        <value>${jdbc.acquireRetryAttempts}</value>
    </property>
    <property name="acquireIncrement">
        <value>${jdbc.acquireIncrement}</value>
    </property>
    <property name="idleConnectionTestPeriod">
        <value>${jdbc.idleConnectionTestPeriod}</value>
    </property>
    <property name="maxIdleTime">
        <value>${jdbc.maxIdleTime}</value>
    </property>
    <property name="maxConnectionAge">
        <value>${jdbc.maxConnectionAge}</value>
    </property>
    <property name="preferredTestQuery">
        <value>${jdbc.preferredTestQuery}</value>
    </property>
    <property name="testConnectionOnCheckin">
        <value>${jdbc.testConnectionOnCheckin}</value>
    </property>
</bean>


<bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="/WEB-INF/hibernate.cfg.xml" />
    <property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
        </props>
    </property>
    <property name="lobHandler" ref="lobHandler" />
</bean>

<tx:annotation-driven transaction-manager="txManager" />

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

实体类的一部分

@Lob
@Basic(fetch=FetchType.LAZY)
@Column(name = "BlobField", columnDefinition = "LONGBLOB")
@Type(type = "org.springframework.orm.hibernate3.support.BlobByteArrayType")
private byte[] blobField;

问题描述。我正在尝试在网页上显示与文件相关的数据库记录,这些记录保存在MySQL数据库中。如果数据量很小,一切正常。但是数据量很大我收到了错误java.lang.OutOfMemoryError: Java heap space 我试图在表的每一行写入blobFields null值。在这种情况下,应用程序工作正常,内存不会消失。我得出结论,标记为懒惰(@Basic(fetch=FetchType.LAZY))的blob字段实际上并不是懒惰的!

6 个答案:

答案 0 :(得分:30)

我很困惑。 Emmanuel Bernard在ANN-418中写道@Lob默认是懒惰的(即你甚至不需要使用@Basic(fetch = FetchType.LAZY)注释)。

有些用户报告延迟加载@Lob doesn't work with all drivers/database

有些用户报告说使用bytecode instrumentation(javassit?cglib?)时可以正常工作。

但我在文档中找不到任何明确的参考。

最后,recommended workaround将使用“假”一对一映射而不是属性。从现有类中删除LOB字段,创建引用同一个表的新类,相同的主键以及仅作为属性的必要LOB字段。将映射指定为一对一,fetch =“select”,lazy =“true”。只要您的父对象仍在您的会话中,您就应该得到您想要的内容。(只需将其转换为注释)。

答案 1 :(得分:5)

当然,您可以提取该值并将其放入一个具有惰性“@OneToOne”关系的新表中,但是在我们的应用程序中,仅使用此配置就可以随意加载LOB

@Lob
@Fetch(FetchMode.SELECT)
@Type(type="org.hibernate.type.PrimitiveByteArrayBlobType")
byte[] myBlob;

这在我们的项目中同时在PostgreSQL,MySQL,SQLServer和Oracle上进行了测试,因此它适用于你

答案 2 :(得分:4)

  

延迟属性加载需要构建时字节码检测。

Hibernate docs: Using lazy property fetching

如果你想避免使用字节码检测,一个选项就是创建两个使用相同表的实体,一个不带blob的实体。然后在需要blob时只使用带有blob的实体。

答案 3 :(得分:3)

我建议您使用继承来处理这种情况。有一个没有blob的基类和一个包含字节数组的派生类。只有在需要在UI上显示blob时才能使用派生类。

答案 4 :(得分:2)

我遇到了同样的问题,这是我的解决办法:

我的实体:

@Entity
@Table(name = "file")
public class FileEntity {

@Id
@GeneratedValue
private UUID id;

@NotNull
private String filename;

@NotNull
@Lob @Basic(fetch = FetchType.LAZY)
private byte[] content;

...

将插件添加到pom.xml:

        <plugin>
            <groupId>org.hibernate.orm.tooling</groupId>
            <artifactId>hibernate-enhance-maven-plugin</artifactId>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <configuration>
                        <failOnError>true</failOnError>
                        <enableLazyInitialization>true</enableLazyInitialization>
                    </configuration>
                    <goals>
                        <goal>enhance</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

答案 5 :(得分:0)

对我来说,惰性加载只能通过编译然后运行来实现,例如,在eclipse或intellij上无效。

我正在使用gradle,然后执行以下操作使其正常工作

  • 注释实体
  • 设置Hibernate gradle插件

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.hibernate:hibernate-gradle-plugin:5.4.0.Final"
    }
}

apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'org.hibernate.orm'
hibernate {
    enhance {
        enableLazyInitialization = true
        enableDirtyTracking = true
        enableAssociationManagement = true
    }
}

Entity.java

@Entity
public class Person {

    @Id
    @GeneratedValue
    private Integer id;

    @Lob
    @Basic(fetch = FetchType.LAZY)
    @Column(length = 255, nullable = false)
    private String name;

测试

./gradlew run

Full working example