webentwicklung-frage-antwort-db.com.de

Frühling, Winterschlaf, Blob faul Laden

Ich brauche Hilfe beim Lazy Blob-Laden in Hibernate. Ich habe in meiner Webanwendung diese Server und Frameworks: MySQL, Tomcat, Spring und Hibernate.

Der Teil der Datenbankkonfiguration.

<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>

Der Teil der Entitätsklasse

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

Die Problembeschreibung. Ich versuche, auf einer Webseite Datenbankeinträge anzuzeigen, die sich auf Dateien beziehen, die in der MySQL-Datenbank gespeichert wurden. Alles funktioniert gut, wenn die Datenmenge klein ist. Aber das Datenvolumen ist groß Ich erhalte einen Fehler Java.lang.OutOfMemoryError: Java heap space Ich habe versucht, blobFields-Nullwerte in jede Zeile der Tabelle zu schreiben. In diesem Fall funktioniert die Anwendung gut, der Speicher geht nicht aus. Ich habe die Schlussfolgerung, dass das Fleckfeld, das als faul (@Basic(fetch=FetchType.LAZY)) markiert ist, eigentlich nicht faul ist!

23

Ich bin verwirrt. Emmanuel Bernard schrieb in ANN-418 , dass @Lob standardmäßig faul ist (d. H. Sie müssen nicht einmal die @Basic(fetch = FetchType.LAZY)-Annotation verwenden). 

Einige Benutzer berichten, dass das langsame Laden eines @Lobnicht mit allen Treibern/Datenbanken funktioniert.

Einige Benutzer berichten, dass es bei der Verwendung von bytecode instrumentation (javassit? Cglib?) Funktioniert.

Ich kann jedoch in der Dokumentation keinen klaren Hinweis darauf finden. 

Am Ende der empfohlenen Problemumgehung verwenden Sie eine "gefälschte" Eins-zu-Eins-Zuordnung anstelle von Eigenschaften. Entfernen Sie die LOB-Felder aus Ihrer vorhandenen Klasse, erstellen Sie neue Klassen, die auf dieselbe Tabelle, denselben Primärschlüssel und nur die erforderlichen LOB-Felder als Eigenschaften verweisen. Geben Sie die Zuordnungen als Eins-zu-Eins an, fetch = "select", lazy = "true". Solange sich Ihr übergeordnetes Objekt noch in Ihrer Sitzung befindet, sollten Sie genau das bekommen, was Sie möchten. (nur in Anmerkungen umsetzen).

30
Pascal Thivent

Natürlich können Sie diesen Wert extrahieren und in eine neue Tabelle mit einer "@OneToOne" -Zusammensetzung einfügen, die faul ist. In unserer Anwendung werden die LOBs jedoch nur bei Bedarf mit dieser Konfiguration geladen

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

Dies wird in unserem Projekt gleichzeitig auf PostgreSQL, MySQL, SQLServer und Oracle getestet. Es sollte also für Sie funktionieren

5
Hons

Ich würde vorschlagen, dass Sie Vererbung verwenden, um dieses Szenario zu behandeln. Verfügen über eine Basisklasse ohne Blob und eine abgeleitete Klasse, die das Byte-Array enthält. Sie würden die abgeleitete Klasse nur dann verwenden, wenn Sie den Blob auf der Benutzeroberfläche anzeigen müssen.

3
Darin Dimitrov

Das Laden von Eigenschaften für faules Eigentum erfordert eine Buildtime-Bytecode-Instrumentierung.

Hibernate-Dokumente: Faules Abrufen von Eigenschaften verwenden

Wenn Sie die Bytecode-Instrumentierung vermeiden möchten, besteht die Möglichkeit, zwei Entitäten zu erstellen, die dieselbe Tabelle verwenden, eine mit dem Blob ohne. Verwenden Sie dann die Entität nur mit Fleck, wenn Sie den Fleck benötigen.

3
Ben George

Ich hatte das gleiche Problem und dies war mein Fix:

Meine Entität:

@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;

...

Plugin zu pom.xml hinzugefügt:

        <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>
0

Für mich funktionierte Lazy Load nur durch das Kompilieren und Ausführen, funktionierte zum Beispiel nicht mit Eclipse oder Intellij. 

Ich benutze gradle, dann habe ich folgendes gemacht, damit es funktioniert

  • Entity kommentieren
  • Einrichten des Ruhezustand-Plugins

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;

Testen

./gradlew run

Vollständiges Arbeitsbeispiel

0
deFreitas