Large Objects may not be used in auto-commit mode

廉价感情. 提交于 2019-11-27 02:10:44

问题


I have a Spring application which uses Hibernate on a PostgreSQL database. I'm trying to store files in a table of the database. It seems it stores the row with the file (I just use persist method on EntityManager), but when the object is loaded from the database I get the following exception:

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

To load the data I'm using a MultipartFile transient atribute and in its setter I'm setting the information I want to persist (byte[], fileName, size). The entity I'm persisting looks like this one (I've ommitted the rest of getters/setters):

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

I can see that when it is persisted I have the data in the row but when I call this method it fails:

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

This method only fails when the result has objects with files. I've tried to set in my persistence.xml

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

but it doesn't solve the problem.

In general the application works well it only commit the data when the transaction is finished and it performs a rollback if something fails, so I don't understand why is this happening.

Any idea?

Thanks.

UPDATE

Looking at the link given by Shekhar it is suggested to include the call in a transation, so I've set the service call inside a transaction an it works (I've added @Transactional annotation).

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

the problem is that I don't want to persist any data so I don't understand why it should be include inside a transaction. Does it make any sense to make a commit when I've only loaded some data form the database?

Thanks.


回答1:


A large object can be stored in several records, that's why you have to use a transaction. All records are correct or nothing at all.

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




回答2:


If you can, create a intermediate Entity between MyClass and file property for instance. Something like:

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

You can't use @Lob and fetch type Lazy. It doesnt work. You must have a a intermediate class.




回答3:


Unless you need to store files large than 1GB I suggest you use bytea as the datatype instead of large object.

bytea is basically what BLOB is in other databases (e.g. Oracle) and it's handling is a lot more compatible with JDBC.




回答4:


Instead of using @Transactional, all I did for this issue was to update this column in PostgreSQL DB from oid type to bytea type and added @Type for the @Lob field.

i.e.

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

And changed

@Lob
private byte[] image;

To

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



回答5:


You should check if auto-commit is really set false with method getAutoCommit() on your Connection.

In my case

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

did not work, because the type of my db connection required auto-commit to be true.

In my case the problem was in the JBoss Configuration. I was using an JTA-datasource and that caused the problem. With an XA-datasource it worked fine. See this post for more details.



来源:https://stackoverflow.com/questions/3164072/large-objects-may-not-be-used-in-auto-commit-mode

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!