Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Large Objects may not be used in auto-commit mode

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.

like image 229
Javi Avatar asked Jul 02 '10 07:07

Javi


People also ask

Which is true about auto-commit mode in JDBC?

By default, JDBC uses an operation mode called auto-commit. This means that every update to the database is immediately made permanent. Any situation where a logical unit of work requires more than one update to the database cannot be done safely in auto-commit mode.

What is Autocommit mode?

Auto-commit mode means that when a statement is completed, the method commit is called on that statement automatically. Auto-commit in effect makes every SQL statement a transaction. The commit occurs when the statement completes or the next statement is executed, whichever comes first.

How can you avoid auto-commit mode in JDBC?

To enable manual- transaction support instead of the auto-commit mode that the JDBC driver uses by default, use the Connection object's setAutoCommit() method. If you pass a boolean false to setAutoCommit( ), you turn off auto-commit.

What happens when auto-commit is set on?

When autocommit is set on, a commit occurs automatically after every statement, except PREPARE and DESCRIBE. If autocommit is on and a cursor is opened, the DBMS does not issue a commit until the CLOSE cursor statement is executed, because cursors are logically a single statement.


2 Answers

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

like image 177
Frank Heikens Avatar answered Sep 29 '22 05:09

Frank Heikens


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; 
like image 25
Philip John Avatar answered Sep 29 '22 06:09

Philip John