35

PostgreSQL データベースで Hibernate を使用する Spring アプリケーションがあります。データベースのテーブルにファイルを保存しようとしています。行をファイルに格納しているようですが (EntityManager で persist メソッドを使用するだけです)、オブジェクトがデータベースから読み込まれると、次の例外が発生します。

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

データをロードするために MultipartFile 一時属性を使用し、そのセッターで永続化したい情報 (byte[]、fileName、size) を設定しています。私が永続化しているエンティティは次のようになります (残りのゲッター/セッターは省略しました)。

@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());
        }
    }
}

永続化すると行にデータがあることがわかりますが、このメソッドを呼び出すと失敗します。

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();
}

このメソッドは、結果にファイルを含むオブジェクトがある場合にのみ失敗します。persistence.xml に設定しようとしました

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

しかし、それは問題を解決しません。

一般に、アプリケーションは正常に機能し、トランザクションが終了したときにのみデータをコミットし、何かが失敗した場合はロールバックを実行するため、なぜこれが起こっているのかわかりません。

何か案が?

ありがとう。

アップデート

Shekhar によって提供されたリンクを見ると、呼び出しをトランザクションに含めることが提案されているため、サービス呼び出しをトランザクション内に設定して動作させました (@Transactional アノテーションを追加しました)。

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

問題は、データを保持したくないため、トランザクション内に含める必要がある理由がわかりません。データベースから一部のデータしかロードしていないときにコミットするのは意味がありますか?

ありがとう。

4

8 に答える 8

41

大きなオブジェクトは複数のレコードに格納できるため、トランザクションを使用する必要があります。すべての記録が正しいか、まったく記録がありません。

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

于 2010-07-02T08:59:03.337 に答える
9

を使用する代わりに@Transactional、この問題に対して私が行ったのは、PostgreSQL DB のこの列をタイプからoidタイプに更新し、フィールドbyteaに追加することだけでした。@Type@Lob

すなわち

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

そして変わった

@Lob
private byte[] image;

@Lob
@Type(type = "org.hibernate.type.ImageType")
private byte[] image;
于 2018-11-28T13:38:57.697 に答える
6

可能であれば、たとえば MyClass とファイル プロパティの間に中間エンティティを作成します。何かのようなもの:

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

@Lob とフェッチ タイプ Lazy は使用できません。うまくいきません。中級クラスが必要です。

于 2013-07-05T01:36:58.977 に答える
5

1GBを超えるファイルを保存する必要がない限り、データ型として大きなオブジェクトではなくbyteaを使用することをお勧めします。

byteaは、基本的にBLOBが他のデータベース(Oracleなど)にあるものであり、その処理はJDBCとはるかに互換性があります。

于 2010-07-04T17:05:59.750 に答える