Frage

Ich habe eine Feder-Anwendung, die auf einer PostgreSQL-Datenbank Hibernate verwendet. Ich versuche, Dateien in einer Tabelle der Datenbank zu speichern. Es scheint es die Zeile mit der Datei speichert (I Verwendung besteht nur Verfahren auf EntityManager), aber wenn das Objekt aus der Datenbank geladen wird ich die folgende Ausnahme erhalten:

org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode.

Um die Daten zu laden, ich bin mit einem MultipartFile transient atribute und in seinem Setter Ich gründe die Informationen, die ich anhalten soll (byte [], Dateiname, Größe). Die Entität Ich aussehen wie diese persistierenden (ich den Rest von Getter / Setter weggelassen habe):

@Entity
@Table(name="myobjects")
public class MyClass {

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence")
    @SequenceGenerator(name="sequence", sequenceName="myobjects_pk_seq", allocationSize=1)
    @Column(name="id")
    private Integer id;

    @Lob
    private String description;

    @Temporal(TemporalType.TIMESTAMP)
    private Date creationDate;

    @Transient
    private MultipartFile multipartFile;

    @Lob
    @Basic(fetch=FetchType.LAZY, optional=true)
    byte[] file;

    String fileName;

    String fileContentType;

    Integer fileSize;

    public void setMultipartFile(MultipartFile multipartFile) {
        this.multipartFile = multipartFile;
        try {
            this.file = this.multipartFile.getBytes();
            this.fileName = this.multipartFile.getOriginalFilename();
            this.fileContentType = this.multipartFile.getContentType();
            this.fileSize = ((Long) this.multipartFile.getSize()).intValue();
        } catch (IOException e) {
            logger.error(e.getStackTrace());
        }
    }
}

Das kann ich sehen, wenn es beibehalten wird ich die Daten in der Zeile haben, aber wenn ich diese Methode nennen es fehlschlägt:

public List<MyClass> findByDescription(String text) {
    Query query = getEntityManager().createQuery("from MyClass WHERE UPPER(description) like :query ORDER BY creationDate DESC");
    query.setParameter("query", "%" + text.toUpperCase() + "%");
    return query.getResultList();
}

Diese Methode schlägt fehl, nur wenn das Ergebnis Objekte mit Dateien. Ich habe zu Satz versuche in meinem persistence.xml

<property name="hibernate.connection.autocommit" value="false" />

aber nicht das Problem lösen.

Im Allgemeinen ist die Anwendung funktioniert gut nur es die Daten verpflichten, wenn die Transaktion abgeschlossen ist, und er führt einen Rollback, wenn etwas fehlschlägt, so verstehe ich nicht, warum das passiert ist.

Jede Idee?

Danke.

UPDATE

auf dem Link von Shekhar gegeben Suche wird vorgeschlagen, den Anruf in einem transation einschließen, so dass ich den Service-Aufruf innerhalb einer Transaktion festgelegt habe eine es funktioniert (ich habe @Transactional Anmerkung hinzugefügt).

@Transactional
public List<myClass> find(String text) {
    return myClassDAO.findByDescription(text);
}

das Problem ist, dass ich mag keine Daten bestehen bleiben, damit ich verstehe nicht, warum soll es in einer Transaktion enthalten werden. Hat es einen Sinn, eine Festschreibung zu machen, wenn ich nur habe einige Daten bilden die Datenbank geladen?

Danke.

War es hilfreich?

Lösung

Ein großes Objekt kann in mehreren Datensätzen gespeichert werden, das ist, warum Sie eine Transaktion verwenden. Alle Sätze sind richtig oder gar nichts.

https://www.postgresql.org/docs/current/static/ largeobjects.html

Andere Tipps

Wenn Sie können, eine Zwischeninstanz zwischen MyClass und Dateieigenschaft zum Beispiel erstellen. So etwas wie:

@Entity
@Table(name="myobjects")
public class MyClass {
    @OneToOne(cascade = ALL, fetch = LAZY)
    private File file;
}

@Entity
@Table(name="file")
public class File {
     @Lob
     byte[] file;
}

Sie können nicht @Lob verwenden und holen Faule geben. Es funktioniert nicht. Sie müssen eine Zwischenklasse haben.

Es sei denn, Sie speichern Dateien benötigen große als 1 GB Ich schlage vor, Sie bytea als Datentyp an Stelle von großen Objekt verwenden.

bytea ist im Grunde, was BLOB in anderen Datenbanken (z Oracle) und die Handhabung viel mehr kompatibel mit JDBC ist.

Statt mit @Transactional, alles, was ich für dieses Problem tat, war diese Spalte in PostgreSQL DB von oid Typ bytea Art und hinzugefügt @Type für das @Lob Feld zu aktualisieren.

d.

ALTER TABLE person DROP COLUMN image;
ALTER TABLE person ADD COLUMN image bytea;

Und geändert

@Lob
private byte[] image;

@Lob
@Type(type = "org.hibernate.type.ImageType")
private byte[] image;

Sie sollten überprüfen, ob autocommit ist wirklich Satz falsch mit der Methode getAutoCommit () auf Ihrer Verbindung.

In meinem Fall

<property name="hibernate.connection.autocommit" value="false" />

hat nicht funktioniert, weil die Art meiner DB-Verbindung erforderlich autocommit um wahr zu sein.

In meinem Fall war das Problem in der JBoss-Konfiguration. Ich wurde mit einer JTA-Datenquelle und die das Problem verursacht hat. Mit einer XA-Datenquelle es funktionierte gut. Siehe diesen Beitrag für weitere Details.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top