大对象可能无法在自动提交模式下使用

时间:2010-07-02 07:59:08

标签: java hibernate postgresql jpa autocommit

我有一个Spring应用程序,它在PostgreSQL数据库上使用Hibernate。我正在尝试将文件存储在数据库的表中。它似乎将行存储在文件中(我只是在EntityManager上使用persist方法),但是当从数据库加载对象时,我得到以下异常:

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

要加载数据,我正在使用MultipartFile瞬态属性,并在其setter中设置我想要保留的信息(byte [],fileName,size)。 我坚持的实体看起来像这个(我已经省略了其余的getter / setter):

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

问题是我不想保留任何数据,因此我不明白为什么它应该包含在事务中。当我只从数据库中加载一些数据时进行提交是否有意义?

感谢。

6 个答案:

答案 0 :(得分:30)

大型对象可以存储在多个记录中,这就是您必须使用事务的原因。所有记录都是正确的或根本没有。

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

答案 1 :(得分:5)

如果可以,请在MyClass和file属性之间创建一个中间实体。 类似的东西:

@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。它不起作用。你必须有一个中级班。

答案 2 :(得分:4)

除非您需要存储大于1GB的文件,否则我建议您使用bytea作为数据类型而不是大对象。

bytea基本上是BLOB在其他数据库(例如Oracle)中的地方,它的处理与JDBC更加兼容。

答案 3 :(得分:1)

在存储库界面上使用posit

答案 4 :(得分:0)

我没有使用@Transactional,而是将PostgreSQL DB中的此列从oid类型更新为bytea类型,并为{添加了@Type {1}}字段。

@Lob

已更改

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

收件人

@Lob
private byte[] image;

答案 5 :(得分:0)

您应该使用Connection上的方法getAutoCommit()检查自动提交的设置是否真的为假。

就我而言

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

不起作用,因为我的数据库连接类型要求自动提交为真。

就我而言,问题出在JBoss配置中。我使用的是JTA数据源,这引起了问题。使用XA数据源,效果很好。有关更多详细信息,请参见this post